diff options
author | Martin Liska <mliska@suse.cz> | 2021-12-12 22:22:10 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2021-12-12 22:22:10 +0100 |
commit | cf116c791582be1c0cc9e04872cb7f8d0d463fd8 (patch) | |
tree | 944e608d1d2b0e84299eb618a4cc015e2d1e4b06 | |
parent | 7a81590757659982cb9b93b922a4c182aa40e2d8 (diff) | |
parent | aeedb00a1ae2ccd10b1a5f00ff466081aeadb54b (diff) | |
download | gcc-cf116c791582be1c0cc9e04872cb7f8d0d463fd8.zip gcc-cf116c791582be1c0cc9e04872cb7f8d0d463fd8.tar.gz gcc-cf116c791582be1c0cc9e04872cb7f8d0d463fd8.tar.bz2 |
Merge branch 'master' into devel/sphinx
366 files changed, 11870 insertions, 6156 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 66c7532..d343471 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,273 @@ +2021-12-11 Jan Hubicka <hubicka@ucw.cz> + + * ipa-profile.c (ipa_profile): Do not update hot bb threshold. + +2021-12-11 Jan Hubicka <hubicka@ucw.cz> + + * ipa-modref.c (get_modref_function_summary): Use ultimate_alias_target. + (ignore_edge): Likewise. + (compute_parm_map): Likewise. + (modref_propagate_in_scc): Likewise. + (modref_propagate_flags_in_scc): Likewise. + +2021-12-10 Jason Merrill <jason@redhat.com> + + * symtab.c (symtab_node::equal_address_to): Fix comment typo. + +2021-12-10 Doug Rupp <rupp@adacore.com> + + * config/vxworks.h (LINK_SPEC): Remove %(link_target). + Change %{v:-v} to %{v:-V}. + +2021-12-10 Olivier Hainque <hainque@adacore.com> + + * config/t-vxworks: Remove assignment to STMP_FIXINC. + +2021-12-10 Martin Liska <mliska@suse.cz> + + * params.opt: Add missing dot. + +2021-12-10 Roger Sayle <roger@nextmovesoftware.com> + + PR ipa/103601 + * ipa-modref-tree.h (useful_for_kill_p): Zero width accesses aren't + useful for kill tracking. + +2021-12-10 Andrew Stubbs <ams@codesourcery.com> + + * config/gcn/mkoffload.c (process_asm): Process the variable table + completely differently. + (process_obj): Encode the varaible data differently. + +2021-12-10 Joel Hutton <joel.hutton@arm.com> + + PR tree-optimization/103523 + * tree-vect-loop.c (vectorizable_induction): Check for + PLUS_EXPR/MINUS_EXPR support. + +2021-12-10 Cui,Lili <lili.cui@intel.com> + + * config/i386/i386.c (ix86_vector_costs::add_stmt_cost): Remove Tremont. + +2021-12-09 Jan Hubicka <hubicka@ucw.cz> + + * doc/invoke.texi (max-inline-functions-called-once-loop-depth, + max-inline-functions-called-once-insns): New parameters. + * ipa-inline.c (check_callers): Handle + param_inline_functions_called_once_loop_depth and + param_inline_functions_called_once_insns. + (edge_badness): Fix linebreaks. + * params.opt (param=max-inline-functions-called-once-loop-depth, + param=max-inline-functions-called-once-insn): New params. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + PR tree-optimization/103215 + * pointer-query.cc (access_ref::merge_ref): Extend the offset and + size of the merged object instead of using the larger. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + PR middle-end/101751 + * doc/extend.texi (attribute access): Adjust. + * gimple-ssa-warn-access.cc (pass_waccess::maybe_check_access_sizes): + Treat access mode none on a void* argument as expecting as few as + zero bytes. + +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * config/aarch64/aarch64-sve-builtins.cc (gt_pch_nx): Change type of + second argument from function with 2 pointer arguments to function + with 3 pointer arguments. + +2021-12-09 Olivier Hainque <hainque@adacore.com> + + * config/aarch64/aarch64-vxworks.h (TARGET_OS_CPP_BUILTINS): + Use VX_CPU_PREFIX in CPU definitions. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + * pointer-query.cc (access_ref::dump): Define new function + (pointer_query::dump): Call it. + * pointer-query.h (access_ref::dump): Declare new function. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + * pointer-query.cc (compute_objsize_r): Add an argument. + (gimple_call_return_array): Pass a new argument to compute_objsize_r. + (access_ref::merge_ref): Same. + (access_ref::inform_access): Add an argument and use it. + (access_data::access_data): Initialize new member. + (handle_min_max_size): Pass a new argument to compute_objsize_r. + (handle_decl): New function. + (handle_array_ref): Pass a new argument to compute_objsize_r. + Avoid incrementing deref. + (set_component_ref_size): New function. + (handle_component_ref): New function. + (handle_mem_ref): Pass a new argument to compute_objsize_r. + Only increment deref after successfully computing object size. + (handle_ssa_name): New function. + (compute_objsize_r): Move code into helpers and call them. + (compute_objsize): Pass a new argument to compute_objsize_r. + * pointer-query.h (access_ref::inform_access): Add an argument. + (access_data::ostype): New member. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + * pointer-query.cc (access_ref::merge_ref): Define new function. + (access_ref::get_ref): Move code into merge_ref and call it. + * pointer-query.h (access_ref::merge_ref): Declare new function. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + * gimple-ssa-warn-restrict.c (builtin_access::builtin_access): Pass + GIMPLE statement to compute_objsize. + * pointer-query.cc (compute_objsize): Add a statement argument. + * pointer-query.h (compute_objsize): Define a new overload. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + * gimple-ssa-warn-access.cc (check_access): Adjust to member name + change. + (pass_waccess::check_strncmp): Same. + * pointer-query.cc (access_ref::access_ref): Remove arguments. + Simpilfy. + (access_data::access_data): Define new ctors. + (access_data::set_bound): Define new member function. + (compute_objsize_r): Remove unnecessary code. + * pointer-query.h (struct access_ref): Remove ctor arguments. + (struct access_data): Declare ctor overloads. + (access_data::dst_bndrng): New member. + (access_data::src_bndrng): New member. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + PR middle-end/103143 + * pointer-query.cc (gimple_call_return_array): Call compute_objsize_r. + +2021-12-09 Olivier Hainque <hainque@adacore.com> + Rasmus Villemoes <rv@rasmusvillemoes.dk> + + * Makefile.in (T_STDINT_GCC_H): New variable, path to + stdint-gcc.h that a target configuration may override when + use_gcc_stdint is "provide". + (stmp-int-hdrs): Depend on it and copy that for + USE_GCC_INT=provide. + * config.gcc (vxworks): Revert to use_gcc_stdint=provide. + * config/t-vxworks (T_STDINT_GCC_H): Define, as vxw-stdint-gcc.h. + (vxw-stdint-gcc.h): New target, produced from the original + stdint-gcc.h. + (vxw-glimits.h): Use an automatic variable to designate the + first and only prerequisite. + * config/vxworks/stdint.h: Remove. + +2021-12-09 Iain Sandoe <iain@sandoe.co.uk> + + PR pch/71934 + * config/host-darwin.c (SAFE_ALLOC_SIZE): Remove. + (darwin_gt_pch_get_address): Rework for relocatable PCH. + (darwin_gt_pch_use_address): Likewise. + +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * config/host-darwin.c (darwin_gt_pch_use_address): When reading + manually the file into mapped area, update mapped_addr as + an automatic variable rather than addr which is a reference parameter. + * config/host-hpux.c (hpux_gt_pch_use_address): When reading + manually the file into mapped area, update addr as + an automatic variable rather than base which is a reference parameter. + +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * coretypes.h (gt_pointer_operator): Use 3 pointer arguments instead + of two. + * gengtype.c (struct walk_type_data): Add in_nested_ptr argument. + (walk_type): Temporarily set d->in_nested_ptr around nested_ptr + handling. + (write_types_local_user_process_field): Pass a new middle pointer + to gt_pointer_operator op calls, if d->in_nested_ptr pass there + address of d->prev_val[2], otherwise NULL. + (write_types_local_process_field): Likewise. + * ggc-common.c (relocate_ptrs): Add real_ptr_p argument. If equal + to ptr_p, do nothing, otherwise if NULL remember ptr_p's + or if non-NULL real_ptr_p's corresponding new address in + reloc_addrs_vec. + (reloc_addrs_vec): New variable. + (compare_ptr, read_uleb128, write_uleb128): New functions. + (gt_pch_save): When iterating over objects through relocate_ptrs, + save current i into state.ptrs_i. Sort reloc_addrs_vec and emit + it as uleb128 of differences between pointer addresses into the + PCH file. + (gt_pch_restore): Allow restoring of PCH to a different address + than the preferred one, in that case adjust global pointers by bias + and also adjust by bias addresses read from the relocation table + as uleb128 differences. Otherwise fseek over it. Perform + gt_pch_restore_stringpool only after adjusting callbacks and for + callback adjustments also take into account the bias. + (default_gt_pch_use_address): Change type of first argument from + void * to void *&. + (mmap_gt_pch_use_address): Likewise. + * ggc-tests.c (gt_pch_nx): Pass NULL as new middle argument to op. + * hash-map.h (hash_map::pch_nx_helper): Likewise. + (gt_pch_nx): Likewise. + * hash-set.h (gt_pch_nx): Likewise. + * hash-table.h (gt_pch_nx): Likewise. + * hash-traits.h (ggc_remove::pch_nx): Likewise. + * hosthooks-def.h (default_gt_pch_use_address): Change type of first + argument from void * to void *&. + (mmap_gt_pch_use_address): Likewise. + * hosthooks.h (struct host_hooks): Change type of first argument of + gt_pch_use_address hook from void * to void *&. + * machmode.h (gt_pch_nx): Expect a callback with 3 pointers instead of + two in the middle argument. + * poly-int.h (gt_pch_nx): Likewise. + * stringpool.c (gt_pch_nx): Pass NULL as new middle argument to op. + * tree-cfg.c (gt_pch_nx): Likewise, except for LOCATION_BLOCK pass + the same &(block) twice. + * value-range.h (gt_pch_nx): Pass NULL as new middle argument to op. + * vec.h (gt_pch_nx): Likewise. + * wide-int.h (gt_pch_nx): Likewise. + * config/host-darwin.c (darwin_gt_pch_use_address): Change type of + first argument from void * to void *&. + * config/host-darwin.h (darwin_gt_pch_use_address): Likewise. + * config/host-hpux.c (hpux_gt_pch_use_address): Likewise. + * config/host-linux.c (linux_gt_pch_use_address): Likewise. If + it couldn't succeed to mmap at the preferred location, set base + to the actual one. Update addr in the manual reading loop instead of + base. + * config/host-netbsd.c (netbsd_gt_pch_use_address): Change type of + first argument from void * to void *&. + * config/host-openbsd.c (openbsd_gt_pch_use_address): Likewise. + * config/host-solaris.c (sol_gt_pch_use_address): Likewise. + * config/i386/host-mingw32.c (mingw32_gt_pch_use_address): Likewise. + * config/rs6000/rs6000-gen-builtins.c (write_init_file): Pass NULL + as new middle argument to op in the generated code. + * doc/gty.texi: Adjust samples for the addition of middle pointer + to gt_pointer_operator callback. + +2021-12-09 Alexandre Oliva <oliva@adacore.com> + + PR target/103097 + * reg-stack.c (convert_regs_1): Move any_malformed_asm + resetting... + (reg_to_stack): ... here. + +2021-12-09 Alexandre Oliva <oliva@adacore.com> + + PR target/103302 + * expr.c (emit_move_multi_word): Skip clobber during lra. + +2021-12-09 Alexandre Oliva <oliva@adacore.com> + + PR tree-optimization/103024 + PR middle-end/103530 + * gimple-harden-conditionals.cc (non_eh_succ_edge): New. + (pass_harden_compares::execute): Accept 1-bit integral types, + and cope with throwing compares. + 2021-12-08 Iain Sandoe <iain@sandoe.co.uk> * config/darwin.h (DARWIN_PIE_SPEC): Add -no_pie when diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 6f8b77f..c59e542 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20211209 +20211212 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2a0be9e..41949f0 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -452,6 +452,7 @@ USER_H_INC_NEXT_POST = @user_headers_inc_next_post@ # Enable target overriding of this fragment, as in config/t-vxworks. T_GLIMITS_H = $(srcdir)/glimits.h +T_STDINT_GCC_H = $(srcdir)/ginclude/stdint-gcc.h # The GCC to use for compiling crt*.o. # Usually the one we just built. @@ -3099,7 +3100,7 @@ gcov-tool$(exeext): $(GCOV_TOOL_OBJS) $(LIBDEPS) # be rebuilt. # Build the include directories. -stmp-int-hdrs: $(STMP_FIXINC) $(T_GLIMITS_H) $(USER_H) fixinc_list +stmp-int-hdrs: $(STMP_FIXINC) $(T_GLIMITS_H) $(T_STDINT_GCC_H) $(USER_H) fixinc_list # Copy in the headers provided with gcc. # # The sed command gets just the last file name component; @@ -3145,7 +3146,7 @@ stmp-int-hdrs: $(STMP_FIXINC) $(T_GLIMITS_H) $(USER_H) fixinc_list cp $(srcdir)/ginclude/stdint-wrap.h include/stdint.h; \ chmod a+r include/stdint.h; \ elif [ $(USE_GCC_STDINT) = provide ]; then \ - cp $(srcdir)/ginclude/stdint-gcc.h include/stdint.h; \ + cp $(T_STDINT_GCC_H) include/stdint.h; \ chmod a+r include/stdint.h; \ fi set -e; for ml in `cat fixinc_list`; do \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 7d7d811..2ff37d0 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,9 @@ +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * gcc-interface/decl.c (gt_pch_nx): Pass NULL as new middle argument + to op. + 2021-12-02 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/Make-lang.in (ADA_GENERATED_FILES): Add warning. diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 93b6eb5..af6b6bd 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -171,7 +171,7 @@ gt_pch_nx (Entity_Id &) void gt_pch_nx (Entity_Id *x, gt_pointer_operator op, void *cookie) { - op (x, cookie); + op (x, NULL, cookie); } struct dummy_type_hasher : ggc_cache_ptr_hash<tree_entity_vec_map> diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index f652f59..66f28fb 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * c-pch.c (c_common_no_more_pch): Pass a temporary void * var + with NULL value instead of NULL to host_hooks.gt_pch_use_address. + 2021-12-03 Jakub Jelinek <jakub@redhat.com> PR pch/71934 diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c index 2cafa13..73a846d 100644 --- a/gcc/c-family/c-pch.c +++ b/gcc/c-family/c-pch.c @@ -375,7 +375,8 @@ c_common_no_more_pch (void) if (cpp_get_callbacks (parse_in)->valid_pch) { cpp_get_callbacks (parse_in)->valid_pch = NULL; - host_hooks.gt_pch_use_address (NULL, 0, -1, 0); + void *addr = NULL; + host_hooks.gt_pch_use_address (addr, 0, -1, 0); } } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index fb2ef2a..d899302 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * c-decl.c (resort_field_decl_cmp): Pass the same pointer twice + to resort_data.new_value. + 2021-12-08 Chung-Lin Tang <cltang@codesourcery.com> * c-parser.c (struct omp_dim): New struct type for use inside diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 3e28a03..9e45798 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -9040,8 +9040,8 @@ resort_field_decl_cmp (const void *x_p, const void *y_p) { tree d1 = DECL_NAME (*x); tree d2 = DECL_NAME (*y); - resort_data.new_value (&d1, resort_data.cookie); - resort_data.new_value (&d2, resort_data.cookie); + resort_data.new_value (&d1, &d1, resort_data.cookie); + resort_data.new_value (&d2, &d2, resort_data.cookie); if (d1 < d2) return -1; } diff --git a/gcc/config.gcc b/gcc/config.gcc index 1ca9d36..c882436 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -1019,16 +1019,9 @@ case ${target} in extra_headers="${extra_headers} ../vxworks/math.h ../vxworks/complex.h" extra_headers="${extra_headers} ../vxworks/inttypes.h ../vxworks/setjmp.h" - # We provide stdint.h ... - + # We provide (a tailored version of) stdint.h tm_file="${tm_file} vxworks-stdint.h" - - # .. only through the yvals conditional wrapping mentioned above - # to abide by the VxWorks 7 expectations. The final copy is performed - # explicitly by a t-vxworks Makefile rule. - - use_gcc_stdint=none - extra_headers="${extra_headers} ../../ginclude/stdint-gcc.h" + use_gcc_stdint=provide case ${enable_threads} in no) ;; diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index bc92213..27be8b9 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -3913,7 +3913,7 @@ gt_pch_nx (function_instance *) } inline void -gt_pch_nx (function_instance *, void (*) (void *, void *), void *) +gt_pch_nx (function_instance *, void (*) (void *, void *, void *), void *) { } diff --git a/gcc/config/aarch64/aarch64-vxworks.h b/gcc/config/aarch64/aarch64-vxworks.h index d5bdb4e..a821bde 100644 --- a/gcc/config/aarch64/aarch64-vxworks.h +++ b/gcc/config/aarch64/aarch64-vxworks.h @@ -50,7 +50,8 @@ along with GCC; see the file COPYING3. If not see builtin_define ("ARMEB"); \ else \ builtin_define ("ARMEL"); \ - builtin_define ("_VX_CPU=ARMARCH8A"); \ + builtin_define \ + (VX_CPU_PREFIX "CPU=" VX_CPU_PREFIX "ARMARCH8A"); \ VXWORKS_OS_CPP_BUILTINS (); \ } while (0) diff --git a/gcc/config/gcn/mkoffload.c b/gcc/config/gcn/mkoffload.c index b2e71ea..d609b7a 100644 --- a/gcc/config/gcn/mkoffload.c +++ b/gcc/config/gcn/mkoffload.c @@ -495,10 +495,8 @@ static void process_asm (FILE *in, FILE *out, FILE *cfile) { int fn_count = 0, var_count = 0, dims_count = 0, regcount_count = 0; - struct obstack fns_os, vars_os, varsizes_os, dims_os, regcounts_os; + struct obstack fns_os, dims_os, regcounts_os; obstack_init (&fns_os); - obstack_init (&vars_os); - obstack_init (&varsizes_os); obstack_init (&dims_os); obstack_init (®counts_os); @@ -567,16 +565,11 @@ process_asm (FILE *in, FILE *out, FILE *cfile) unsigned varsize; if (sscanf (buf, " .8byte %ms\n", &varname)) { - obstack_ptr_grow (&vars_os, varname); + fputs (buf, out); fgets (buf, sizeof (buf), in); if (!sscanf (buf, " .8byte %u\n", &varsize)) abort (); - obstack_int_grow (&varsizes_os, varsize); var_count++; - - /* The HSA Runtime cannot locate the symbol if it is not - exported from the kernel. */ - fprintf (out, "\t.global %s\n", varname); } break; } @@ -595,7 +588,19 @@ process_asm (FILE *in, FILE *out, FILE *cfile) char dummy; if (sscanf (buf, " .section .gnu.offload_vars%c", &dummy) > 0) - state = IN_VARS; + { + state = IN_VARS; + + /* Add a global symbol to allow plugin-gcn.c to locate the table + at runtime. It can't use the "offload_var_table.N" emitted by + the compiler because a) they're not global, and b) there's one + for each input file combined into the binary. */ + fputs (buf, out); + fputs ("\t.global .offload_var_table\n" + "\t.type .offload_var_table, @object\n" + ".offload_var_table:\n", + out); + } else if (sscanf (buf, " .section .gnu.offload_funcs%c", &dummy) > 0) state = IN_FUNCS; else if (sscanf (buf, " .amdgpu_metadata%c", &dummy) > 0) @@ -622,7 +627,7 @@ process_asm (FILE *in, FILE *out, FILE *cfile) regcount.sgpr_count = regcount.vgpr_count = -1; } - if (state == IN_CODE || state == IN_METADATA) + if (state == IN_CODE || state == IN_METADATA || state == IN_VARS) fputs (buf, out); } @@ -633,24 +638,7 @@ process_asm (FILE *in, FILE *out, FILE *cfile) fprintf (cfile, "#include <stdlib.h>\n"); fprintf (cfile, "#include <stdbool.h>\n\n"); - char **vars = XOBFINISH (&vars_os, char **); - unsigned *varsizes = XOBFINISH (&varsizes_os, unsigned *); - fprintf (cfile, - "static const struct global_var_info {\n" - " const char *name;\n" - " void *address;\n" - "} vars[] = {\n"); - int i; - for (i = 0; i < var_count; ++i) - { - const char *sep = i < var_count - 1 ? "," : " "; - fprintf (cfile, " { \"%s\", NULL }%s /* size: %u */\n", vars[i], sep, - varsizes[i]); - } - fprintf (cfile, "};\n\n"); - - obstack_free (&vars_os, NULL); - obstack_free (&varsizes_os, NULL); + fprintf (cfile, "static const int gcn_num_vars = %d;\n\n", var_count); /* Dump out function idents. */ fprintf (cfile, "static const struct hsa_kernel_description {\n" @@ -661,6 +649,7 @@ process_asm (FILE *in, FILE *out, FILE *cfile) "} gcn_kernels[] = {\n "); dim.d[0] = dim.d[1] = dim.d[2] = 0; const char *comma; + int i; for (comma = "", i = 0; i < fn_count; comma = ",\n ", i++) { /* Find if we recorded dimensions for this function. */ @@ -732,13 +721,11 @@ process_obj (FILE *in, FILE *cfile) " unsigned kernel_count;\n" " const struct hsa_kernel_description *kernel_infos;\n" " unsigned global_variable_count;\n" - " const struct global_var_info *global_variables;\n" "} target_data = {\n" " &gcn_image,\n" " sizeof (gcn_kernels) / sizeof (gcn_kernels[0]),\n" " gcn_kernels,\n" - " sizeof (vars) / sizeof (vars[0]),\n" - " vars\n" + " gcn_num_vars\n" "};\n\n"); fprintf (cfile, diff --git a/gcc/config/host-darwin.c b/gcc/config/host-darwin.c index 559b919f..e5657fb 100644 --- a/gcc/config/host-darwin.c +++ b/gcc/config/host-darwin.c @@ -33,29 +33,27 @@ The spaces should all have 512Mb available c.f. PCH files for large C++ or Objective-C in the range of 150Mb for 64b hosts. - We also try to steer clear of places already used for sanitizers. */ + We also try to steer clear of places already used for sanitizers. + + If the allocation fails at the 'ideal' address, we go with what the + kernel provides (there is more likelihood that we will need to relocate + on read in). */ #define PAGE_SZ 4096 #if defined(__x86_64) && defined(__LP64__) # define TRY_EMPTY_VM_SPACE 0x180000000000ULL -# define SAFE_ALLOC_SIZE 0x20000000 #elif defined(__x86_64) # define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL -# define SAFE_ALLOC_SIZE 0x20000000 #elif defined(__i386) # define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL -# define SAFE_ALLOC_SIZE 0x20000000 #elif defined(__POWERPC__) && defined(__LP64__) # define TRY_EMPTY_VM_SPACE 0x180000000000ULL -# define SAFE_ALLOC_SIZE 0x20000000 #elif defined(__POWERPC__) # define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL -# define SAFE_ALLOC_SIZE 0x20000000 #elif defined(__aarch64__) # undef PAGE_SZ # define PAGE_SZ 16384 # define TRY_EMPTY_VM_SPACE 0x180000000000ULL -# define SAFE_ALLOC_SIZE 0x20000000 #else # error "unknown Darwin target" #endif @@ -67,13 +65,7 @@ void * darwin_gt_pch_get_address (size_t sz, int fd) { - if (sz > SAFE_ALLOC_SIZE) - { - error ("PCH memory request exceeds the available space"); - return NULL; - } - - /* Now try with the constraint that we really want this address... */ + /* First try with the constraint that we really want this address... */ void *addr = mmap ((void *)TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0); @@ -86,47 +78,36 @@ darwin_gt_pch_get_address (size_t sz, int fd) if (addr == (void *) TRY_EMPTY_VM_SPACE) return addr; - warning (OPT_Winvalid_pch, "PCH memory [fixed at %p] is not available %m", - (void *) TRY_EMPTY_VM_SPACE); - /* OK try to find a space without the constraint. */ addr = mmap ((void *) TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - /* If we failed this time, that means there is *no* large enough free - space. */ - if (addr == (void *) MAP_FAILED) + /* We return whatever the kernel gave us. */ + if (addr != (void *) MAP_FAILED) { - error ("no memory is available for PCH : %m"); - return NULL; + /* Unmap the area before returning. */ + munmap (addr, sz); + return addr; } - /* Unmap the area before returning. */ - munmap (addr, sz); - - /* If we got the exact area we requested, then that's great. */ - if (TRY_EMPTY_VM_SPACE && addr == (void *) TRY_EMPTY_VM_SPACE) - return addr; - - warning (OPT_Winvalid_pch, "PCH memory at %p is not available", - (void *) TRY_EMPTY_VM_SPACE); - - /* Otherwise, we need to try again but put some buffer space first. */ - size_t buffer_size = 32 * 1024 * 1024; + /* Otherwise, try again but put some arbitrary buffer space first. */ + size_t buffer_size = 64 * 1024 * 1024; void *buffer = mmap (0, buffer_size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); addr = mmap ((void *)TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (buffer != (void *) MAP_FAILED) munmap (buffer, buffer_size); + /* If we failed this time, that means there is *no* large enough free + space. */ if (addr == (void *) MAP_FAILED) { error ("PCH memory not available %m"); return NULL; } - warning (OPT_Winvalid_pch, "PCH memory at %p used instead", addr); munmap (addr, sz); return addr; } @@ -136,7 +117,7 @@ darwin_gt_pch_get_address (size_t sz, int fd) fail with -1. */ int -darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off) +darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off) { void *mapped_addr; @@ -147,9 +128,6 @@ darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off) return -1; gcc_checking_assert (!(off % PAGE_SZ)); - if (addr != (void *) TRY_EMPTY_VM_SPACE) - warning (OPT_Winvalid_pch, "PCH at %p does not use the default position", - addr); /* Try to map the file with MAP_PRIVATE and FIXED. */ mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, @@ -159,25 +137,34 @@ darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off) if (mapped_addr == addr) return 1; - warning (OPT_Winvalid_pch, "PCH private mmap of written position (%p)" - " failed [errno %d] %m", addr, errno); - + /* In theory, the only alternative to success for MAP_FIXED should be FAILED + however, there are some buggy earlier implementations that could return + an address. */ if (mapped_addr != (void *) MAP_FAILED) munmap (mapped_addr, sz); - /* Try to make an anonymous private mmap at the desired location. */ + /* Try to map the file with MAP_PRIVATE but let the kernel move it. */ mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, (off_t)0); + MAP_PRIVATE, fd, (off_t) off); - if (mapped_addr != addr) + /* Hopefully, we succeed. */ + if (mapped_addr != (void *) MAP_FAILED) { - warning (OPT_Winvalid_pch, "PCH anon mmap at written position (%p)" - " failed [errno %d] %m", addr, errno); - if (mapped_addr != (void *) MAP_FAILED) - munmap (mapped_addr, sz); - return -1; + addr = mapped_addr; + return 1; } + /* Try to make an anonymous private mmap at the desired location in case + the problem is in mapping the file. */ + mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, (off_t)0); + + /* If this fails, we are out of ideas (and maybe memory). */ + if (mapped_addr == (void *) MAP_FAILED) + return -1; + + addr = mapped_addr; + if (lseek (fd, off, SEEK_SET) == (off_t) -1) return -1; @@ -185,10 +172,10 @@ darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off) { ssize_t nbytes; - nbytes = read (fd, addr, MIN (sz, (size_t) -1 >> 1)); + nbytes = read (fd, mapped_addr, MIN (sz, (size_t) -1 >> 1)); if (nbytes <= 0) return -1; - addr = (char *) addr + nbytes; + mapped_addr = (char *) mapped_addr + nbytes; sz -= nbytes; } diff --git a/gcc/config/host-darwin.h b/gcc/config/host-darwin.h index 4acae9c..f3a477e 100644 --- a/gcc/config/host-darwin.h +++ b/gcc/config/host-darwin.h @@ -18,7 +18,7 @@ <http://www.gnu.org/licenses/>. */ extern void * darwin_gt_pch_get_address (size_t sz, int fd); -extern int darwin_gt_pch_use_address (void *addr, size_t sz, int fd, +extern int darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off); #undef HOST_HOOKS_GT_PCH_GET_ADDRESS diff --git a/gcc/config/host-hpux.c b/gcc/config/host-hpux.c index 6009810..c63dda8 100644 --- a/gcc/config/host-hpux.c +++ b/gcc/config/host-hpux.c @@ -24,7 +24,7 @@ #include "hosthooks-def.h" static void *hpux_gt_pch_get_address (size_t, int); -static int hpux_gt_pch_use_address (void *, size_t, int, size_t); +static int hpux_gt_pch_use_address (void *&, size_t, int, size_t); #undef HOST_HOOKS_GT_PCH_GET_ADDRESS #define HOST_HOOKS_GT_PCH_GET_ADDRESS hpux_gt_pch_get_address @@ -78,7 +78,7 @@ hpux_gt_pch_get_address (size_t size, int fd) little else we can do given the current PCH implementation. */ static int -hpux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +hpux_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; @@ -115,10 +115,10 @@ hpux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) { ssize_t nbytes; - nbytes = read (fd, base, MIN (size, SSIZE_MAX)); + nbytes = read (fd, addr, MIN (size, SSIZE_MAX)); if (nbytes <= 0) return -1; - base = (char *) base + nbytes; + addr = (char *) addr + nbytes; size -= nbytes; } diff --git a/gcc/config/host-linux.c b/gcc/config/host-linux.c index 34945f1..0481ecf 100644 --- a/gcc/config/host-linux.c +++ b/gcc/config/host-linux.c @@ -181,7 +181,7 @@ linux_gt_pch_get_address (size_t size, int fd) little else we can do given the current PCH implementation. */ static int -linux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +linux_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; @@ -204,24 +204,22 @@ linux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (addr != base) - { - if (addr != (void *) MAP_FAILED) - munmap (addr, size); - return -1; - } + if (addr == (void *) MAP_FAILED) + return -1; if (lseek (fd, offset, SEEK_SET) == (off_t)-1) return -1; + base = addr; + while (size) { ssize_t nbytes; - nbytes = read (fd, base, MIN (size, (size_t)-1 >> 1)); + nbytes = read (fd, addr, MIN (size, (size_t)-1 >> 1)); if (nbytes <= 0) return -1; - base = (char *) base + nbytes; + addr = (char *) addr + nbytes; size -= nbytes; } diff --git a/gcc/config/host-netbsd.c b/gcc/config/host-netbsd.c index 818ecb2..32f86c8 100644 --- a/gcc/config/host-netbsd.c +++ b/gcc/config/host-netbsd.c @@ -66,7 +66,7 @@ netbsd_gt_pch_get_address (size_t size, int fd) mapping the data at BASE, -1 if we couldn't. */ static int -netbsd_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +netbsd_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git a/gcc/config/host-openbsd.c b/gcc/config/host-openbsd.c index c5f8944..f7b9043 100644 --- a/gcc/config/host-openbsd.c +++ b/gcc/config/host-openbsd.c @@ -66,7 +66,7 @@ openbsd_gt_pch_get_address (size_t size, int fd) mapping the data at BASE, -1 if we couldn't. */ static int -openbsd_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +openbsd_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git a/gcc/config/host-solaris.c b/gcc/config/host-solaris.c index 556e9cf..b08cf51 100644 --- a/gcc/config/host-solaris.c +++ b/gcc/config/host-solaris.c @@ -105,7 +105,7 @@ sol_gt_pch_get_address (size_t size, int fd) mapping the data at BASE, -1 if we couldn't. */ static int -sol_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +sol_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git a/gcc/config/i386/host-mingw32.c b/gcc/config/i386/host-mingw32.c index 360a280..a182563 100644 --- a/gcc/config/i386/host-mingw32.c +++ b/gcc/config/i386/host-mingw32.c @@ -32,7 +32,7 @@ #include <stdlib.h> static void * mingw32_gt_pch_get_address (size_t, int); -static int mingw32_gt_pch_use_address (void *, size_t, int, size_t); +static int mingw32_gt_pch_use_address (void *&, size_t, int, size_t); static size_t mingw32_gt_pch_alloc_granularity (void); #undef HOST_HOOKS_GT_PCH_GET_ADDRESS @@ -118,7 +118,7 @@ mingw32_gt_pch_get_address (size_t size, int) if the memory is allocated but the data not loaded, return 1 if done. */ static int -mingw32_gt_pch_use_address (void *addr, size_t size, int fd, +mingw32_gt_pch_use_address (void *&addr, size_t size, int fd, size_t offset) { void * mmap_addr; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f1e41fd..9f4ed34 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -23144,8 +23144,7 @@ ix86_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, for Silvermont as it has out of order integer pipeline and can execute 2 scalar instruction per tick, but has in order SIMD pipeline. */ if ((TARGET_CPU_P (SILVERMONT) || TARGET_CPU_P (GOLDMONT) - || TARGET_CPU_P (GOLDMONT_PLUS) || TARGET_CPU_P (TREMONT) - || TARGET_CPU_P (INTEL)) + || TARGET_CPU_P (GOLDMONT_PLUS) || TARGET_CPU_P (INTEL)) && stmt_info && stmt_info->stmt) { tree lhs_op = gimple_get_lhs (stmt_info->stmt); diff --git a/gcc/config/nvptx/nvptx-c.c b/gcc/config/nvptx/nvptx-c.c index 72594a82e..7efdf70 100644 --- a/gcc/config/nvptx/nvptx-c.c +++ b/gcc/config/nvptx/nvptx-c.c @@ -39,7 +39,9 @@ nvptx_cpu_cpp_builtins (void) cpp_define (parse_in, "__nvptx_softstack__"); if (TARGET_UNIFORM_SIMT) cpp_define (parse_in,"__nvptx_unisimt__"); - if (TARGET_SM35) + if (TARGET_SM53) + cpp_define (parse_in, "__PTX_SM__=530"); + else if (TARGET_SM35) cpp_define (parse_in, "__PTX_SM__=350"); else cpp_define (parse_in,"__PTX_SM__=300"); diff --git a/gcc/config/nvptx/nvptx-modes.def b/gcc/config/nvptx/nvptx-modes.def index ff61b36..cc19a26 100644 --- a/gcc/config/nvptx/nvptx-modes.def +++ b/gcc/config/nvptx/nvptx-modes.def @@ -1,3 +1,5 @@ +FLOAT_MODE (HF, 2, ieee_half_format); /* HFmode */ + VECTOR_MODE (INT, SI, 2); /* V2SI */ VECTOR_MODE (INT, DI, 2); /* V2DI */ diff --git a/gcc/config/nvptx/nvptx-opts.h b/gcc/config/nvptx/nvptx-opts.h index bfa926e..f7371dc 100644 --- a/gcc/config/nvptx/nvptx-opts.h +++ b/gcc/config/nvptx/nvptx-opts.h @@ -23,7 +23,8 @@ enum ptx_isa { PTX_ISA_SM30, - PTX_ISA_SM35 + PTX_ISA_SM35, + PTX_ISA_SM53 }; enum ptx_version diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c index 951252e..445d7ce 100644 --- a/gcc/config/nvptx/nvptx.c +++ b/gcc/config/nvptx/nvptx.c @@ -294,6 +294,8 @@ nvptx_ptx_type_from_mode (machine_mode mode, bool promote) case E_DImode: return ".u64"; + case E_HFmode: + return ".f16"; case E_SFmode: return ".f32"; case E_DFmode: @@ -5406,7 +5408,9 @@ nvptx_file_start (void) fputs ("\t.version\t6.3\n", asm_out_file); else fputs ("\t.version\t3.1\n", asm_out_file); - if (TARGET_SM35) + if (TARGET_SM53) + fputs ("\t.target\tsm_53\n", asm_out_file); + else if (TARGET_SM35) fputs ("\t.target\tsm_35\n", asm_out_file); else fputs ("\t.target\tsm_30\n", asm_out_file); @@ -5717,7 +5721,9 @@ nvptx_omp_device_kind_arch_isa (enum omp_device_kind_arch_isa trait, if (strcmp (name, "sm_30") == 0) return !TARGET_SM35; if (strcmp (name, "sm_35") == 0) - return TARGET_SM35; + return TARGET_SM35 && !TARGET_SM53; + if (strcmp (name, "sm_53") == 0) + return TARGET_SM53; return 0; default: gcc_unreachable (); @@ -6614,6 +6620,24 @@ nvptx_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, } static bool +nvptx_scalar_mode_supported_p (scalar_mode mode) +{ + if (mode == HFmode && TARGET_SM53) + return true; + + return default_scalar_mode_supported_p (mode); +} + +static bool +nvptx_libgcc_floating_mode_supported_p (scalar_float_mode mode) +{ + if (mode == HFmode && TARGET_SM53) + return true; + + return default_libgcc_floating_mode_supported_p (mode); +} + +static bool nvptx_vector_mode_supported (machine_mode mode) { return (mode == V2SImode @@ -6935,6 +6959,13 @@ nvptx_libc_has_function (enum function_class fn_class, tree type) #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM nvptx_cannot_force_const_mem +#undef TARGET_SCALAR_MODE_SUPPORTED_P +#define TARGET_SCALAR_MODE_SUPPORTED_P nvptx_scalar_mode_supported_p + +#undef TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P +#define TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P \ + nvptx_libgcc_floating_mode_supported_p + #undef TARGET_VECTOR_MODE_SUPPORTED_P #define TARGET_VECTOR_MODE_SUPPORTED_P nvptx_vector_mode_supported diff --git a/gcc/config/nvptx/nvptx.h b/gcc/config/nvptx/nvptx.h index d367174..c3480cc 100644 --- a/gcc/config/nvptx/nvptx.h +++ b/gcc/config/nvptx/nvptx.h @@ -87,6 +87,7 @@ #define STACK_SIZE_MODE Pmode #define TARGET_SM35 (ptx_isa_option >= PTX_ISA_SM35) +#define TARGET_SM53 (ptx_isa_option >= PTX_ISA_SM53) #define TARGET_PTX_6_3 (ptx_version_option >= PTX_VERSION_6_3) diff --git a/gcc/config/nvptx/nvptx.md b/gcc/config/nvptx/nvptx.md index b7a0393..da4ac8f 100644 --- a/gcc/config/nvptx/nvptx.md +++ b/gcc/config/nvptx/nvptx.md @@ -273,6 +273,48 @@ } [(set_attr "subregs_ok" "true")]) +(define_insn "*movhf_insn" + [(set (match_operand:HF 0 "nonimmediate_operand" "=R,R,m") + (match_operand:HF 1 "nonimmediate_operand" "R,m,R"))] + "!MEM_P (operands[0]) || REG_P (operands[1])" + "@ + %.\\tmov.b16\\t%0, %1; + %.\\tld.b16\\t%0, %1; + %.\\tst.b16\\t%0, %1;") + +(define_expand "movhf" + [(set (match_operand:HF 0 "nonimmediate_operand" "") + (match_operand:HF 1 "nonimmediate_operand" ""))] + "" +{ + /* Load HFmode constants as SFmode with an explicit FLOAT_TRUNCATE. */ + if (CONST_DOUBLE_P (operands[1])) + { + rtx tmp1 = gen_reg_rtx (SFmode); + REAL_VALUE_TYPE d = *CONST_DOUBLE_REAL_VALUE (operands[1]); + real_convert (&d, SFmode, &d); + emit_move_insn (tmp1, const_double_from_real_value (d, SFmode)); + + if (!REG_P (operands[0])) + { + rtx tmp2 = gen_reg_rtx (HFmode); + emit_insn (gen_truncsfhf2 (tmp2, tmp1)); + emit_move_insn (operands[0], tmp2); + } + else + emit_insn (gen_truncsfhf2 (operands[0], tmp1)); + DONE; + } + + if (MEM_P (operands[0]) && !REG_P (operands[1])) + { + rtx tmp = gen_reg_rtx (HFmode); + emit_move_insn (tmp, operands[1]); + emit_move_insn (operands[0], tmp); + DONE; + } +}) + (define_insn "load_arg_reg<mode>" [(set (match_operand:QHIM 0 "nvptx_register_operand" "=R") (unspec:QHIM [(match_operand 1 "const_int_operand" "n")] @@ -1078,6 +1120,29 @@ "flag_unsafe_math_optimizations" "%.\\tex2.approx%t0\\t%0, %1;") +;; HFmode floating point arithmetic. + +(define_insn "addhf3" + [(set (match_operand:HF 0 "nvptx_register_operand" "=R") + (plus:HF (match_operand:HF 1 "nvptx_register_operand" "R") + (match_operand:HF 2 "nvptx_register_operand" "R")))] + "TARGET_SM53" + "%.\\tadd.f16\\t%0, %1, %2;") + +(define_insn "subhf3" + [(set (match_operand:HF 0 "nvptx_register_operand" "=R") + (minus:HF (match_operand:HF 1 "nvptx_register_operand" "R") + (match_operand:HF 2 "nvptx_register_operand" "R")))] + "TARGET_SM53" + "%.\\tsub.f16\\t%0, %1, %2;") + +(define_insn "mulhf3" + [(set (match_operand:HF 0 "nvptx_register_operand" "=R") + (mult:HF (match_operand:HF 1 "nvptx_register_operand" "R") + (match_operand:HF 2 "nvptx_register_operand" "R")))] + "TARGET_SM53" + "%.\\tmul.f16\\t%0, %1, %2;") + ;; Conversions involving floating point (define_insn "extendsfdf2" @@ -1171,6 +1236,18 @@ "" "%.\\tcvt<FPINT2:fpint2_roundingmode>.s%T0%t1\\t%0, %1;") +(define_insn "extendhf<mode>2" + [(set (match_operand:SDFM 0 "nvptx_register_operand" "=R") + (float_extend:SDFM (match_operand:HF 1 "nvptx_register_operand" "R")))] + "TARGET_SM53" + "%.\\tcvt%t0%t1\\t%0, %1;") + +(define_insn "trunc<mode>hf2" + [(set (match_operand:HF 0 "nvptx_register_operand" "=R") + (float_truncate:HF (match_operand:SDFM 1 "nvptx_register_operand" "R")))] + "TARGET_SM53" + "%.\\tcvt%#%t0%t1\\t%0, %1;") + ;; Vector operations (define_insn "*vec_set<mode>_0" diff --git a/gcc/config/nvptx/nvptx.opt b/gcc/config/nvptx/nvptx.opt index 468c6ca..514f19d 100644 --- a/gcc/config/nvptx/nvptx.opt +++ b/gcc/config/nvptx/nvptx.opt @@ -61,6 +61,9 @@ Enum(ptx_isa) String(sm_30) Value(PTX_ISA_SM30) EnumValue Enum(ptx_isa) String(sm_35) Value(PTX_ISA_SM35) +EnumValue +Enum(ptx_isa) String(sm_53) Value(PTX_ISA_SM53) + ; Default needs to be in sync with default in ASM_SPEC in nvptx.h. misa= Target RejectNegative ToLower Joined Enum(ptx_isa) Var(ptx_isa_option) Init(PTX_ISA_SM35) diff --git a/gcc/config/rs6000/rs6000-gen-builtins.c b/gcc/config/rs6000/rs6000-gen-builtins.c index d2e9c4c..34ab70f 100644 --- a/gcc/config/rs6000/rs6000-gen-builtins.c +++ b/gcc/config/rs6000/rs6000-gen-builtins.c @@ -2886,7 +2886,7 @@ write_init_file (void) "void gt_pch_nx (bifdata *bd, gt_pointer_operator op, " "void *cookie)\n"); fprintf (init_file, - "{\n op(&(bd->fntype), cookie);\n}\n\n"); + "{\n op(&(bd->fntype), NULL, cookie);\n}\n\n"); fprintf (init_file, "void gt_ggc_mx (ovlddata *od)\n"); fprintf (init_file, @@ -2899,7 +2899,7 @@ write_init_file (void) "void gt_pch_nx (ovlddata *od, gt_pointer_operator op, " "void *cookie)\n"); fprintf (init_file, - "{\n op(&(od->fntype), cookie);\n}\n"); + "{\n op(&(od->fntype), NULL, cookie);\n}\n"); return 1; } diff --git a/gcc/config/t-vxworks b/gcc/config/t-vxworks index 5a06ebe..0175a5f 100644 --- a/gcc/config/t-vxworks +++ b/gcc/config/t-vxworks @@ -24,24 +24,11 @@ vxworks-c.o: $(srcdir)/config/vxworks-c.c $(COMPILE) $< $(POSTCOMPILE) -# Arrange to install our stdint.h wrapper, by copying it in the -# build-time include dir before this include dir is installed and after -# stmp-int-hdrs removes it (because it was told we don't provide it). - -INSTALL_HEADERS += install-stdint.h - -install-stdint.h: stmp-int-hdrs - cp -p $(srcdir)/config/vxworks/stdint.h include/stdint.h - chmod a+r include/stdint.h - -$(INSTALL_HEADERS_DIR): install-stdint.h - # Both the kernel and RTP headers provide limits.h. They embed VxWorks # specificities and are dated on some configurations so we both need to # provide our own version and make sure the system one gets exposed. LIMITS_H_TEST = true -STMP_FIXINC = stmp-fixinc # VxWorks system environments have been GCC based for a long time and # we need to make sure that our files and the system ones use distinct @@ -54,5 +41,13 @@ T_GLIMITS_H = vxw-glimits.h vxw-glimits.h: $(srcdir)/glimits.h ID=`echo $(BASEVER_c) | sed -e 's/\./_/g'` && \ - sed -e "s/_LIMITS_H__/_LIMITS_H__$${ID}_/" < $(srcdir)/glimits.h > $@T + sed -e "s/_LIMITS_H__/_LIMITS_H__$${ID}_/" < $< > $@T + mv $@T $@ + +# Arrange to "provide" a tailored version of stdint-gcc.h + +T_STDINT_GCC_H = vxw-stdint-gcc.h + +vxw-stdint-gcc.h: $(srcdir)/ginclude/stdint-gcc.h + sed -e "/#define _GCC_STDINT_H/ a #include <_yvals.h>" < $< > $@T mv $@T $@ diff --git a/gcc/config/vxworks.h b/gcc/config/vxworks.h index bddf2c3..8210de4 100644 --- a/gcc/config/vxworks.h +++ b/gcc/config/vxworks.h @@ -141,8 +141,8 @@ along with GCC; see the file COPYING3. If not see %{!shared: \ %{mrtp:-q %{h*} \ %{R*} %{!T*: %(link_start) } \ - %(link_target) %(link_os)}} \ - %{v:-v} \ + %(link_os)}} \ + %{v:-V} \ %{shared:-shared} \ %{Bstatic:-Bstatic} \ %{Bdynamic:-Bdynamic} \ diff --git a/gcc/config/vxworks/stdint.h b/gcc/config/vxworks/stdint.h deleted file mode 100644 index 5e0dbdf..0000000 --- a/gcc/config/vxworks/stdint.h +++ /dev/null @@ -1,28 +0,0 @@ -/* This file is part of GCC. - -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. - -Under Section 7 of GPL version 3, you are granted additional -permissions described in the GCC Runtime Library Exception, version -3.1, as published by the Free Software Foundation. - -You should have received a copy of the GNU General Public License and -a copy of the GCC Runtime Library Exception along with this program; -see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -<http://www.gnu.org/licenses/>. */ - -#ifndef __GCC_STDINT_H -#define __GCC_STDINT_H - -#include <_yvals.h> -#include <stdint-gcc.h> - -#endif diff --git a/gcc/coretypes.h b/gcc/coretypes.h index b4f530d..5d0fc1d 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -442,8 +442,10 @@ enum optimize_size_level }; /* Support for user-provided GGC and PCH markers. The first parameter - is a pointer to a pointer, the second a cookie. */ -typedef void (*gt_pointer_operator) (void *, void *); + is a pointer to a pointer, the second either NULL if the pointer to + pointer points into a GC object or the actual pointer address if + the first argument points to a temporary and the third a cookie. */ +typedef void (*gt_pointer_operator) (void *, void *, void *); #if !defined (HAVE_UCHAR) typedef unsigned char uchar; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a8e7fb..3ea43f1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2021-12-09 Marek Polacek <polacek@redhat.com> + + PR c++/103401 + * parser.c (cp_parser_decltype): Clear + auto_is_implicit_function_template_parm_p. + (cp_parser_type_id_1): Give errors only when !cp_parser_simulate_error. + (cp_parser_parameter_declaration): Clear + auto_is_implicit_function_template_parm_p after parsing the + decl-specifier-seq. + (cp_parser_sizeof_operand): Clear + auto_is_implicit_function_template_parm_p. + +2021-12-09 Jakub Jelinek <jakub@redhat.com> + + PR pch/71934 + * module.cc (nop): Add another void * argument. + * name-lookup.c (resort_member_name_cmp): Pass the same pointer twice + to resort_data.new_value. + 2021-12-08 Chung-Lin Tang <cltang@codesourcery.com> * parser.c (struct omp_dim): New struct type for use inside diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 71d0fab..9266055 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -11750,7 +11750,7 @@ trees_out::mark_class_def (tree defn) /* Nop sorting, needed for resorting the member vec. */ static void -nop (void *, void *) +nop (void *, void *, void *) { } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 0806928..229ba45 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2123,8 +2123,8 @@ resort_member_name_cmp (const void *a_p, const void *b_p) tree name_a = OVL_NAME (a); tree name_b = OVL_NAME (b); - resort_data.new_value (&name_a, resort_data.cookie); - resort_data.new_value (&name_b, resort_data.cookie); + resort_data.new_value (&name_a, &name_a, resort_data.cookie); + resort_data.new_value (&name_b, &name_b, resort_data.cookie); gcc_checking_assert (name_a != name_b); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6f273bf..de464afd 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -16432,6 +16432,16 @@ cp_parser_decltype (cp_parser *parser) = parser->greater_than_is_operator_p; parser->greater_than_is_operator_p = true; + /* Don't synthesize an implicit template type parameter here. This + could happen with C++23 code like + + void f(decltype(new auto{0})); + + where we want to deduce the auto right away so that the parameter + is of type 'int *'. */ + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, false); + /* Do not actually evaluate the expression. */ ++cp_unevaluated_operand; @@ -24144,22 +24154,22 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags, /* OK */; else { - location_t loc = type_specifier_seq.locations[ds_type_spec]; - if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + if (!cp_parser_simulate_error (parser)) { - if (!cp_parser_simulate_error (parser)) + location_t loc = type_specifier_seq.locations[ds_type_spec]; + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) { error_at (loc, "missing template arguments after %qT", auto_node); inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here", tmpl); } + else if (parser->in_template_argument_list_p) + error_at (loc, "%qT not permitted in template argument", + auto_node); + else + error_at (loc, "invalid use of %qT", auto_node); } - else if (parser->in_template_argument_list_p) - error_at (loc, "%qT not permitted in template argument", - auto_node); - else - error_at (loc, "invalid use of %qT", auto_node); return error_mark_node; } } @@ -24668,6 +24678,15 @@ cp_parser_parameter_declaration (cp_parser *parser, &decl_specifiers, &declares_class_or_enum); + /* [dcl.spec.auto.general]: "A placeholder-type-specifier of the form + type-constraint opt auto can be used as a decl-specifier of the + decl-specifier-seq of a parameter-declaration of a function declaration + or lambda-expression..." but we must not synthesize an implicit template + type parameter in its declarator. That is, in "void f(auto[auto{10}]);" + we want to synthesize only the first auto. */ + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, false); + /* Complain about missing 'typename' or other invalid type names. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -32369,6 +32388,9 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword) = parser->non_integral_constant_expression_p; parser->integral_constant_expression_p = false; + auto cleanup = make_temp_override + (parser->auto_is_implicit_function_template_parm_p, false); + /* Do not actually evaluate the expression. */ ++cp_unevaluated_operand; ++c_inhibit_evaluation_warnings; diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 370e33c..91b3d7c 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,42 @@ +2021-12-10 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/103529 + * dmd/MERGE: Merge upstream dmd 3982604c5. + * Make-lang.in (D_FRONTEND_OBJS): Add d/root-optional.o. + * d-attribs.cc (build_attributes): Update for new front-end interface. + * d-codegen.cc (d_build_call): Likewise. + * d-compiler.cc (Compiler::paintAsType): Likewise. + * d-lang.cc (d_handle_option): Remove OPT_fpreview_intpromote, add + handling of OPT_frevert_intpromote. + * d-port.cc (Port::valcpy): Assert buffer is aligned. + * d-target.cc (Target::isVectorOpSupported): Update for new front-end + interface. + * decl.cc (layout_class_initializer): Likewise. + * expr.cc (lvalue_p): Likewise. + (binop_assignment): Likewise. + (ExprVisitor::visit): Likewise. + (ExprVisitor::visit (AssignExp *)): Remove generation of _d_arrayctor + and _d_arraysetctor library helpers. + (ExprVisitor::visit (VarExp *)): Support __traits(initSymbol). + * intrinsics.cc (expand_intrinsic_rotate): Update for new front-end + interface. + * lang.opt (fpreview=intpromote): Remove. + (frevert=intpromote): New. + * runtime.def (ARRAYCTOR): Remove. + (ARRAYSETCTOR): Remove. + * toir.cc (IRVisitor::visit): Update for new front-end interface. + * types.cc (layout_aggregate_members): Likewise. + * dmd/root/optional.d: New file. + * dmd/root/optional.h: New file. + +2021-12-10 Iain Buclaw <ibuclaw@gdcproject.org> + + * decl.cc (get_symbol_decl): Align methods to MINIMUM_METHOD_BOUNDARY. + +2021-12-09 Martin Liska <mliska@suse.cz> + + * expr.cc: Call memcpy only when length != 0. + 2021-12-08 Iain Buclaw <ibuclaw@gdcproject.org> * dmd/MERGE: Merge upstream dmd 568496d5b. diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index d7f7147..00169a7 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -162,6 +162,7 @@ D_FRONTEND_OBJS = \ d/root-filename.o \ d/root-hash.o \ d/root-longdouble.o \ + d/root-optional.o \ d/root-port.o \ d/root-region.o \ d/root-rmem.o \ diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 04b9791..5c9f569 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -337,10 +337,10 @@ build_attributes (Expressions *eattrs) continue; /* Get the result of the attribute if it hasn't already been folded. */ - if (attr->op == TOKcall) + if (attr->op == EXP::call) attr = attr->ctfeInterpret (); - if (attr->op != TOKstructliteral) + if (attr->op != EXP::structLiteral) { warning_at (make_location_t (attr->loc), OPT_Wattributes, "%qE attribute has no effect", @@ -353,7 +353,7 @@ build_attributes (Expressions *eattrs) Expressions *elems = attr->isStructLiteralExp ()->elements; Expression *e0 = (*elems)[0]; - if (e0->op != TOKstring) + if (e0->op != EXP::string_) { warning_at (make_location_t (attr->loc), OPT_Wattributes, "unknown attribute %qs", e0->toChars()); diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index c082ac5..39c3c6c 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2154,9 +2154,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object, { Lagain: Expression *arg = (*arguments)[i]; - gcc_assert (arg->op != TOKtuple); + gcc_assert (arg->op != EXP::tuple); - if (arg->op == TOKcomma) + if (arg->op == EXP::comma) { CommaExp *ce = arg->isCommaExp (); tree tce = build_expr (ce->e1); @@ -2200,7 +2200,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object, /* Nested structs also have ADDRESSABLE set, but if the type has neither a copy constructor nor a destructor available, then we need to take care of copying its value before passing it. */ - if (arg->op == TOKstructliteral || (!sd->postblit && !sd->dtor)) + if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor)) targ = force_target_expr (targ); targ = convert (build_reference_type (TREE_TYPE (targ)), diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc index 3df40073..c1e78c0 100644 --- a/gcc/d/d-compiler.cc +++ b/gcc/d/d-compiler.cc @@ -50,7 +50,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type) cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type)); else if (expr->type->isfloating ()) cst = build_float_cst (expr->toReal (), expr->type); - else if (expr->op == TOKarrayliteral) + else if (expr->op == EXP::arrayLiteral) { /* Build array as VECTOR_CST, assumes EXPR is constant. */ Expressions *elements = expr->isArrayLiteralExp ()->elements; @@ -99,7 +99,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type) cst = native_interpret_expr (vectype, buffer, len); Expression *e = d_eval_constant_expression (expr->loc, cst); - gcc_assert (e != NULL && e->op == TOKvector); + gcc_assert (e != NULL && e->op == EXP::vector); return e->isVectorExp ()->e1; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 576eefc..2c5d206 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -620,10 +620,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.inclusiveInContracts = value; break; - case OPT_fpreview_intpromote: - global.params.fix16997 = value; - break; - case OPT_fpreview_nosharedaccess: global.params.noSharedAccess = value; break; @@ -642,8 +638,9 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, case OPT_frevert_all: global.params.useDIP25 = FeatureState::disabled; - global.params.markdown = !value; global.params.dtorFields = FeatureState::disabled; + global.params.fix16997 = !value; + global.params.markdown = !value; break; case OPT_frevert_dip25: @@ -654,6 +651,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.dtorFields = FeatureState::disabled; break; + case OPT_frevert_intpromote: + global.params.fix16997 = !value; + break; + case OPT_frevert_markdown: global.params.markdown = !value; break; diff --git a/gcc/d/d-port.cc b/gcc/d/d-port.cc index 58b3fe1..4e867a7 100644 --- a/gcc/d/d-port.cc +++ b/gcc/d/d-port.cc @@ -145,6 +145,8 @@ Port::readlongBE (const void *buffer) void Port::valcpy (void *buffer, uint64_t value, size_t sz) { + gcc_assert (((size_t) buffer) % sz == 0); + switch (sz) { case 1: diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 21417dd..dd244f1 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -287,7 +287,7 @@ Target::isVectorTypeSupported (int sz, Type *type) Returns true if the operation is supported or type is not a vector. */ bool -Target::isVectorOpSupported (Type *type, unsigned op, Type *) +Target::isVectorOpSupported (Type *type, EXP op, Type *) { if (type->ty != TY::Tvector) return true; @@ -299,31 +299,31 @@ Target::isVectorOpSupported (Type *type, unsigned op, Type *) /* Don't support if expression cannot be represented. */ switch (op) { - case TOKpow: - case TOKpowass: + case EXP::pow: + case EXP::powAssign: /* pow() is lowered as a function call. */ return false; - case TOKmod: - case TOKmodass: + case EXP::mod: + case EXP::modAssign: /* fmod() is lowered as a function call. */ if (type->isfloating ()) return false; break; - case TOKandand: - case TOKoror: + case EXP::andAnd: + case EXP::orOr: /* Logical operators must have a result type of bool. */ return false; - case TOKle: - case TOKlt: - case TOKge: - case TOKgt: - case TOKequal: - case TOKnotequal: - case TOKidentity: - case TOKnotidentity: + case EXP::lessOrEqual: + case EXP::lessThan: + case EXP::greaterOrEqual: + case EXP::greaterThan: + case EXP::equal: + case EXP::notEqual: + case EXP::identity: + case EXP::notIdentity: /* Comparison operators must have a result type of bool. */ return false; diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index a4976b6..bbde4a6 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1248,6 +1248,9 @@ get_symbol_decl (Declaration *decl) DECL_VINDEX (decl->csym) = size_int (fd->vtblIndex); DECL_VIRTUAL_P (decl->csym) = 1; } + + /* Align method to the minimum boundary for target. */ + SET_DECL_ALIGN (decl->csym, MINIMUM_METHOD_BOUNDARY); } else if (fd->isMain () || fd->isCMain ()) { @@ -2236,7 +2239,7 @@ layout_class_initializer (ClassDeclaration *cd) ne->type = cd->type; Expression *e = ne->ctfeInterpret (); - gcc_assert (e->op == TOKclassreference); + gcc_assert (e->op == EXP::classReference); return build_class_instance (e->isClassReferenceExp ()); } diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index d23e1fe..4bae16c 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -568496d5b6ed02d577dfa86f73c7bb4edee05813 +3982604c54e8770585985a33577fbf19b9b5c9ce 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/access.d b/gcc/d/dmd/access.d index 944c9d3..d8a6517 100644 --- a/gcc/d/dmd/access.d +++ b/gcc/d/dmd/access.d @@ -201,7 +201,7 @@ bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d) { // Do access check ClassDeclaration cd = tc.sym; - if (e.op == TOK.super_) + if (e.op == EXP.super_) { if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration()) cd = cd2; diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 1fe8e80..dc772e8 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -472,7 +472,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol } foreach (e; *elements) { - if (e && e.op == TOK.error) + if (e && e.op == EXP.error) return false; } @@ -565,6 +565,18 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol override final Type getType() { + /* Apply storage classes to forward references. (Issue 22254) + * Note: Avoid interfaces for now. Implementing qualifiers on interface + * definitions exposed some issues in their TypeInfo generation in DMD. + * Related PR: https://github.com/dlang/dmd/pull/13312 + */ + if (semanticRun == PASS.init && !isInterfaceDeclaration()) + { + auto stc = storage_class; + if (_scope) + stc |= _scope.stc; + type = type.addSTC(stc); + } return type; } diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index e048cdc..80db47d 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -91,7 +91,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find if (ad.aliasthis) { Loc loc = e.loc; - Type tthis = (e.op == TOK.type ? e.type : null); + Type tthis = (e.op == EXP.type ? e.type : null); const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0); uint olderrors = gag ? global.startGagging() : 0; e = dotExp(e.type, sc, e, ad.aliasthis.ident, flags); @@ -100,7 +100,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find if (tthis && ad.aliasthis.sym.needThis()) { - if (e.op == TOK.variable) + if (e.op == EXP.variable) { if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) { diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index e2b3319..a234501 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -23,6 +23,7 @@ import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; +import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.mtype; @@ -37,9 +38,9 @@ import dmd.visitor; bool isArrayOpValid(Expression e) { //printf("isArrayOpValid() %s\n", e.toChars()); - if (e.op == TOK.slice) + if (e.op == EXP.slice) return true; - if (e.op == TOK.arrayLiteral) + if (e.op == EXP.arrayLiteral) { Type t = e.type.toBasetype(); while (t.ty == Tarray || t.ty == Tsarray) @@ -53,17 +54,17 @@ bool isArrayOpValid(Expression e) { return isArrayOpValid((cast(UnaExp)e).e1); } - if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign) + if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign) { BinExp be = cast(BinExp)e; return isArrayOpValid(be.e1) && isArrayOpValid(be.e2); } - if (e.op == TOK.construct) + if (e.op == EXP.construct) { BinExp be = cast(BinExp)e; - return be.e1.op == TOK.slice && isArrayOpValid(be.e2); + return be.e1.op == EXP.slice && isArrayOpValid(be.e2); } - // if (e.op == TOK.call) + // if (e.op == EXP.call) // { // TODO: Decide if [] is required after arrayop calls. // } @@ -74,7 +75,7 @@ bool isArrayOpValid(Expression e) bool isNonAssignmentArrayOp(Expression e) { - if (e.op == TOK.slice) + if (e.op == EXP.slice) return isNonAssignmentArrayOp((cast(SliceExp)e).e1); Type tb = e.type.toBasetype(); @@ -166,11 +167,11 @@ Expression arrayOp(BinAssignExp e, Scope* sc) if (tn && (!tn.isMutable() || !tn.isAssignable())) { e.error("slice `%s` is not mutable", e.e1.toChars()); - if (e.op == TOK.addAssign) + if (e.op == EXP.addAssign) checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp); return ErrorExp.get(); } - if (e.e1.op == TOK.arrayLiteral) + if (e.e1.op == EXP.arrayLiteral) { return e.e1.modifiableLvalue(sc, e.e1); } @@ -228,7 +229,7 @@ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* // RPN, prefix unary ops with u OutBuffer buf; buf.writestring("u"); - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); e.e1.accept(this); tiargs.push(new StringExp(Loc.initial, buf.extractSlice()).expressionSemantic(sc)); } @@ -246,7 +247,7 @@ private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* // RPN e.e1.accept(this); e.e2.accept(this); - tiargs.push(new StringExp(Loc.initial, Token.toString(e.op)).expressionSemantic(sc)); + tiargs.push(new StringExp(Loc.initial, EXPtoString(e.op)).expressionSemantic(sc)); } } } @@ -274,12 +275,12 @@ bool isArrayOpImplicitCast(TypeDArray tfrom, TypeDArray tto) /*********************************************** * Test if expression is a unary array op. */ -bool isUnaArrayOp(TOK op) +bool isUnaArrayOp(EXP op) { switch (op) { - case TOK.negate: - case TOK.tilde: + case EXP.negate: + case EXP.tilde: return true; default: break; @@ -290,19 +291,19 @@ bool isUnaArrayOp(TOK op) /*********************************************** * Test if expression is a binary array op. */ -bool isBinArrayOp(TOK op) +bool isBinArrayOp(EXP 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: + case EXP.add: + case EXP.min: + case EXP.mul: + case EXP.div: + case EXP.mod: + case EXP.xor: + case EXP.and: + case EXP.or: + case EXP.pow: return true; default: break; @@ -313,19 +314,19 @@ bool isBinArrayOp(TOK op) /*********************************************** * Test if expression is a binary assignment array op. */ -bool isBinAssignArrayOp(TOK op) +bool isBinAssignArrayOp(EXP 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: + case EXP.addAssign: + case EXP.minAssign: + case EXP.mulAssign: + case EXP.divAssign: + case EXP.modAssign: + case EXP.xorAssign: + case EXP.andAssign: + case EXP.orAssign: + case EXP.powAssign: return true; default: break; @@ -339,9 +340,9 @@ bool isBinAssignArrayOp(TOK op) bool isArrayOpOperand(Expression e) { //printf("Expression.isArrayOpOperand() %s\n", e.toChars()); - if (e.op == TOK.slice) + if (e.op == EXP.slice) return true; - if (e.op == TOK.arrayLiteral) + if (e.op == EXP.arrayLiteral) { Type t = e.type.toBasetype(); while (t.ty == Tarray || t.ty == Tsarray) @@ -354,7 +355,7 @@ bool isArrayOpOperand(Expression e) return (isUnaArrayOp(e.op) || isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || - e.op == TOK.assign); + e.op == EXP.assign); } return false; } @@ -371,9 +372,9 @@ bool isArrayOpOperand(Expression e) ErrorExp arrayOpInvalidError(Expression e) { e.error("invalid array operation `%s` (possible missing [])", e.toChars()); - if (e.op == TOK.add) + if (e.op == EXP.add) checkPossibleAddCatError!(AddExp, CatExp)(e.isAddExp()); - else if (e.op == TOK.addAssign) + else if (e.op == EXP.addAssign) checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp()); return ErrorExp.get(); } diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index df88bb9..f638765 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -62,7 +62,7 @@ enum STC : ulong // transfer changes to declaration.h 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 + // = 0x1_0000, templateparameter = 0x2_0000, /// template parameter ref_ = 0x4_0000, /// `ref` scope_ = 0x8_0000, /// `scope` @@ -74,7 +74,7 @@ enum STC : ulong // transfer changes to declaration.h 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 + // = 0x400_0000, manifest = 0x800_0000, /// manifest constant nodtor = 0x1000_0000, /// do not run destructor diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 0bf40ef..e8704aa 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -929,12 +929,13 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration (*args)[0] = e; } - if (e.isBool(true)) + const opt = e.toBool(); + if (opt.isEmpty()) + return PINLINE.default_; + else if (opt.get()) return PINLINE.always; - else if (e.isBool(false)) - return PINLINE.never; else - return PINLINE.default_; + return PINLINE.never; } override const(char)* kind() const @@ -1198,7 +1199,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration // expand static foreach import dmd.statementsem: makeTupleForeach; - Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion).decl; + Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl; if (d) // process generated declarations { // Add members lazily. diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 0ecd635..5945644 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -94,15 +94,15 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result = BE.fallthru; if (s.exp) { - if (s.exp.op == TOK.halt) + if (s.exp.op == EXP.halt) { result = BE.halt; return; } - if (s.exp.op == TOK.assert_) + if (s.exp.op == EXP.assert_) { AssertExp a = cast(AssertExp)s.exp; - if (a.e1.isBool(false)) // if it's an assert(0) + if (a.e1.toBool().hasValue(false)) // if it's an assert(0) { result = BE.halt; return; @@ -216,7 +216,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; - if (!(result & BE.break_) && s.condition.isBool(true)) + if (!(result & BE.break_) && s.condition.toBool().hasValue(true)) result &= ~BE.fallthru; } result &= ~(BE.break_ | BE.continue_); @@ -235,9 +235,10 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; - if (s.condition.isBool(true)) + const opt = s.condition.toBool(); + if (opt.hasValue(true)) result &= ~BE.fallthru; - else if (s.condition.isBool(false)) + else if (opt.hasValue(false)) return; } else @@ -274,11 +275,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result = BE.none; if (canThrow(s.condition, func, mustNotThrow)) result |= BE.throw_; - if (s.condition.isBool(true)) + + const opt = s.condition.toBool(); + if (opt.hasValue(true)) { result |= blockExit(s.ifbody, func, mustNotThrow); } - else if (s.condition.isBool(false)) + else if (opt.hasValue(false)) { result |= blockExit(s.elsebody, func, mustNotThrow); } @@ -534,4 +537,3 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) s.accept(be); return be.result; } - diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d index c4f84b1..2f5b6c7 100644 --- a/gcc/d/dmd/builtin.d +++ b/gcc/d/dmd/builtin.d @@ -13,8 +13,6 @@ module dmd.builtin; -import core.stdc.math; -import core.stdc.string; import dmd.arraytypes; import dmd.expression; import dmd.func; diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index ed05af6..b67a9d1 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -150,7 +150,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow override void visit(AssignExp ae) { // blit-init cannot throw - if (ae.op == TOK.blit) + if (ae.op == EXP.blit) return; /* Element-wise assignment could invoke postblits. */ diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index da66812..c536d25 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -578,7 +578,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) 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); + Expression e = new EqualExp(EXP.equal, loc, e1, e2); fop.fbody = new ReturnStatement(loc, e); uint errors = global.startGagging(); // Do not report errors Scope* sc2 = sc.push(); @@ -642,13 +642,13 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) Dsymbol s = null; switch (e.op) { - case TOK.overloadSet: + case EXP.overloadSet: s = (cast(OverExp)e).vars; break; - case TOK.scope_: + case EXP.scope_: s = (cast(ScopeExp)e).sds; break; - case TOK.variable: + case EXP.variable: s = (cast(VarExp)e).var; break; default: diff --git a/gcc/d/dmd/common/outbuffer.h b/gcc/d/dmd/common/outbuffer.h index a5e3f9c..ce23436 100644 --- a/gcc/d/dmd/common/outbuffer.h +++ b/gcc/d/dmd/common/outbuffer.h @@ -49,7 +49,7 @@ public: void reserve(d_size_t nbytes); void setsize(d_size_t size); void reset(); - void write(const void *data, size_t nbytes); + void write(const void *data, d_size_t nbytes); void writestring(const char *string); void prependstring(const char *string); void writenl(); // write newline diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 05bd4bd..abf2814 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -152,7 +152,7 @@ extern (C++) final class StaticForeach : RootObject sc = sc.endCTFE(); el = el.optimize(WANTvalue); el = el.ctfeInterpret(); - if (el.op == TOK.int64) + if (el.op == EXP.int64) { Expressions *es = void; if (auto ale = aggr.isArrayLiteralExp()) diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 1dada60..3ca23f2 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -56,13 +56,13 @@ int isConst(Expression e) //printf("Expression::isConst(): %s\n", e.toChars()); switch (e.op) { - case TOK.int64: - case TOK.float64: - case TOK.complex80: + case EXP.int64: + case EXP.float64: + case EXP.complex80: return 1; - case TOK.null_: + case EXP.null_: return 0; - case TOK.symbolOffset: + case EXP.symbolOffset: return 2; default: return 0; @@ -71,13 +71,13 @@ int isConst(Expression e) } /********************************** - * Initialize a TOK.cantExpression Expression. + * Initialize a EXP.cantExpression Expression. * Params: * ue = where to write it */ void cantExp(out UnionExp ue) { - emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); + emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); } /* =============================== constFold() ============================== */ @@ -120,7 +120,7 @@ UnionExp Not(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; - emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type); + emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type); return ue; } @@ -128,7 +128,7 @@ private UnionExp Bool(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; - emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type); + emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(true) ? 1 : 0, type); return ue; } @@ -222,13 +222,13 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2) } emplaceExp!(ComplexExp)(&ue, loc, v, type); } - else if (e1.op == TOK.symbolOffset) + else if (e1.op == EXP.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) + else if (e2.op == EXP.symbolOffset) { SymOffExp soe = cast(SymOffExp)e2; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger()); @@ -325,7 +325,7 @@ UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2) } emplaceExp!(ComplexExp)(&ue, loc, v, type); } - else if (e1.op == TOK.symbolOffset) + else if (e1.op == EXP.symbolOffset) { SymOffExp soe = cast(SymOffExp)e1; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger()); @@ -722,26 +722,26 @@ UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2) return ue; } -/* Also returns TOK.cantExpression if cannot be computed. +/* Also returns EXP.cantExpression if cannot be computed. */ -UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2) +UnionExp Equal(EXP 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_) + assert(op == EXP.equal || op == EXP.notEqual); + if (e1.op == EXP.null_) { - if (e2.op == TOK.null_) + if (e2.op == EXP.null_) cmp = 1; - else if (e2.op == TOK.string_) + else if (e2.op == EXP.string_) { StringExp es2 = cast(StringExp)e2; cmp = (0 == es2.len); } - else if (e2.op == TOK.arrayLiteral) + else if (e2.op == EXP.arrayLiteral) { ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; cmp = !es2.elements || (0 == es2.elements.dim); @@ -752,14 +752,14 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e return ue; } } - else if (e2.op == TOK.null_) + else if (e2.op == EXP.null_) { - if (e1.op == TOK.string_) + if (e1.op == EXP.string_) { StringExp es1 = cast(StringExp)e1; cmp = (0 == es1.len); } - else if (e1.op == TOK.arrayLiteral) + else if (e1.op == EXP.arrayLiteral) { ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; cmp = !es1.elements || (0 == es1.elements.dim); @@ -770,7 +770,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e return ue; } } - else if (e1.op == TOK.string_ && e2.op == TOK.string_) + else if (e1.op == EXP.string_ && e2.op == EXP.string_) { StringExp es1 = cast(StringExp)e1; StringExp es2 = cast(StringExp)e2; @@ -787,7 +787,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e else cmp = 0; } - else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral) + else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral) { ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; @@ -803,7 +803,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e { auto ee1 = es1[i]; auto ee2 = es2[i]; - ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2); + ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2); if (CTFEExp.isCantExp(ue.exp())) return ue; cmp = cast(int)ue.exp().toInteger(); @@ -812,7 +812,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e } } } - else if (e1.op == TOK.arrayLiteral && e2.op == TOK.string_) + else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_) { // Swap operands and use common code Expression etmp = e1; @@ -820,7 +820,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e e2 = etmp; goto Lsa; } - else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral) + else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral) { Lsa: StringExp es1 = cast(StringExp)e1; @@ -847,7 +847,7 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e } } } - else if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral) + else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral) { StructLiteralExp es1 = cast(StructLiteralExp)e1; StructLiteralExp es2 = cast(StructLiteralExp)e2; @@ -873,8 +873,8 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e cmp = 0; break; } - ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2); - if (ue.exp().op == TOK.cantExpression) + ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2); + if (ue.exp().op == EXP.cantExpression) return ue; cmp = cast(int)ue.exp().toInteger(); if (cmp == 0) @@ -920,25 +920,25 @@ UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e cantExp(ue); return ue; } - if (op == TOK.notEqual) + if (op == EXP.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 Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2) { UnionExp ue = void; int cmp; - if (e1.op == TOK.null_) + if (e1.op == EXP.null_) { - cmp = (e2.op == TOK.null_); + cmp = (e2.op == EXP.null_); } - else if (e2.op == TOK.null_) + else if (e2.op == EXP.null_) { cmp = 0; } - else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset) + else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset) { SymOffExp es1 = cast(SymOffExp)e1; SymOffExp es2 = cast(SymOffExp)e2; @@ -962,24 +962,24 @@ UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expressio } else { - ue = Equal((op == TOK.identity) ? TOK.equal : TOK.notEqual, loc, type, e1, e2); + ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2); return ue; } } - if (op == TOK.notIdentity) + if (op == EXP.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 Cmp(EXP 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_) + if (e1.op == EXP.string_ && e2.op == EXP.string_) { StringExp es1 = cast(StringExp)e1; StringExp es2 = cast(StringExp)e2; @@ -1032,7 +1032,7 @@ UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2) return ue; } -/* Also returns TOK.cantExpression if cannot be computed. +/* Also returns EXP.cantExpression if cannot be computed. * to: type to cast to * type: type to paint the result */ @@ -1048,7 +1048,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) emplaceExp!(UnionExp)(&ue, e1); return ue; } - if (e1.op == TOK.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to)) + if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to)) { Expression ex = (cast(VectorExp)e1).e1; emplaceExp!(UnionExp)(&ue, ex); @@ -1067,14 +1067,14 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) } /* Allow casting from one string type to another */ - if (e1.op == TOK.string_) + if (e1.op == EXP.string_) { if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size()) { goto L1; } } - if (e1.op == TOK.arrayLiteral && typeb == tb) + if (e1.op == EXP.arrayLiteral && typeb == tb) { L1: Expression ex = expType(to, e1); @@ -1157,7 +1157,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) { cantExp(ue); } - else if (tb.ty == Tstruct && e1.op == TOK.int64) + else if (tb.ty == Tstruct && e1.op == EXP.int64) { // Struct = 0; StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); @@ -1169,7 +1169,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) UnionExp zero; emplaceExp!(IntegerExp)(&zero, 0); ue = Cast(loc, v.type, v.type, zero.exp()); - if (ue.exp().op == TOK.cantExpression) + if (ue.exp().op == EXP.cantExpression) return ue; elements.push(ue.exp().copy()); } @@ -1193,18 +1193,18 @@ UnionExp ArrayLength(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; - if (e1.op == TOK.string_) + if (e1.op == EXP.string_) { StringExp es1 = cast(StringExp)e1; emplaceExp!(IntegerExp)(&ue, loc, es1.len, type); } - else if (e1.op == TOK.arrayLiteral) + else if (e1.op == EXP.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) + else if (e1.op == EXP.assocArrayLiteral) { AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1; size_t dim = ale.keys.dim; @@ -1220,7 +1220,7 @@ UnionExp ArrayLength(Type type, Expression e1) return ue; } -/* Also return TOK.cantExpression if this fails +/* Also return EXP.cantExpression if this fails */ UnionExp Index(Type type, Expression e1, Expression e2) { @@ -1228,7 +1228,7 @@ UnionExp Index(Type type, Expression e1, Expression e2) 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) + if (e1.op == EXP.string_ && e2.op == EXP.int64) { StringExp es1 = cast(StringExp)e1; uinteger_t i = e2.toInteger(); @@ -1242,7 +1242,7 @@ UnionExp Index(Type type, Expression e1, Expression e2) emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type); } } - else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOK.int64) + else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64) { TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype(); uinteger_t length = tsa.dim.toInteger(); @@ -1252,7 +1252,7 @@ UnionExp Index(Type type, Expression e1, Expression e2) 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) + else if (e1.op == EXP.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; auto e = ale[cast(size_t)i]; @@ -1266,10 +1266,10 @@ UnionExp Index(Type type, Expression e1, Expression e2) else cantExp(ue); } - else if (e1.type.toBasetype().ty == Tarray && e2.op == TOK.int64) + else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64) { uinteger_t i = e2.toInteger(); - if (e1.op == TOK.arrayLiteral) + if (e1.op == EXP.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; if (i >= ale.elements.dim) @@ -1291,7 +1291,7 @@ UnionExp Index(Type type, Expression e1, Expression e2) else cantExp(ue); } - else if (e1.op == TOK.assocArrayLiteral) + else if (e1.op == EXP.assocArrayLiteral) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1; /* Search the keys backwards, in case there are duplicate keys @@ -1300,10 +1300,10 @@ UnionExp Index(Type type, Expression e1, Expression e2) { i--; Expression ekey = (*ae.keys)[i]; - ue = Equal(TOK.equal, loc, Type.tbool, ekey, e2); + ue = Equal(EXP.equal, loc, Type.tbool, ekey, e2); if (CTFEExp.isCantExp(ue.exp())) return ue; - if (ue.exp().isBool(true)) + if (ue.exp().toBool().hasValue(true)) { Expression e = (*ae.values)[i]; e.type = type; @@ -1322,7 +1322,7 @@ UnionExp Index(Type type, Expression e1, Expression e2) return ue; } -/* Also return TOK.cantExpression if this fails +/* Also return EXP.cantExpression if this fails */ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) { @@ -1347,7 +1347,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) newupr <= upr); } - if (e1.op == TOK.string_ && lwr.op == TOK.int64 && upr.op == TOK.int64) + if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64) { StringExp es1 = cast(StringExp)e1; const uinteger_t ilwr = lwr.toInteger(); @@ -1367,7 +1367,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) es.type = type; } } - else if (e1.op == TOK.arrayLiteral && lwr.op == TOK.int64 && upr.op == TOK.int64 && !hasSideEffect(e1)) + else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1)) { ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; const uinteger_t ilwr = lwr.toInteger(); @@ -1480,14 +1480,14 @@ private Expressions* copyElements(Expression e1, Expression e2 = null) } } - if (e1.op == TOK.arrayLiteral) + if (e1.op == EXP.arrayLiteral) append(cast(ArrayLiteralExp)e1); else elems.push(e1); if (e2) { - if (e2.op == TOK.arrayLiteral) + if (e2.op == EXP.arrayLiteral) append(cast(ArrayLiteralExp)e2); else elems.push(e2); @@ -1496,7 +1496,7 @@ private Expressions* copyElements(Expression e1, Expression e2 = null) return elems; } -/* Also return TOK.cantExpression if this fails +/* Also return EXP.cantExpression if this fails */ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) { @@ -1507,13 +1507,13 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) 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)) + if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral)) { e = e2; t = t1; goto L2; } - else if ((e1.op == TOK.int64 || e1.op == TOK.structLiteral) && e2.op == TOK.null_) + else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_) { e = e1; t = t2; @@ -1547,7 +1547,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.null_ && e2.op == TOK.null_) + else if (e1.op == EXP.null_ && e2.op == EXP.null_) { if (type == e1.type) { @@ -1575,7 +1575,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.string_ && e2.op == TOK.string_) + else if (e1.op == EXP.string_ && e2.op == EXP.string_) { // Concatenate the strings StringExp es1 = cast(StringExp)e1; @@ -1604,7 +1604,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral()) + else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral()) { // [chars] ~ string --> [chars] StringExp es = cast(StringExp)e2; @@ -1621,7 +1621,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral()) + else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral()) { // string ~ [chars] --> [chars] StringExp es = cast(StringExp)e1; @@ -1638,7 +1638,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.string_ && e2.op == TOK.int64) + else if (e1.op == EXP.string_ && e2.op == EXP.int64) { // string ~ char --> string StringExp es1 = cast(StringExp)e1; @@ -1663,7 +1663,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.int64 && e2.op == TOK.string_) + else if (e1.op == EXP.int64 && e2.op == EXP.string_) { // [w|d]?char ~ string --> string // We assume that we only ever prepend one char of the same type @@ -1684,7 +1684,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf())) + else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // Concatenate the arrays auto elems = copyElements(e1, e2); @@ -1701,12 +1701,12 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf())) + else if (e1.op == EXP.arrayLiteral && e2.op == EXP.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())) + else if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { e = e2; L3: @@ -1725,9 +1725,9 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) 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)) + else if ((e1.op == EXP.arrayLiteral || e1.op == EXP.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type)) { - auto elems = (e1.op == TOK.arrayLiteral) + auto elems = (e1.op == EXP.arrayLiteral) ? copyElements(e1) : new Expressions(); elems.push(e2); @@ -1743,7 +1743,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e2.op == TOK.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type)) + else if (e2.op == EXP.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type)) { auto elems = copyElements(e1, e2); @@ -1759,13 +1759,13 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } - else if (e1.op == TOK.null_ && e2.op == TOK.string_) + else if (e1.op == EXP.null_ && e2.op == EXP.string_) { t = e1.type; e = e2; goto L1; } - else if (e1.op == TOK.string_ && e2.op == TOK.null_) + else if (e1.op == EXP.string_ && e2.op == EXP.null_) { e = e1; t = e2.type; @@ -1801,13 +1801,13 @@ UnionExp Ptr(Type type, Expression e1) { //printf("Ptr(e1 = %s)\n", e1.toChars()); UnionExp ue = void; - if (e1.op == TOK.add) + if (e1.op == EXP.add) { AddExp ae = cast(AddExp)e1; - if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64) + if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64) { AddrExp ade = cast(AddrExp)ae.e1; - if (ade.e1.op == TOK.structLiteral) + if (ade.e1.op == EXP.structLiteral) { StructLiteralExp se = cast(StructLiteralExp)ade.e1; uint offset = cast(uint)ae.e2.toInteger(); diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 7d8ab67..dfc45e0 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -212,7 +212,7 @@ final class CParser(AST) : Parser!AST case TOK.sizeof_: Lexp: auto exp = cparseExpression(); - if (token.value == TOK.identifier && exp.op == TOK.identifier) + if (token.value == TOK.identifier && exp.op == EXP.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(); @@ -781,11 +781,11 @@ final class CParser(AST) : Parser!AST break; case TOK.plusPlus: - e = new AST.PostExp(TOK.plusPlus, loc, e); + e = new AST.PostExp(EXP.plusPlus, loc, e); break; case TOK.minusMinus: - e = new AST.PostExp(TOK.minusMinus, loc, e); + e = new AST.PostExp(EXP.minusMinus, loc, e); break; case TOK.leftParenthesis: @@ -841,14 +841,14 @@ final class CParser(AST) : Parser!AST // 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); + e = new AST.PreExp(EXP.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); + e = new AST.PreExp(EXP.preMinusMinus, loc, e); break; case TOK.and: @@ -1122,14 +1122,15 @@ final class CParser(AST) : Parser!AST const loc = token.loc; auto e = cparseShiftExp(); - TOK op = token.value; - switch (op) + EXP op = EXP.reserved; + switch (token.value) { - case TOK.lessThan: - case TOK.lessOrEqual: - case TOK.greaterThan: - case TOK.greaterOrEqual: + case TOK.lessThan: op = EXP.lessThan; goto Lcmp; + case TOK.lessOrEqual: op = EXP.lessOrEqual; goto Lcmp; + case TOK.greaterThan: op = EXP.greaterThan; goto Lcmp; + case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp; + Lcmp: nextToken(); auto e2 = cparseShiftExp(); e = new AST.CmpExp(op, loc, e, e2); @@ -1153,12 +1154,13 @@ final class CParser(AST) : Parser!AST const loc = token.loc; auto e = cparseRelationalExp(); - const TOK op = token.value; - switch (op) + EXP op = EXP.reserved; + switch (token.value) { - case TOK.equal: - case TOK.notEqual: + case TOK.equal: op = EXP.equal; goto Lequal; + case TOK.notEqual: op = EXP.notEqual; goto Lequal; + Lequal: nextToken(); auto e2 = cparseRelationalExp(); e = new AST.EqualExp(op, loc, e, e2); @@ -1245,7 +1247,7 @@ final class CParser(AST) : Parser!AST { nextToken(); auto e2 = cparseOrExp(); - e = new AST.LogicalExp(loc, TOK.andAnd, e, e2); + e = new AST.LogicalExp(loc, EXP.andAnd, e, e2); } return e; } @@ -1265,7 +1267,7 @@ final class CParser(AST) : Parser!AST { nextToken(); auto e2 = cparseAndAndExp(); - e = new AST.LogicalExp(loc, TOK.orOr, e, e2); + e = new AST.LogicalExp(loc, EXP.orOr, e, e2); } return e; } @@ -1693,7 +1695,11 @@ final class CParser(AST) : Parser!AST switch (token.value) { case TOK.identifier: - error("missing comma"); + if (s) + { + error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars()); + goto Lend; + } goto default; case TOK.semicolon: @@ -1707,7 +1713,8 @@ final class CParser(AST) : Parser!AST break; default: - error("`=`, `;` or `,` expected"); + error("`=`, `;` or `,` expected to end declaration instead of `%s`", token.toChars()); + Lend: while (token.value != TOK.semicolon && token.value != TOK.endOfFile) nextToken(); nextToken(); diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index df742c0..4ad79da 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -490,7 +490,7 @@ private final class CppMangleVisitor : Visitor mangle_function(d.isFuncDeclaration()); buf.writestring("EE"); } - else if (e && e.op == TOK.variable && (cast(VarExp)e).var.isVarDeclaration()) + else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration()) { VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); buf.writeByte('L'); diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 7f76d75..9cd09ba 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -46,7 +46,7 @@ extern (C++) final class ClassReferenceExp : Expression extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) { - super(loc, TOK.classReference, __traits(classInstanceSize, ClassReferenceExp)); + super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp)); assert(lit && lit.sd && lit.sd.isClassDeclaration()); this.value = lit; this.type = type; @@ -131,7 +131,7 @@ extern (C++) final class ThrownExceptionExp : Expression extern (D) this(const ref Loc loc, ClassReferenceExp victim) { - super(loc, TOK.thrownException, __traits(classInstanceSize, ThrownExceptionExp)); + super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp)); this.thrown = victim; this.type = victim.type; } @@ -167,7 +167,7 @@ extern (C++) final class ThrownExceptionExp : Expression */ extern (C++) final class CTFEExp : Expression { - extern (D) this(TOK tok) + extern (D) this(EXP tok) { super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp)); type = Type.tvoid; @@ -177,17 +177,17 @@ extern (C++) final class CTFEExp : Expression { switch (op) { - case TOK.cantExpression: + case EXP.cantExpression: return "<cant>"; - case TOK.voidExpression: + case EXP.voidExpression: return "cast(void)0"; - case TOK.showCtfeContext: + case EXP.showCtfeContext: return "<error>"; - case TOK.break_: + case EXP.break_: return "<break>"; - case TOK.continue_: + case EXP.continue_: return "<continue>"; - case TOK.goto_: + case EXP.goto_: return "<goto>"; default: assert(0); @@ -206,19 +206,19 @@ extern (C++) final class CTFEExp : Expression extern (D) static bool isCantExp(const Expression e) { - return e && e.op == TOK.cantExpression; + return e && e.op == EXP.cantExpression; } extern (D) static bool isGotoExp(const Expression e) { - return e && e.op == TOK.goto_; + return e && e.op == EXP.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); + return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext); } /************** Aggregate literals (AA/string/array/struct) ******************/ @@ -231,29 +231,29 @@ bool needToCopyLiteral(const Expression expr) { switch (e.op) { - case TOK.arrayLiteral: + case EXP.arrayLiteral: return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code; - case TOK.assocArrayLiteral: + case EXP.assocArrayLiteral: return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code; - case TOK.structLiteral: + case EXP.structLiteral: return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code; - case TOK.string_: - case TOK.this_: - case TOK.variable: + case EXP.string_: + case EXP.this_: + case EXP.variable: return false; - case TOK.assign: + case EXP.assign: return false; - case TOK.index: - case TOK.dotVariable: - case TOK.slice: - case TOK.cast_: + case EXP.index: + case EXP.dotVariable: + case EXP.slice: + case EXP.cast_: e = (cast(UnaExp)e).e1; continue; - case TOK.concatenate: + case EXP.concatenate: return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2); - case TOK.concatenateAssign: - case TOK.concatenateElemAssign: - case TOK.concatenateDcharAssign: + case EXP.concatenateAssign: + case EXP.concatenateElemAssign: + case EXP.concatenateDcharAssign: e = (cast(BinExp)e).e2; continue; default: @@ -358,7 +358,7 @@ UnionExp copyLiteral(Expression e) 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_) + if (e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.symbolOffset || e.op == EXP.null_ || e.op == EXP.variable || e.op == EXP.dotVariable || e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.char_ || e.op == EXP.complex80 || e.op == EXP.void_ || e.op == EXP.vector || e.op == EXP.typeid_) { // Simple value types // Keep e1 for DelegateExp and DotVarExp @@ -372,7 +372,7 @@ UnionExp copyLiteral(Expression e) if (se.type.toBasetype().ty == Tsarray) { // same with resolveSlice() - if (se.e1.op == TOK.null_) + if (se.e1.op == EXP.null_) { emplaceExp!(NullExp)(&ue, se.loc, se.type); return ue; @@ -415,7 +415,7 @@ UnionExp copyLiteral(Expression e) emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type); return ue; } - if (e.op == TOK.error) + if (e.op == EXP.error) { emplaceExp!(UnionExp)(&ue, e); return ue; @@ -468,11 +468,11 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit) { emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2); } - else if (lit.op == TOK.arrayLiteral) + else if (lit.op == EXP.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_) + else if (lit.op == EXP.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()); @@ -490,7 +490,7 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit) { // Can't type paint from struct to struct*; this needs another // level of indirection - if (lit.op == TOK.structLiteral && isPointer(type)) + if (lit.op == EXP.structLiteral && isPointer(type)) lit.error("CTFE internal error: painting `%s`", type.toChars()); ue = copyLiteral(lit); } @@ -511,7 +511,7 @@ Expression resolveSlice(Expression e, UnionExp* pue = null) SliceExp se = e.isSliceExp(); if (!se) return e; - if (se.e1.op == TOK.null_) + if (se.e1.op == EXP.null_) return se.e1; if (pue) { @@ -531,13 +531,13 @@ uinteger_t resolveArrayLength(const Expression e) { switch (e.op) { - case TOK.vector: + case EXP.vector: return e.isVectorExp().dim; - case TOK.null_: + case EXP.null_: return 0; - case TOK.slice: + case EXP.slice: { auto se = cast(SliceExp)e; const ilo = se.lwr.toInteger(); @@ -545,16 +545,16 @@ uinteger_t resolveArrayLength(const Expression e) return iup - ilo; } - case TOK.string_: + case EXP.string_: return e.isStringExp().len; - case TOK.arrayLiteral: + case EXP.arrayLiteral: { const ale = e.isArrayLiteralExp(); return ale.elements ? ale.elements.dim : 0; } - case TOK.assocArrayLiteral: + case EXP.assocArrayLiteral: { return e.isAssocArrayLiteralExp().keys.dim; } @@ -667,7 +667,7 @@ bool isPointer(Type t) // 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_); + return e.toBool().hasValue(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != EXP.null_); } /* Is it safe to convert from srcPointee* to destPointee* ? @@ -725,12 +725,12 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) const ex = dve.e1; const v = dve.var.isVarDeclaration(); assert(v); - StructLiteralExp se = (ex.op == TOK.classReference) + StructLiteralExp se = (ex.op == EXP.classReference) ? (cast(ClassReferenceExp)ex).value : cast(StructLiteralExp)ex; // We can't use getField, because it makes a copy - const i = (ex.op == TOK.classReference) + const i = (ex.op == EXP.classReference) ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset) : se.getFieldIndex(e.type, v.offset); e = (*se.elements)[i]; @@ -738,7 +738,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) 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) + if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64) { *ofs = ie.e2.toInteger(); return ie.e1; @@ -747,7 +747,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) 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) + (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64) { *ofs = se.lwr.toInteger(); return se.e1; @@ -773,17 +773,17 @@ bool pointToSameMemoryBlock(Expression agg1, Expression 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()) + if (agg1.op == EXP.int64 && agg2.op == EXP.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) + if (agg1.op == EXP.variable && agg2.op == EXP.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) + if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) { return true; } @@ -803,14 +803,14 @@ UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expressi const sz = pointee.size(); emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); } - else if (agg1.op == TOK.string_ && agg2.op == TOK.string_ && + else if (agg1.op == EXP.string_ && agg2.op == EXP.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 && + else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) { emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type); @@ -818,28 +818,28 @@ UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expressi 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); + emplaceExp!(CTFEExp)(&ue, EXP.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) +// and op is EXP.add or EXP.min +UnionExp pointerArithmetic(const ref Loc loc, EXP 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); + emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); return ue; } - if (eptr.op == TOK.address) + if (eptr.op == EXP.address) eptr = (cast(AddrExp)eptr).e1; dinteger_t ofs1; Expression agg1 = getAggregateFromPointer(eptr, &ofs1); - if (agg1.op == TOK.symbolOffset) + if (agg1.op == EXP.symbolOffset) { if ((cast(SymOffExp)agg1).var.type.ty != Tsarray) { @@ -847,7 +847,7 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr goto Lcant; } } - else if (agg1.op != TOK.string_ && agg1.op != TOK.arrayLiteral) + else if (agg1.op != EXP.string_ && agg1.op != EXP.arrayLiteral) { error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); goto Lcant; @@ -857,7 +857,7 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr dinteger_t sz = pointee.size(); sinteger_t indx; dinteger_t len; - if (agg1.op == TOK.symbolOffset) + if (agg1.op == EXP.symbolOffset) { indx = ofs1 / sz; len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger(); @@ -869,9 +869,9 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr indx = ofs1; len = dollar.toInteger(); } - if (op == TOK.add || op == TOK.addAssign || op == TOK.plusPlus) + if (op == EXP.add || op == EXP.addAssign || op == EXP.plusPlus) indx += ofs2 / sz; - else if (op == TOK.min || op == TOK.minAssign || op == TOK.minusMinus) + else if (op == EXP.min || op == EXP.minAssign || op == EXP.minusMinus) indx -= ofs2 / sz; else { @@ -883,14 +883,14 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len); goto Lcant; } - if (agg1.op == TOK.symbolOffset) + if (agg1.op == EXP.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_) + if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_) { error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars()); goto Lcant; @@ -918,31 +918,31 @@ UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr // 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) +int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2) { if (pointToSameMemoryBlock(agg1, agg2)) { int n; switch (op) { - case TOK.lessThan: + case EXP.lessThan: n = (ofs1 < ofs2); break; - case TOK.lessOrEqual: + case EXP.lessOrEqual: n = (ofs1 <= ofs2); break; - case TOK.greaterThan: + case EXP.greaterThan: n = (ofs1 > ofs2); break; - case TOK.greaterOrEqual: + case EXP.greaterOrEqual: n = (ofs1 >= ofs2); break; - case TOK.identity: - case TOK.equal: + case EXP.identity: + case EXP.equal: n = (ofs1 == ofs2); break; - case TOK.notIdentity: - case TOK.notEqual: + case EXP.notIdentity: + case EXP.notEqual: n = (ofs1 != ofs2); break; default: @@ -950,29 +950,29 @@ int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, d } return n; } - const null1 = (agg1.op == TOK.null_); - const null2 = (agg2.op == TOK.null_); + const null1 = (agg1.op == EXP.null_); + const null2 = (agg2.op == EXP.null_); int cmp; if (null1 || null2) { switch (op) { - case TOK.lessThan: + case EXP.lessThan: cmp = null1 && !null2; break; - case TOK.greaterThan: + case EXP.greaterThan: cmp = !null1 && null2; break; - case TOK.lessOrEqual: + case EXP.lessOrEqual: cmp = null1; break; - case TOK.greaterOrEqual: + case EXP.greaterOrEqual: cmp = null2; break; - case TOK.identity: - case TOK.equal: - case TOK.notIdentity: // 'cmp' gets inverted below - case TOK.notEqual: + case EXP.identity: + case EXP.equal: + case EXP.notIdentity: // 'cmp' gets inverted below + case EXP.notEqual: cmp = (null1 == null2); break; default: @@ -983,17 +983,17 @@ int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, d { switch (op) { - case TOK.identity: - case TOK.equal: - case TOK.notIdentity: // 'cmp' gets inverted below - case TOK.notEqual: + case EXP.identity: + case EXP.equal: + case EXP.notIdentity: // 'cmp' gets inverted below + case EXP.notEqual: cmp = 0; break; default: return -1; // memory blocks are different } } - if (op == TOK.notIdentity || op == TOK.notEqual) + if (op == EXP.notIdentity || op == EXP.notEqual) cmp ^= 1; return cmp; } @@ -1019,35 +1019,35 @@ Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to) /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity bool isCtfeComparable(Expression e) { - if (e.op == TOK.slice) + if (e.op == EXP.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) + if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference) { return true; } // https://issues.dlang.org/show_bug.cgi?id=14123 // TypeInfo object is comparable in CTFE - if (e.op == TOK.typeid_) + if (e.op == EXP.typeid_) return true; return false; } return true; } -/// Map TOK comparison ops -private bool numCmp(N)(TOK op, N n1, N n2) +/// Map EXP comparison ops +private bool numCmp(N)(EXP op, N n1, N n2) { switch (op) { - case TOK.lessThan: + case EXP.lessThan: return n1 < n2; - case TOK.lessOrEqual: + case EXP.lessOrEqual: return n1 <= n2; - case TOK.greaterThan: + case EXP.greaterThan: return n1 > n2; - case TOK.greaterOrEqual: + case EXP.greaterOrEqual: return n1 >= n2; default: @@ -1056,35 +1056,35 @@ private bool numCmp(N)(TOK op, N n1, N n2) } /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool specificCmp(TOK op, int rawCmp) +bool specificCmp(EXP 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) +bool intUnsignedCmp(EXP 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) +bool intSignedCmp(EXP 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) +bool realCmp(EXP 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: + case EXP.lessThan: + case EXP.lessOrEqual: + case EXP.greaterThan: + case EXP.greaterOrEqual: return false; default: @@ -1128,7 +1128,7 @@ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte auto se2 = x2.isStringExp(); auto ae2 = x2.isArrayLiteralExp(); - // Now both must be either TOK.arrayLiteral or TOK.string_ + // Now both must be either EXP.arrayLiteral or EXP.string_ if (se1 && se2) return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); if (se1 && ae2) @@ -1171,13 +1171,13 @@ private FuncDeclaration funcptrOf(Expression e) return de.func; if (auto fe = e.isFuncExp()) return fe.fd; - assert(e.op == TOK.null_); + assert(e.op == EXP.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_; + return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_; } /***** @@ -1192,14 +1192,14 @@ private bool isArray(const Expression e) */ 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 == EXP.classReference || e2.op == EXP.classReference) { - if (e1.op == TOK.classReference && e2.op == TOK.classReference && + if (e1.op == EXP.classReference && e2.op == EXP.classReference && (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value) return 0; return 1; } - if (e1.op == TOK.typeid_ && e2.op == TOK.typeid_) + if (e1.op == EXP.typeid_ && e2.op == EXP.typeid_) { // printf("e1: %s\n", e1.toChars()); // printf("e2: %s\n", e2.toChars()); @@ -1210,7 +1210,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide return t1 != t2; } // null == null, regardless of type - if (e1.op == TOK.null_ && e2.op == TOK.null_) + if (e1.op == EXP.null_ && e2.op == EXP.null_) return 0; if (e1.type.ty == Tpointer && e2.type.ty == Tpointer) { @@ -1218,7 +1218,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide 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 ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) { if (ofs1 == ofs2) return 0; @@ -1232,17 +1232,17 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide 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_) + if (e1.op == EXP.function_ && e2.op == EXP.function_) return 0; - assert(e1.op == TOK.delegate_ && e2.op == TOK.delegate_); + assert(e1.op == EXP.delegate_ && e2.op == EXP.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)) + // If they are EXP.variable, it means they are FuncDeclarations + if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) { return 0; } @@ -1293,7 +1293,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } return c1 != c2; } - if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral) + if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral) { StructLiteralExp es1 = cast(StructLiteralExp)e1; StructLiteralExp es2 = cast(StructLiteralExp)e2; @@ -1314,7 +1314,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide 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 + if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp continue; if (ee1 == ee2) @@ -1328,7 +1328,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide return 0; // All elements are equal } } - if (e1.op == TOK.assocArrayLiteral && e2.op == TOK.assocArrayLiteral) + if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral) { AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1; AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2; @@ -1367,27 +1367,27 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1 -bool ctfeEqual(const ref Loc loc, TOK op, Expression e1, Expression e2) +bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2) { - return !ctfeRawCmp(loc, e1, e2) ^ (op == TOK.notEqual); + return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual); } /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1 -bool ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2) +bool ctfeIdentity(const ref Loc loc, EXP 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()); + //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr, + // EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars()); bool cmp; - if (e1.op == TOK.null_) + if (e1.op == EXP.null_) { - cmp = (e2.op == TOK.null_); + cmp = (e2.op == EXP.null_); } - else if (e2.op == TOK.null_) + else if (e2.op == EXP.null_) { cmp = false; } - else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset) + else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset) { SymOffExp es1 = cast(SymOffExp)e1; SymOffExp es2 = cast(SymOffExp)e2; @@ -1407,13 +1407,13 @@ bool ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2) { cmp = !ctfeRawCmp(loc, e1, e2, true); } - if (op == TOK.notIdentity || op == TOK.notEqual) + if (op == EXP.notIdentity || op == EXP.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) +bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2) { Type t1 = e1.type.toBasetype(); Type t2 = e2.type.toBasetype(); @@ -1435,7 +1435,7 @@ 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()) + if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral()) { // [chars] ~ string => string (only valid for CTFE) StringExp es1 = cast(StringExp)e2; @@ -1448,9 +1448,9 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) foreach (size_t i; 0 .. es2.elements.dim) { Expression es2e = (*es2.elements)[i]; - if (es2e.op != TOK.int64) + if (es2e.op != EXP.int64) { - emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); + emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); return ue; } dinteger_t v = es2e.toInteger(); @@ -1464,7 +1464,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) es.type = type; return ue; } - if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral()) + if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral()) { // string ~ [chars] => string (only valid for CTFE) // Concatenate the strings @@ -1478,9 +1478,9 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) foreach (size_t i; 0 .. es2.elements.dim) { Expression es2e = (*es2.elements)[i]; - if (es2e.op != TOK.int64) + if (es2e.op != EXP.int64) { - emplaceExp!(CTFEExp)(&ue, TOK.cantExpression); + emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); return ue; } const v = es2e.toInteger(); @@ -1495,7 +1495,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) es.type = type; return ue; } - if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf())) + if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; @@ -1505,13 +1505,13 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) 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())) + if (e1.op == EXP.arrayLiteral && e2.op == EXP.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())) + if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // null ~ [ e2 ] ----> [ e2 ].dup ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy()); @@ -1532,7 +1532,7 @@ Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2 { --i; Expression ekey = (*ae.keys)[i]; - const int eq = ctfeEqual(loc, TOK.equal, ekey, e2); + const int eq = ctfeEqual(loc, EXP.equal, ekey, e2); if (eq) { return (*ae.values)[i]; @@ -1581,10 +1581,10 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres return paintTypeOntoLiteral(pue, to, e); } - if (e.op == TOK.null_) + if (e.op == EXP.null_) return paint(); - if (e.op == TOK.classReference) + if (e.op == EXP.classReference) { // Disallow reinterpreting class casts. Do this by ensuring that // the original class can implicitly convert to the target class @@ -1603,7 +1603,7 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres return paint(); // Allow casting away const for struct literals - if (e.op == TOK.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0)) + if (e.op == EXP.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0)) return paint(); Expression r; @@ -1647,14 +1647,14 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres */ void assignInPlace(Expression dest, Expression src) { - if (!(dest.op == TOK.structLiteral || dest.op == TOK.arrayLiteral || dest.op == TOK.string_)) + if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_)) { printf("invalid op %d %d\n", src.op, dest.op); assert(0); } Expressions* oldelems; Expressions* newelems; - if (dest.op == TOK.structLiteral) + if (dest.op == EXP.structLiteral) { assert(dest.op == src.op); oldelems = (cast(StructLiteralExp)dest).elements; @@ -1666,22 +1666,22 @@ void assignInPlace(Expression dest, Expression src) foreach (_; 0 .. newelems.dim - oldelems.dim) oldelems.push(null); } - else if (dest.op == TOK.arrayLiteral && src.op == TOK.arrayLiteral) + else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral) { oldelems = (cast(ArrayLiteralExp)dest).elements; newelems = (cast(ArrayLiteralExp)src).elements; } - else if (dest.op == TOK.string_ && src.op == TOK.string_) + else if (dest.op == EXP.string_ && src.op == EXP.string_) { sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0); return; } - else if (dest.op == TOK.arrayLiteral && src.op == TOK.string_) + else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_) { sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0); return; } - else if (src.op == TOK.arrayLiteral && dest.op == TOK.string_) + else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_) { sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0); return; @@ -1696,12 +1696,12 @@ void assignInPlace(Expression dest, Expression src) { Expression e = (*newelems)[i]; Expression o = (*oldelems)[i]; - if (e.op == TOK.structLiteral) + if (e.op == EXP.structLiteral) { assert(o.op == e.op); assignInPlace(o, e); } - else if (e.type.ty == Tsarray && e.op != TOK.void_ && o.type.ty == Tsarray) + else if (e.type.ty == Tsarray && e.op != EXP.void_ && o.type.ty == Tsarray) { assignInPlace(o, e); } @@ -1724,7 +1724,7 @@ Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, { j--; Expression ekey = (*aae.keys)[j]; - int eq = ctfeEqual(loc, TOK.equal, ekey, index); + int eq = ctfeEqual(loc, EXP.equal, ekey, index); if (eq) { (*valuesx)[j] = newval; @@ -1752,13 +1752,13 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres auto elements = new Expressions(newlen); // Resolve slices size_t indxlo = 0; - if (oldval.op == TOK.slice) + if (oldval.op == EXP.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_) + if (oldval.op == EXP.string_) { StringExp oldse = cast(StringExp)oldval; void* s = mem.xcalloc(newlen + 1, oldse.sz); @@ -1793,7 +1793,7 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres { if (oldlen != 0) { - assert(oldval.op == TOK.arrayLiteral); + assert(oldval.op == EXP.arrayLiteral); ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval; foreach (size_t i; 0 .. copylen) (*elements)[i] = (*ae.elements)[indxlo + i]; @@ -1825,13 +1825,13 @@ bool isCtfeValueValid(Expression newval) Type tb = newval.type.toBasetype(); switch (newval.op) { - case TOK.int64: - case TOK.float64: - case TOK.char_: - case TOK.complex80: + case EXP.int64: + case EXP.float64: + case EXP.char_: + case EXP.complex80: return tb.isscalar(); - case TOK.null_: + case EXP.null_: return tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || @@ -1839,75 +1839,75 @@ bool isCtfeValueValid(Expression newval) tb.ty == Tclass || tb.ty == Tdelegate; - case TOK.string_: + case EXP.string_: return true; // CTFE would directly use the StringExp in AST. - case TOK.arrayLiteral: + case EXP.arrayLiteral: return true; //((ArrayLiteralExp *)newval)->ownedByCtfe; - case TOK.assocArrayLiteral: + case EXP.assocArrayLiteral: return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe; - case TOK.structLiteral: + case EXP.structLiteral: return true; //((StructLiteralExp *)newval)->ownedByCtfe; - case TOK.classReference: + case EXP.classReference: return true; - case TOK.type: + case EXP.type: return true; - case TOK.vector: + case EXP.vector: return true; // vector literal - case TOK.function_: + case EXP.function_: return true; // function literal or delegate literal - case TOK.delegate_: + case EXP.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); + return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func); } - case TOK.symbolOffset: + case EXP.symbolOffset: { // function pointer, or pointer to static variable Declaration d = (cast(SymOffExp)newval).var; return d.isFuncDeclaration() || d.isDataseg(); } - case TOK.typeid_: + case EXP.typeid_: { // always valid return true; } - case TOK.address: + case EXP.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 + (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) || + e1.op == EXP.variable || + e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) || + e1.op == EXP.index && isCtfeReferenceValid(e1) || + e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray ); } - case TOK.slice: + case EXP.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); + assert(se.lwr && se.lwr.op == EXP.int64); + assert(se.upr && se.upr.op == EXP.int64); + return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral); } - case TOK.void_: + case EXP.void_: return true; // uninitialized value default: @@ -1920,10 +1920,10 @@ bool isCtfeReferenceValid(Expression newval) { switch (newval.op) { - case TOK.this_: + case EXP.this_: return true; - case TOK.variable: + case EXP.variable: { const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration(); assert(v); @@ -1931,16 +1931,16 @@ bool isCtfeReferenceValid(Expression newval) return true; } - case TOK.index: + case EXP.index: { const Expression eagg = (cast(IndexExp)newval).e1; - return eagg.op == TOK.string_ || eagg.op == TOK.arrayLiteral || eagg.op == TOK.assocArrayLiteral; + return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral; } - case TOK.dotVariable: + case EXP.dotVariable: { Expression eagg = (cast(DotVarExp)newval).e1; - return (eagg.op == TOK.structLiteral || eagg.op == TOK.classReference) && isCtfeValueValid(eagg); + return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg); } default: @@ -1959,44 +1959,44 @@ void showCtfeExpr(Expression e, int level = 0) // We need the struct definition to detect block assignment StructDeclaration sd = null; ClassDeclaration cd = null; - if (e.op == TOK.structLiteral) + if (e.op == EXP.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) + else if (e.op == EXP.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) + else if (e.op == EXP.arrayLiteral) { elements = (cast(ArrayLiteralExp)e).elements; printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e); } - else if (e.op == TOK.assocArrayLiteral) + else if (e.op == EXP.assocArrayLiteral) { printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e); } - else if (e.op == TOK.string_) + else if (e.op == EXP.string_) { printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr); } - else if (e.op == TOK.slice) + else if (e.op == EXP.slice) { printf("SLICE %p: %s\n", e, e.toChars()); showCtfeExpr((cast(SliceExp)e).e1, level + 1); } - else if (e.op == TOK.variable) + else if (e.op == EXP.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) + else if (e.op == EXP.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()); @@ -2069,7 +2069,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var) 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 mustCopy = (elem.op == EXP.arrayLiteral || elem.op == EXP.structLiteral); const d = cast(size_t)tsa.dim.toInteger(); auto elements = new Expressions(d); foreach (i; 0 .. d) diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 87c3ada..2e5a79d 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -29,6 +29,7 @@ import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; +import dmd.hdrgen; import dmd.impcnvtab; import dmd.id; import dmd.importc; @@ -994,7 +995,7 @@ MATCH implicitConvTo(Expression e, Type t) Type typeb = e.type.toBasetype(); // Look for pointers to functions where the functions are overloaded. - if (e.e1.op == TOK.overloadSet && + if (e.e1.op == EXP.overloadSet && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { OverExp eo = e.e1.isOverExp(); @@ -1019,7 +1020,7 @@ MATCH implicitConvTo(Expression e, Type t) } } - if (e.e1.op == TOK.variable && + if (e.e1.op == EXP.variable && typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && tb.ty == Tpointer && tb.nextOf().ty == Tfunction) { @@ -1443,7 +1444,7 @@ MATCH implicitConvTo(Expression e, Type t) } // Enhancement 10724 - if (tb.ty == Tpointer && e.e1.op == TOK.string_) + if (tb.ty == Tpointer && e.e1.op == EXP.string_) e.e1.accept(this); } @@ -1564,7 +1565,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) result = e; return; } - if (e.op == TOK.variable) + if (e.op == EXP.variable) { VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); if (v && v.storage_class & STC.manifest) @@ -1728,6 +1729,11 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } const fsize = t1b.nextOf().size(); const tsize = tob.nextOf().size(); + if (fsize == SIZE_INVALID || tsize == SIZE_INVALID) + { + result = ErrorExp.get(); + return; + } if (fsize != tsize) { const dim = t1b.isTypeSArray().dim.toInteger(); @@ -1846,7 +1852,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) override void visit(StructLiteralExp e) { visit(cast(Expression)e); - if (result.op == TOK.structLiteral) + if (result.op == EXP.structLiteral) (cast(StructLiteralExp)result).stype = t; // commit type } @@ -1868,6 +1874,13 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } StringExp se = e; + + void lcast() + { + result = new CastExp(e.loc, se, t); + result.type = t; // so semantic() won't be run on e + } + if (!e.committed) { se = cast(StringExp)e.copy(); @@ -1942,7 +1955,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) se = cast(StringExp)e.copy(); copied = 1; } - goto Lcast; + return lcast(); } if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer) { @@ -1951,10 +1964,16 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) se = cast(StringExp)e.copy(); copied = 1; } - goto Lcast; + return lcast(); } - if (typeb.nextOf().size() == tb.nextOf().size()) + const nextSz = typeb.nextOf().size(); + if (nextSz == SIZE_INVALID) + { + result = ErrorExp.get(); + return; + } + if (nextSz == tb.nextOf().size()) { if (!copied) { @@ -2135,7 +2154,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } // Look for pointers to functions where the functions are overloaded. - if (e.e1.op == TOK.overloadSet && + if (e.e1.op == EXP.overloadSet && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { OverExp eo = cast(OverExp)e.e1; @@ -2169,7 +2188,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } } - if (e.e1.op == TOK.variable && + if (e.e1.op == EXP.variable && typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && tb.ty == Tpointer && tb.nextOf().ty == Tfunction) { @@ -2621,7 +2640,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (e.e1.implicitConvTo(t1b) > MATCH.nomatch) { Expression e1x = e.e1.implicitCastTo(sc, t1b); - assert(e1x.op != TOK.error); + assert(e1x.op != EXP.error); e = cast(SliceExp)e.copy(); e.e1 = e1x; e.type = t; @@ -2732,10 +2751,10 @@ Expression inferType(Expression e, Type t, int flag = 0) 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); + case EXP.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e); + case EXP.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e); + case EXP.function_: return visitFun(cast(FuncExp) e); + case EXP.question: return visitTer(cast(CondExp) e); default: } return e; @@ -2789,7 +2808,7 @@ Expression scaleFactor(BinExp be, Scope* sc) if (sc.func && !sc.intypeof) { eoff = eoff.optimize(WANTvalue); - if (eoff.op == TOK.int64 && eoff.toInteger() == 0) + if (eoff.op == EXP.int64 && eoff.toInteger() == 0) { } else if (sc.func.setUnsafe()) @@ -2811,7 +2830,7 @@ Expression scaleFactor(BinExp be, Scope* sc) */ private bool isVoidArrayLiteral(Expression e, Type other) { - while (e.op == TOK.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1)) + while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1)) { auto ale = cast(ArrayLiteralExp)e; e = ale[0]; @@ -2823,7 +2842,7 @@ private bool isVoidArrayLiteral(Expression e, Type other) 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); + return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0); } /** @@ -2833,7 +2852,7 @@ private bool isVoidArrayLiteral(Expression e, Type other) * * Params: * sc = Current scope - * op = Operator such as `e1 op e2`. In practice, either TOK.question + * op = Operator such as `e1 op e2`. In practice, either EXP.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 @@ -2841,7 +2860,7 @@ private bool isVoidArrayLiteral(Expression e, Type other) * 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) +Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2) { //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars()); @@ -2906,9 +2925,9 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2) } } - if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic())) + if (op != EXP.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic())) { - if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar()) + if (op == EXP.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar()) { e1 = e1.castTo(sc, Type.tdchar); e2 = e2.castTo(sc, Type.tdchar); @@ -3077,7 +3096,7 @@ Lagain: 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))) + if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.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[] @@ -3089,7 +3108,7 @@ Lagain: 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))) + if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.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[] @@ -3107,9 +3126,9 @@ Lagain: // 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) + if (t1.ty == Tsarray && e2.op == EXP.arrayLiteral && op != EXP.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)) + if (m == MATCH.constant && (op == EXP.addAssign || op == EXP.minAssign || op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || op == EXP.powAssign || op == EXP.andAssign || op == EXP.orAssign || op == EXP.xorAssign)) { // Don't make the lvalue const return Lret(t2); @@ -3121,7 +3140,7 @@ Lagain: { // 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) + if (t2.ty == Tsarray && e1.op == EXP.arrayLiteral && op != EXP.concatenate) return convert(e1, t2); return convert(e2, t1); } @@ -3134,9 +3153,9 @@ Lagain: Type t1n = t1.nextOf(); Type t2n = t2.nextOf(); ubyte mod; - if (e1.op == TOK.null_ && e2.op != TOK.null_) + if (e1.op == EXP.null_ && e2.op != EXP.null_) mod = t2n.mod; - else if (e1.op != TOK.null_ && e2.op == TOK.null_) + else if (e1.op != EXP.null_ && e2.op == EXP.null_) mod = t1n.mod; else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared()) return null; @@ -3161,9 +3180,9 @@ Lagain: if (t1.mod != t2.mod) { ubyte mod; - if (e1.op == TOK.null_ && e2.op != TOK.null_) + if (e1.op == EXP.null_ && e2.op != EXP.null_) mod = t2.mod; - else if (e1.op != TOK.null_ && e2.op == TOK.null_) + else if (e1.op != EXP.null_ && e2.op == EXP.null_) mod = t1.mod; else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared()) return null; @@ -3352,9 +3371,9 @@ Lagain: goto Lagain; } - if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2)) + if ((e1.op == EXP.string_ || e1.op == EXP.null_) && e1.implicitConvTo(t2)) return convert(e1, t2); - if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1)) + if ((e2.op == EXP.string_ || e2.op == EXP.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()); @@ -3427,6 +3446,69 @@ LmodCompare: if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray)) return convert(e1, t2); + /// Covers array operations for user-defined types + Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc) + { + // scalar op scalar - we shouldn't be here + if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray) + return null; + + // only supporting slices and array literals + if (!e1.isSliceExp() && !e1.isArrayLiteralExp() && !e2.isSliceExp() && !e2.isArrayLiteralExp()) + return null; + + // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal, + // replace it with the first element of the array + Expression lhs = e1; + Expression rhs = e2; + + // T[x .. y] op ? + if (e1.isSliceExp()) + lhs = new IndexExp(Loc.initial, (cast(UnaExp)e1).e1, IntegerExp.literal!0); + + // [t1, t2, .. t3] op ? + if (e1.isArrayLiteralExp()) + lhs = (cast(ArrayLiteralExp)e1).opIndex(0); + + // ? op U[z .. t] + if (e2.isSliceExp()) + rhs = new IndexExp(Loc.initial, (cast(UnaExp)e2).e1, IntegerExp.literal!0); + + // ? op [u1, u2, .. u3] + if (e2.isArrayLiteralExp()) + rhs = (cast(ArrayLiteralExp)e2).opIndex(0); + + // create a new binary expression with the new lhs and rhs (at this stage, at least + // one of lhs/rhs has been replaced with the 0'th element of the array it was before) + Expression exp; + switch (op) + { + case EXP.add: + exp = new AddExp(Loc.initial, lhs, rhs); break; + case EXP.min: + exp = new MinExp(Loc.initial, lhs, rhs); break; + case EXP.mul: + exp = new MulExp(Loc.initial, lhs, rhs); break; + case EXP.div: + exp = new DivExp(Loc.initial, lhs, rhs); break; + case EXP.pow: + exp = new PowExp(Loc.initial, lhs, rhs); break; + default: + exp = null; + } + + if (exp) + { + // if T op U is valid and has type V + // then T[] op U and T op U[] should be valid and have type V[] + Expression e = exp.trySemantic(sc); + if (e && e.type) + return e.type.arrayOf; + } + + return null; + } + if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1)) { if (e2.implicitConvTo(t1.nextOf())) @@ -3463,8 +3545,12 @@ LmodCompare: e2 = e2.castTo(sc, t); return Lret(t); } - return null; } + + t = checkArrayOpType(e1, e2, op, sc); + if (t !is null) + return Lret(t); + return null; } else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2)) @@ -3483,15 +3569,19 @@ LmodCompare: t = e1.type.arrayOf(); } else - return null; + { + t = checkArrayOpType(e1, e2, op, sc); + if (t is null) + return null; + } - //printf("test %s\n", Token::toChars(op)); + //printf("test %s\n", EXPtoString(op).ptr); e1 = e1.optimize(WANTvalue); if (isCommutative(op) && e1.isConst()) { /* Swap operands to minimize number of functions generated */ - //printf("swap %s\n", Token::toChars(op)); + //printf("swap %s\n", EXPtoString(op).ptr); Expression tmp = e1; e1 = e2; e2 = tmp; @@ -3512,7 +3602,7 @@ Expression typeCombine(BinExp be, Scope* sc) Expression errorReturn() { Expression ex = be.incompatibleTypes(); - if (ex.op == TOK.error) + if (ex.op == EXP.error) return ex; return ErrorExp.get(); } @@ -3520,7 +3610,7 @@ Expression typeCombine(BinExp be, Scope* sc) Type t1 = be.e1.type.toBasetype(); Type t2 = be.e2.type.toBasetype(); - if (be.op == TOK.min || be.op == TOK.add) + if (be.op == EXP.min || be.op == EXP.add) { // struct+struct, and class+class are errors if (t1.ty == Tstruct && t2.ty == Tstruct) @@ -3540,9 +3630,9 @@ Expression typeCombine(BinExp be, Scope* sc) return errorReturn(); // If the types have no value, return an error - if (be.e1.op == TOK.error) + if (be.e1.op == EXP.error) return be.e1; - if (be.e2.op == TOK.error) + if (be.e2.op == EXP.error) return be.e2; return null; } @@ -3606,8 +3696,8 @@ void fix16997(Scope* sc, UnaExp ue) 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()); + ue.deprecation("integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`", + ue.toChars(), EXPtoString(ue.op).ptr, ue.e1.toChars()); break; default: diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index e3f135a..18c8ca2 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -94,7 +94,7 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1) ((fd.isCtorDeclaration() && var.isField()) || (fd.isStaticCtorDeclaration() && !var.isField())) && fd.toParentDecl() == var.toParent2() && - (!e1 || e1.op == TOK.this_)) + (!e1 || e1.op == EXP.this_)) { bool result = true; @@ -250,7 +250,10 @@ extern (C++) abstract class Declaration : Dsymbol override final d_uns64 size(const ref Loc loc) { assert(type); - return type.size(); + const sz = type.size(); + if (sz == SIZE_INVALID) + errors = true; + return sz; } /** @@ -371,7 +374,7 @@ extern (C++) abstract class Declaration : Dsymbol } } - if (e1 && e1.op == TOK.this_ && isField()) + if (e1 && e1.op == EXP.this_ && isField()) { VarDeclaration vthis = (cast(ThisExp)e1).var; for (Scope* scx = sc; scx; scx = scx.enclosing) @@ -385,7 +388,7 @@ extern (C++) abstract class Declaration : Dsymbol } } - if (v && (isCtorinit() || isField())) + if (v && (v.isCtorinit() || isField())) { // It's only modifiable if inside the right constructor if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_)) @@ -434,11 +437,6 @@ extern (C++) abstract class Declaration : Dsymbol 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; @@ -655,7 +653,7 @@ extern (C++) final class TupleDeclaration : Declaration if (o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; - if (e.op == TOK.dSymbol) + if (e.op == EXP.dSymbol) { DsymbolExp ve = cast(DsymbolExp)e; Declaration d = ve.s.isDeclaration(); @@ -1062,6 +1060,7 @@ extern (C++) class VarDeclaration : Declaration 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 setInCtorOnly; // field can only be set in a constructor, as it is const or immutable // Both these mean the var is not rebindable once assigned, // and the destructor gets run when it goes out of scope @@ -1131,7 +1130,7 @@ extern (C++) class VarDeclaration : Declaration RootObject o = (*v2.objects)[i]; assert(o.dyncast() == DYNCAST.expression); Expression e = cast(Expression)o; - assert(e.op == TOK.dSymbol); + assert(e.op == EXP.dSymbol); DsymbolExp se = cast(DsymbolExp)e; se.s.setFieldOffset(ad, fieldState, isunion); } @@ -1250,6 +1249,11 @@ extern (C++) class VarDeclaration : Declaration return false; } + final bool isCtorinit() const pure nothrow @nogc @safe + { + return setInCtorOnly; + } + /******************************* * Does symbol go into data segment? * Includes extern variables. @@ -1607,7 +1611,7 @@ extern (C++) class VarDeclaration : Declaration ExpInitializer ez = _init.isExpInitializer(); assert(ez); Expression e = ez.exp; - if (e.op == TOK.construct || e.op == TOK.blit) + if (e.op == EXP.construct || e.op == EXP.blit) e = (cast(AssignExp)e).e2; return lambdaCheckForNestedRef(e, sc); } @@ -1670,11 +1674,11 @@ extern (C++) class VarDeclaration : Declaration assert(this.loc != Loc.initial); assert(v.loc != Loc.initial); - if (auto ld = this.loc.linnum - v.loc.linnum) - return ld < 0; + if (this.loc.linnum != v.loc.linnum) + return this.loc.linnum < v.loc.linnum; - if (auto cd = this.loc.charnum - v.loc.charnum) - return cd < 0; + if (this.loc.charnum != v.loc.charnum) + return this.loc.charnum < v.loc.charnum; // Default fallback return this.sequenceNumber < v.sequenceNumber; @@ -1930,9 +1934,9 @@ extern (C++) class BitFieldDeclaration : VarDeclaration */ extern (C++) final class SymbolDeclaration : Declaration { - StructDeclaration dsym; + AggregateDeclaration dsym; - extern (D) this(const ref Loc loc, StructDeclaration dsym) + extern (D) this(const ref Loc loc, AggregateDeclaration dsym) { super(loc, dsym.ident); this.dsym = dsym; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 4a4c353..884146e 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -53,7 +53,7 @@ struct IntRange; #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 + // 0x10000ULL #define STCtemplateparameter 0x20000ULL /// template parameter #define STCref 0x40000ULL /// `ref` #define STCscope 0x80000ULL /// `scope` @@ -65,7 +65,7 @@ struct IntRange; #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 + // 0x4000000ULL #define STCmanifest 0x8000000ULL /// manifest constant #define STCnodtor 0x10000000ULL /// do not run destructor @@ -131,7 +131,6 @@ public: virtual bool isDataseg(); virtual bool isThreadlocal(); virtual bool isCodeseg() const; - 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; } @@ -247,6 +246,7 @@ public: 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 setInCtorOnly; // field can only be set in a constructor, as it is const or immutable bool onstack; // it is a class that was allocated on the stack bool mynew; // it is a class new'd with custom operator new char canassign; // it can be assigned to @@ -266,6 +266,7 @@ public: bool needThis(); bool isExport() const; bool isImportedSymbol() const; + bool isCtorinit() const; bool isDataseg(); bool isThreadlocal(); bool isCTFE(); @@ -303,7 +304,7 @@ public: class SymbolDeclaration : public Declaration { public: - StructDeclaration *dsym; + AggregateDeclaration *dsym; // Eliminate need for dynamic_cast SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; } diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a1f36c0..891adb3 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -34,6 +34,7 @@ import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; +import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.init; @@ -63,26 +64,26 @@ 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.dotTemplateInstance: // ditto - case TOK.dot: // ditto + case EXP.int64: + case EXP.float64: + case EXP.complex80: + case EXP.null_: + case EXP.void_: + case EXP.string_: + case EXP.this_: + case EXP.super_: + case EXP.type: + case EXP.typeid_: + case EXP.template_: // non-eponymous template/instance + case EXP.scope_: // ditto + case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here + case EXP.dotTemplateInstance: // ditto + case EXP.dot: // ditto if (e.type.ty == Terror) return ErrorExp.get(); - goto case TOK.error; + goto case EXP.error; - case TOK.error: + case EXP.error: return e; default: @@ -115,7 +116,7 @@ public Expression ctfeInterpret(Expression e) */ public Expression ctfeInterpretForPragmaMsg(Expression e) { - if (e.op == TOK.error || e.op == TOK.type) + if (e.op == EXP.error || e.op == EXP.type) return e; // It's also OK for it to be a function declaration (happens only with @@ -410,7 +411,7 @@ private struct InterState * thisarg = 'this', if a needThis() function, NULL if not. * * Returns: - * result expression if successful, TOK.cantExpression if not, + * result expression if successful, EXP.cantExpression if not, * or CTFEExp if function returned void. */ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg) @@ -507,7 +508,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta /* 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_))) + if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_))) earg = copyLiteral(earg).copy(); } if (auto tee = earg.isThrownExceptionExp()) @@ -563,7 +564,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta } ctfeGlobals.stack.push(v); - if (fparam.isReference() && earg.op == TOK.variable && + if (fparam.isReference() && earg.op == EXP.variable && earg.isVarExp().var.toParent2() == fd) { VarDeclaration vx = earg.isVarExp().var.isVarDeclaration(); @@ -660,16 +661,16 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta } else { - assert(!e || (e.op != TOK.continue_ && e.op != TOK.break_)); + assert(!e || (e.op != EXP.continue_ && e.op != EXP.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) + if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis) e = thisarg; - if (tf.isref && fd.isThis2 && e.op == TOK.index) + if (tf.isref && fd.isThis2 && e.op == EXP.index) { auto ie = e.isIndexExp(); auto pe = ie.e1.isPtrExp(); @@ -733,14 +734,14 @@ public: this.goal = goal; } - // If e is TOK.throw_exception or TOK.cantExpression, + // If e is EXP.throw_exception or EXP.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; + result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e; return true; } return false; @@ -839,7 +840,7 @@ public: continue; if (exceptionOrCant(e)) return; - if (e.op == TOK.break_) + if (e.op == EXP.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -850,7 +851,7 @@ public: result = null; return; } - if (e.op == TOK.continue_) + if (e.op == EXP.continue_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -894,7 +895,7 @@ public: if (isTrueBool(e)) result = interpret(pue, s.ifbody, istate); - else if (e.isBool(false)) + else if (e.toBool().hasValue(false)) result = interpret(pue, s.elsebody, istate); else { @@ -935,7 +936,7 @@ public: if (auto eaddr = e.isAddrExp()) x = eaddr.e1; VarDeclaration v; - while (x.op == TOK.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null) + while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null) { if (v.storage_class & STC.ref_) { @@ -952,7 +953,7 @@ public: else break; } - // TODO: If it is a TOK.dotVariable or TOK.index, we should check that it is not + // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not // pointing to a local struct or static array. } if (auto se = e.isStructLiteralExp()) @@ -1023,7 +1024,7 @@ public: return; } - // We need to treat pointers specially, because TOK.symbolOffset can be used to + // We need to treat pointers specially, because EXP.symbolOffset can be used to // return a value OR a pointer Expression e = interpret(pue, s.exp, istate); if (exceptionOrCant(e)) @@ -1122,7 +1123,7 @@ public: if (exceptionOrCant(e)) return; - if (e && e.op == TOK.break_) + if (e && e.op == EXP.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -1132,7 +1133,7 @@ public: istate.gotoTarget = null; break; } - if (e && e.op == TOK.continue_) + if (e && e.op == EXP.continue_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -1158,7 +1159,7 @@ public: result = CTFEExp.cantexp; return; } - if (e.isBool(false)) + if (e.toBool().hasValue(false)) break; assert(isTrueBool(e)); } @@ -1189,7 +1190,7 @@ public: Expression e = interpret(&ue, s.condition, istate); if (exceptionOrCant(e)) return; - if (e.isBool(false)) + if (e.toBool().hasValue(false)) break; assert(isTrueBool(e)); } @@ -1201,7 +1202,7 @@ public: if (exceptionOrCant(e)) return; - if (e && e.op == TOK.break_) + if (e && e.op == EXP.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -1211,7 +1212,7 @@ public: istate.gotoTarget = null; break; } - if (e && e.op == TOK.continue_) + if (e && e.op == EXP.continue_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -1263,7 +1264,7 @@ public: return; if (exceptionOrCant(e)) return; - if (e && e.op == TOK.break_) + if (e && e.op == EXP.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -1290,7 +1291,7 @@ public: Expression ecase = interpret(&uecase, cs.exp, istate); if (exceptionOrCant(ecase)) return; - if (ctfeEqual(cs.exp.loc, TOK.equal, econdition, ecase)) + if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase)) { scase = cs; break; @@ -1310,7 +1311,7 @@ public: istate.start = scase; Expression e = interpret(pue, s._body, istate); assert(!istate.start); // jump must not fail - if (e && e.op == TOK.break_) + if (e && e.op == EXP.break_) { if (istate.gotoTarget && istate.gotoTarget != s) { @@ -1515,7 +1516,7 @@ public: (*collateral.value.elements)[bypass] = boss; return newest; } - while ((*boss.value.elements)[next].op == TOK.classReference) + while ((*boss.value.elements)[next].op == EXP.classReference) { boss = cast(ClassReferenceExp)(*boss.value.elements)[next]; } @@ -1606,7 +1607,7 @@ public: if (exceptionOrCant(e)) return; - assert(e.op == TOK.classReference); + assert(e.op == EXP.classReference); result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp()); } @@ -1630,7 +1631,7 @@ public: } // If it is with(Enum) {...}, just execute the body. - if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type) + if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type) { result = interpret(pue, s._body, istate); return; @@ -1707,7 +1708,7 @@ public: { debug (LOG) { - printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars()); + printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars()); printf("type = %s\n", e.type.toChars()); showCtfeExpr(e); } @@ -1755,9 +1756,9 @@ public: { if (istate && istate.fd.isThis2) { - assert(result.op == TOK.address); + assert(result.op == EXP.address); result = (cast(AddrExp)result).e1; - assert(result.op == TOK.arrayLiteral); + assert(result.op == EXP.arrayLiteral); result = (*(cast(ArrayLiteralExp)result).elements)[0]; if (e.type.ty == Tstruct) { @@ -1765,7 +1766,7 @@ public: } return; } - assert(result.op == TOK.structLiteral || result.op == TOK.classReference || result.op == TOK.type); + assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type); return; } e.error("value of `this` is not known at compile time"); @@ -1909,7 +1910,7 @@ public: dinteger_t indx = e.offset / sz; assert(sz * indx == e.offset); Expression aggregate = null; - if (val.op == TOK.arrayLiteral || val.op == TOK.string_) + if (val.op == EXP.arrayLiteral || val.op == EXP.string_) { aggregate = val; } @@ -2054,13 +2055,13 @@ public: return CTFEExp.cantexp; assert(e.type); - if (e.op == TOK.construct || e.op == TOK.blit) + if (e.op == EXP.construct || e.op == EXP.blit) { AssignExp ae = cast(AssignExp)e; e = ae.e2; } - if (e.op == TOK.error) + if (e.op == EXP.error) { // FIXME: Ultimately all errors should be detected in prior semantic analysis stage. } @@ -2142,12 +2143,20 @@ public: } else if (SymbolDeclaration s = d.isSymbolDeclaration()) { + // exclude void[]-typed `__traits(initSymbol)` + if (auto ta = s.type.toBasetype().isTypeDArray()) + { + assert(ta.next.ty == Tvoid); + error(loc, "cannot determine the address of the initializer symbol during CTFE"); + return CTFEExp.cantexp; + } + // Struct static initializers, for example e = s.dsym.type.defaultInitLiteral(loc); - if (e.op == TOK.error) + if (e.op == EXP.error) error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars()); e = e.expressionSemantic(null); - if (e.op == TOK.error) + if (e.op == EXP.error) e = CTFEExp.cantexp; else // Convert NULL to CTFEExp e = interpret(e, istate, goal); @@ -2195,10 +2204,10 @@ public: { // 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.type.toBasetype().ty == Tsarray) || - ev.op == TOK.dotVariable) + if (ev.op == EXP.variable || + ev.op == EXP.index || + (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) || + ev.op == EXP.dotVariable) { result = interpret(pue, ev, istate, goal); return; @@ -2363,13 +2372,13 @@ public: if (exceptionOrCant(ex)) return; - if (result.op == TOK.null_) + if (result.op == EXP.null_) { e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars()); result = CTFEExp.cantexp; return; } - if (result.op != TOK.classReference) + if (result.op != EXP.classReference) { e.error("CTFE internal error: determining classinfo"); result = CTFEExp.cantexp; @@ -2406,7 +2415,7 @@ public: // A tuple of assignments can contain void (Bug 5676). if (goal == CTFEGoal.Nothing) continue; - if (ex.op == TOK.voidExpression) + if (ex.op == EXP.voidExpression) { e.error("CTFE internal error: void element `%s` in tuple", exp.toChars()); assert(0); @@ -2464,7 +2473,7 @@ public: else { // segfault bug 6250 - assert(exp.op != TOK.index || (cast(IndexExp)exp).e1 != e); + assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e); ex = interpretRegion(exp, istate); if (exceptionOrCant(ex)) @@ -2569,7 +2578,7 @@ public: for (size_t j = i; j < keysx.dim; j++) { auto ekey2 = (*keysx)[j]; - if (!ctfeEqual(e.loc, TOK.equal, ekey, ekey2)) + if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2)) continue; // Remove ekey @@ -2904,15 +2913,15 @@ public: return; switch (e.op) { - case TOK.negate: + case EXP.negate: *pue = Neg(e.type, e1); break; - case TOK.tilde: + case EXP.tilde: *pue = Com(e.type, e1); break; - case TOK.not: + case EXP.not: *pue = Not(e.type, e1); break; @@ -2948,7 +2957,7 @@ public: { 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) + if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min) { UnionExp ue1 = void; Expression e1 = interpret(&ue1, e.e1, istate); @@ -2976,7 +2985,7 @@ public: result = (*pue).exp(); return; } - if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == TOK.add) + if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add) { UnionExp ue1 = void; Expression e1 = interpret(&ue1, e.e1, istate); @@ -3015,7 +3024,7 @@ public: if (!evalOperand(&ue2, e.e2, e2)) return; - if (e.op == TOK.rightShift || e.op == TOK.leftShift || e.op == TOK.unsignedRightShift) + if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift) { const sinteger_t i2 = e2.toInteger(); const d_uns64 sz = e1.type.size() * 8; @@ -3073,13 +3082,13 @@ public: { // The following should really be an assert() e1.error("CTFE internal error: non-constant value `%s`", e1.toChars()); - emplaceExp!CTFEExp(&ue, TOK.cantExpression); + emplaceExp!CTFEExp(&ue, EXP.cantExpression); return ue; } if (e2.isConst() != 1) { e2.error("CTFE internal error: non-constant value `%s`", e2.toChars()); - emplaceExp!CTFEExp(&ue, TOK.cantExpression); + emplaceExp!CTFEExp(&ue, EXP.cantExpression); return ue; } @@ -3116,7 +3125,7 @@ public: const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2); if (cmp == -1) { - char dir = (e.op == TOK.greaterThan || e.op == TOK.greaterOrEqual) ? '<' : '>'; + char dir = (e.op == EXP.greaterThan || e.op == EXP.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; @@ -3162,73 +3171,73 @@ public: { switch (e.op) { - case TOK.add: + case EXP.add: interpretCommon(e, &Add); return; - case TOK.min: + case EXP.min: interpretCommon(e, &Min); return; - case TOK.mul: + case EXP.mul: interpretCommon(e, &Mul); return; - case TOK.div: + case EXP.div: interpretCommon(e, &Div); return; - case TOK.mod: + case EXP.mod: interpretCommon(e, &Mod); return; - case TOK.leftShift: + case EXP.leftShift: interpretCommon(e, &Shl); return; - case TOK.rightShift: + case EXP.rightShift: interpretCommon(e, &Shr); return; - case TOK.unsignedRightShift: + case EXP.unsignedRightShift: interpretCommon(e, &Ushr); return; - case TOK.and: + case EXP.and: interpretCommon(e, &And); return; - case TOK.or: + case EXP.or: interpretCommon(e, &Or); return; - case TOK.xor: + case EXP.xor: interpretCommon(e, &Xor); return; - case TOK.pow: + case EXP.pow: interpretCommon(e, &Pow); return; - case TOK.equal: - case TOK.notEqual: + case EXP.equal: + case EXP.notEqual: interpretCompareCommon(e, &ctfeEqual); return; - case TOK.identity: - case TOK.notIdentity: + case EXP.identity: + case EXP.notIdentity: interpretCompareCommon(e, &ctfeIdentity); return; - case TOK.lessThan: - case TOK.lessOrEqual: - case TOK.greaterThan: - case TOK.greaterOrEqual: + case EXP.lessThan: + case EXP.lessOrEqual: + case EXP.greaterThan: + case EXP.greaterOrEqual: interpretCompareCommon(e, &ctfeCmp); return; default: - printf("be = '%s' %s at [%s]\n", Token.toChars(e.op), e.toChars(), e.loc.toChars()); + printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars()); assert(0); } } @@ -3286,7 +3295,7 @@ public: * So we need to recurse to determine if it is a block assignment. */ bool isBlockAssignment = false; - if (e1.op == TOK.slice) + if (e1.op == EXP.slice) { // a[] = e can have const e. So we compare the naked types. Type tdst = e1.type.toBasetype(); @@ -3306,7 +3315,7 @@ public: // 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) && + if ((e.op == EXP.construct || e.op == EXP.blit) && ((cast(AssignExp)e).memset == MemorySet.referenceInit)) { assert(!fp); @@ -3329,7 +3338,7 @@ public: if (fp) { - while (e1.op == TOK.cast_) + while (e1.op == EXP.cast_) { CastExp ce = cast(CastExp)e1; e1 = ce.e1; @@ -3342,7 +3351,7 @@ public: AssocArrayLiteralExp existingAA = null; Expression lastIndex = null; Expression oldval = null; - if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) + if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) { // --------------------------------------- // Deal with AA index assignment @@ -3356,7 +3365,7 @@ public: */ 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) + while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray) { assert(ie.modifiable); ie = cast(IndexExp)ie.e1; @@ -3430,7 +3439,7 @@ public: 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) + while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) { Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate); if (exceptionOrCant(ekey)) @@ -3465,13 +3474,13 @@ public: assert(existingAA && lastIndex); e1 = null; // stomp } - else if (e1.op == TOK.arrayLength) + else if (e1.op == EXP.arrayLength) { oldval = interpretRegion(e1, istate); if (exceptionOrCant(oldval)) return; } - else if (e.op == TOK.construct || e.op == TOK.blit) + else if (e.op == EXP.construct || e.op == EXP.blit) { // Unless we have a simple var assignment, we're // only modifying part of the variable. So we need to make sure @@ -3501,10 +3510,10 @@ public: if (exceptionOrCant(e1)) return; - if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) + if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) { IndexExp ie = cast(IndexExp)e1; - assert(ie.e1.op == TOK.assocArrayLiteral); + assert(ie.e1.op == EXP.assocArrayLiteral); existingAA = cast(AssocArrayLiteralExp)ie.e1; lastIndex = ie.e2; } @@ -3516,7 +3525,7 @@ public: Expression newval = interpretRegion(e.e2, istate); if (exceptionOrCant(newval)) return; - if (e.op == TOK.blit && newval.op == TOK.int64) + if (e.op == EXP.blit && newval.op == EXP.int64) { Type tbn = e.type.baseElemOf(); if (tbn.ty == Tstruct) @@ -3524,7 +3533,7 @@ public: /* Look for special case of struct being initialized with 0. */ newval = e.type.defaultInitLiteral(e.loc); - if (newval.op == TOK.error) + if (newval.op == EXP.error) { result = CTFEExp.cantexp; return; @@ -3554,7 +3563,7 @@ public: 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) + if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign) { // We need to dup it and repaint the type. For a dynamic array // we can skip duplication, because it gets copied later anyway. @@ -3574,10 +3583,10 @@ public: 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)) + (e.op == EXP.addAssign || + e.op == EXP.minAssign || + e.op == EXP.plusPlus || + e.op == EXP.minusMinus)) { newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy(); } @@ -3612,7 +3621,7 @@ public: result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval); return; } - if (e1.op == TOK.arrayLength) + if (e1.op == EXP.arrayLength) { /* Change the assignment from: * arr.length = n; @@ -3692,11 +3701,11 @@ public: /* 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) + if (e1.op == EXP.slice || + e1.op == EXP.vector || + e1.op == EXP.arrayLiteral || + e1.op == EXP.string_ || + e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray) { // Note that slice assignments don't support things like ++, so // we don't need to remember 'returnValue'. @@ -3709,8 +3718,8 @@ public: 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 + auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex) + : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value : null; auto v = dve.var.isVarDeclaration(); if (!sle || !v) @@ -3745,7 +3754,7 @@ public: if (v is v2 || !v.isOverlappedWith(v2)) continue; auto e = (*sle.elements)[i]; - if (e.op != TOK.void_) + if (e.op != EXP.void_) (*sle.elements)[i] = voidInitLiteral(e.type, v).copy(); } } @@ -3768,8 +3777,8 @@ public: * e.v = newval */ auto ex = dve.e1; - auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex) - : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value + auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex) + : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value : null; auto v = (cast(DotVarExp)e1).var.isVarDeclaration(); if (!sle || !v) @@ -3783,7 +3792,7 @@ public: return CTFEExp.cantexp; } - int fieldi = ex.op == TOK.structLiteral ? findFieldIndexByName(sle.sd, v) + int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v) : (cast(ClassReferenceExp)ex).findFieldIndexByName(v); if (fieldi == -1) { @@ -3820,7 +3829,7 @@ public: existingSE.setCodeUnit(index, cast(dchar)newval.toInteger()); return null; } - if (aggregate.op != TOK.arrayLiteral) + if (aggregate.op != EXP.arrayLiteral) { e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars()); return CTFEExp.cantexp; @@ -3848,7 +3857,7 @@ public: 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 + if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast { UnionExp ue = void; Expression ex = interpretVectorToArray(&ue, ve); @@ -3856,13 +3865,13 @@ public: } } - if (newval.op == TOK.structLiteral && oldval) + if (newval.op == EXP.structLiteral && oldval) { - assert(oldval.op == TOK.structLiteral || oldval.op == TOK.arrayLiteral || oldval.op == TOK.string_); + assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_); newval = copyLiteral(newval).copy(); assignInPlace(oldval, newval); } - else if (wantCopy && e.op == TOK.assign) + else if (wantCopy && e.op == EXP.assign) { // Currently postblit/destructor calls on static array are done // in the druntime internal functions so they don't appear in AST. @@ -3878,8 +3887,8 @@ public: return CTFEExp.cantexp; } } - assert(oldval.op == TOK.arrayLiteral); - assert(newval.op == TOK.arrayLiteral); + assert(oldval.op == EXP.arrayLiteral); + assert(newval.op == EXP.arrayLiteral); Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements; Expressions* newelems = (cast(ArrayLiteralExp)newval).elements; @@ -3907,7 +3916,7 @@ public: if (wantCopy) newval = copyLiteral(newval).copy(); - if (t1b.ty == Tsarray && e.op == TOK.construct && e.e2.isLvalue()) + if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=9245 if (Expression ex = evaluatePostblit(istate, newval)) @@ -3923,7 +3932,7 @@ public: *payload = oldval; // Blit assignment should return the newly created value. - if (e.op == TOK.blit) + if (e.op == EXP.blit) return oldval; return null; @@ -3938,7 +3947,7 @@ public: * 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, + * Returns EXP.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 */ @@ -4024,7 +4033,7 @@ public: lowerbound = 0; upperbound = se.len; } - else if (e1.op == TOK.null_) + else if (e1.op == EXP.null_) { lowerbound = 0; upperbound = 0; @@ -4088,7 +4097,7 @@ public: return CTFEExp.cantexp; } } - assert(newval.op != TOK.slice); + assert(newval.op != EXP.slice); } if (auto se = newval.isStringExp()) { @@ -4126,7 +4135,7 @@ public: return CTFEExp.cantexp; } - if (newval.op == TOK.slice && !isBlockAssignment) + if (newval.op == EXP.slice && !isBlockAssignment) { auto se = cast(SliceExp)newval; auto aggr2 = se.e1; @@ -4142,7 +4151,7 @@ public: // 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); + assert(aggr2.op == EXP.arrayLiteral); Expressions* oldelems = existingAE.elements; Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements; @@ -4210,9 +4219,9 @@ public: } // no overlapping //length? - assert(newval.op != TOK.slice); + assert(newval.op != EXP.slice); } - if (newval.op == TOK.string_ && !isBlockAssignment) + if (newval.op == EXP.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. @@ -4220,12 +4229,12 @@ public: sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex); return newval; } - if (newval.op == TOK.arrayLiteral && !isBlockAssignment) + if (newval.op == EXP.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(); + bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue(); foreach (j, newelem; *newelems) { newelem = paintTypeOntoLiteral(elemtype, newelem); @@ -4265,7 +4274,7 @@ public: 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) + if (!directblk && (*w)[k].op == EXP.arrayLiteral) { // Multidimensional array block assign if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k])) @@ -4303,7 +4312,7 @@ public: 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_; + bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_; Type tb = tn.baseElemOf(); StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null); @@ -4311,8 +4320,8 @@ public: 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; + rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue(); + rb.needsDtor = sd && sd.dtor && e.op == EXP.assign; if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound)) return ex; @@ -4338,57 +4347,57 @@ public: { switch (e.op) { - case TOK.addAssign: + case EXP.addAssign: interpretAssignCommon(e, &Add); return; - case TOK.minAssign: + case EXP.minAssign: interpretAssignCommon(e, &Min); return; - case TOK.concatenateAssign: - case TOK.concatenateElemAssign: - case TOK.concatenateDcharAssign: + case EXP.concatenateAssign: + case EXP.concatenateElemAssign: + case EXP.concatenateDcharAssign: interpretAssignCommon(e, &ctfeCat); return; - case TOK.mulAssign: + case EXP.mulAssign: interpretAssignCommon(e, &Mul); return; - case TOK.divAssign: + case EXP.divAssign: interpretAssignCommon(e, &Div); return; - case TOK.modAssign: + case EXP.modAssign: interpretAssignCommon(e, &Mod); return; - case TOK.leftShiftAssign: + case EXP.leftShiftAssign: interpretAssignCommon(e, &Shl); return; - case TOK.rightShiftAssign: + case EXP.rightShiftAssign: interpretAssignCommon(e, &Shr); return; - case TOK.unsignedRightShiftAssign: + case EXP.unsignedRightShiftAssign: interpretAssignCommon(e, &Ushr); return; - case TOK.andAssign: + case EXP.andAssign: interpretAssignCommon(e, &And); return; - case TOK.orAssign: + case EXP.orAssign: interpretAssignCommon(e, &Or); return; - case TOK.xorAssign: + case EXP.xorAssign: interpretAssignCommon(e, &Xor); return; - case TOK.powAssign: + case EXP.powAssign: interpretAssignCommon(e, &Pow); return; @@ -4403,7 +4412,7 @@ public: { printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } - if (e.op == TOK.plusPlus) + if (e.op == EXP.plusPlus) interpretAssignCommon(e, &Add, 1); else interpretAssignCommon(e, &Min, 1); @@ -4421,19 +4430,19 @@ public: static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2) { int ret = 1; - while (e.op == TOK.not) + while (e.op == EXP.not) { ret *= -1; e = (cast(NotExp)e).e1; } switch (e.op) { - case TOK.lessThan: - case TOK.lessOrEqual: + case EXP.lessThan: + case EXP.lessOrEqual: ret *= -1; goto case; /+ fall through +/ - case TOK.greaterThan: - case TOK.greaterOrEqual: + case EXP.greaterThan: + case EXP.greaterOrEqual: *p1 = (cast(BinExp)e).e1; *p2 = (cast(BinExp)e).e2; if (!(isPointer((*p1).type) && isPointer((*p2).type))) @@ -4465,7 +4474,7 @@ public: */ private void interpretFourPointerRelation(UnionExp* pue, BinExp e) { - assert(e.op == TOK.andAnd || e.op == TOK.orOr); + assert(e.op == EXP.andAnd || e.op == EXP.orOr); /* It can only be an isInside expression, if both e1 and e2 are * directional pointer comparisons. @@ -4506,7 +4515,7 @@ public: Expression agg1 = getAggregateFromPointer(p1, &ofs1); Expression agg2 = getAggregateFromPointer(p2, &ofs2); - if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != TOK.null_ && agg2.op != TOK.null_) + if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_) { // Here it is either CANT_INTERPRET, // or an IsInside comparison returning false. @@ -4545,7 +4554,7 @@ public: (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); + emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type); result = pue.exp(); return; } @@ -4582,29 +4591,29 @@ public: * Returns: * negate operator */ - static TOK negateRelation(TOK op) pure + static EXP negateRelation(EXP 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; + case EXP.greaterOrEqual: op = EXP.lessThan; break; + case EXP.greaterThan: op = EXP.lessOrEqual; break; + case EXP.lessOrEqual: op = EXP.greaterThan; break; + case EXP.lessThan: op = EXP.greaterOrEqual; break; default: assert(0); } return op; } - const TOK cmpop = nott ? negateRelation(ex.op) : ex.op; + const EXP 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) + if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0) { result = interpret(pue, e.e2, istate); return; } - emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type); + emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type); result = pue.exp(); } @@ -4625,22 +4634,22 @@ public: return; bool res; - const andand = e.op == TOK.andAnd; - if (andand ? result.isBool(false) : isTrueBool(result)) + const andand = e.op == EXP.andAnd; + if (andand ? result.toBool().hasValue(false) : isTrueBool(result)) res = !andand; - else if (andand ? isTrueBool(result) : result.isBool(false)) + else if (andand ? isTrueBool(result) : result.toBool().hasValue(false)) { UnionExp ue2 = void; result = interpret(&ue2, e.e2, istate); if (exceptionOrCant(result)) return; - if (result.op == TOK.voidExpression) + if (result.op == EXP.voidExpression) { assert(e.type.ty == Tvoid); result = null; return; } - if (result.isBool(false)) + if (result.toBool().hasValue(false)) res = false; else if (isTrueBool(result)) res = true; @@ -4762,8 +4771,8 @@ public: 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) + // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars()); + if (ea.op == EXP.variable || ea.op == EXP.symbolOffset) result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue); else if (auto ae = ea.isAddrExp()) result = interpretRegion(ae.e1, istate); @@ -4805,6 +4814,29 @@ public: result = interpretRegion(ae, istate); return; } + else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor) + { + // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`. + // The following code will rewrite it back to `ea = eb` and then interpret that expression. + if (fd.ident == Id._d_arraysetctor) + assert(e.arguments.dim == 2); + else + assert(e.arguments.dim == 3); + + Expression ea = (*e.arguments)[0]; + if (ea.isCastExp) + ea = ea.isCastExp.e1; + + Expression eb = (*e.arguments)[1]; + if (eb.isCastExp && fd.ident == Id._d_arrayctor) + eb = eb.isCastExp.e1; + + ConstructExp ce = new ConstructExp(e.loc, ea, eb); + ce.type = ea.type; + + result = interpret(ce, istate); + return; + } } else if (auto soe = ecall.isSymOffExp()) { @@ -4848,7 +4880,7 @@ public: // Currently this is satisfied because closure is not yet supported. assert(!fd.isNested() || fd.needThis()); - if (pthis.op == TOK.typeid_) + if (pthis.op == EXP.typeid_) { pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars()); result = CTFEExp.cantexp; @@ -4856,7 +4888,7 @@ public: } assert(pthis); - if (pthis.op == TOK.null_) + if (pthis.op == EXP.null_) { assert(pthis.type.toBasetype().ty == Tclass); e.error("function call through null class reference `%s`", pthis.toChars()); @@ -4864,7 +4896,7 @@ public: return; } - assert(pthis.op == TOK.structLiteral || pthis.op == TOK.classReference || pthis.op == TOK.type); + assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type); if (fd.isVirtual() && !e.directcall) { @@ -4899,7 +4931,7 @@ public: } result = interpretFunction(pue, fd, istate, e.arguments, pthis); - if (result.op == TOK.voidExpression) + if (result.op == EXP.voidExpression) return; if (!exceptionOrCantInterpret(result)) { @@ -4929,7 +4961,7 @@ public: // 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) + if (!istate && firstComma(e.e1).op == EXP.declaration) { ctfeGlobals.stack.startFrame(null); istate = &istateComma; @@ -4946,8 +4978,8 @@ public: // 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 && + if (e.e1.op == EXP.declaration && + e.e2.op == EXP.variable && e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var && e.e2.isVarExp().var.storage_class & STC.ctfe) { @@ -4967,7 +4999,7 @@ public: newval = interpretRegion(newval, istate); if (exceptionOrCant(newval)) return endTempStackFrame(); - if (newval.op != TOK.voidExpression) + if (newval.op != EXP.voidExpression) { // v isn't necessarily null. setValueWithoutChecking(v, copyLiteral(newval).copy()); @@ -4999,7 +5031,7 @@ public: if (isPointer(e.econd.type)) { - if (econd.op != TOK.null_) + if (econd.op != EXP.null_) { econd = IntegerExp.createBool(true); } @@ -5010,7 +5042,7 @@ public: result = interpret(pue, e.e1, istate, goal); incUsageCtfe(istate, e.e1.loc); } - else if (econd.isBool(false)) + else if (econd.toBool().hasValue(false)) { result = interpret(pue, e.e2, istate, goal); incUsageCtfe(istate, e.e2.loc); @@ -5033,7 +5065,7 @@ public: assert(e1); if (exceptionOrCant(e1)) return; - if (e1.op != TOK.string_ && e1.op != TOK.arrayLiteral && e1.op != TOK.slice && e1.op != TOK.null_) + if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_) { e.error("`%s` cannot be evaluated at compile time", e.toChars()); result = CTFEExp.cantexp; @@ -5055,7 +5087,7 @@ public: { 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) + if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64) { // Convert literal __vector(int) -> __vector([array]) auto elements = new Expressions(e.dim); @@ -5086,7 +5118,7 @@ public: assert(e1); if (exceptionOrCant(e1)) return; - if (e1.op != TOK.arrayLiteral && e1.op != TOK.int64 && e1.op != TOK.float64) + if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64) { e.error("`%s` cannot be evaluated at compile time", e.toChars()); result = CTFEExp.cantexp; @@ -5115,7 +5147,7 @@ public: if (auto ve = e1.isVectorExp()) { result = interpretVectorToArray(pue, ve); - if (result.op != TOK.vector) + if (result.op != EXP.vector) return; } e.error("`%s` cannot be evaluated at compile time", e.toChars()); @@ -5169,24 +5201,24 @@ public: dinteger_t ofs; Expression agg = getAggregateFromPointer(e1, &ofs); - if (agg.op == TOK.null_) + if (agg.op == EXP.null_) { e.error("cannot index through null pointer `%s`", e.e1.toChars()); return false; } - if (agg.op == TOK.int64) + if (agg.op == EXP.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) + if (agg.op == EXP.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_) + if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_) { dinteger_t len = resolveArrayLength(agg); if (ofs + indx >= len) @@ -5211,7 +5243,7 @@ public: Expression e1 = interpretRegion(e.e1, istate); if (exceptionOrCantInterpret(e1)) return false; - if (e1.op == TOK.null_) + if (e1.op == EXP.null_) { e.error("cannot index null array `%s`", e.e1.toChars()); return false; @@ -5225,11 +5257,11 @@ public: // Set the $ variable, and find the array literal to modify dinteger_t len; - if (e1.op == TOK.variable && e1.type.toBasetype().ty == Tsarray) + if (e1.op == EXP.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) + if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector) { e.error("cannot determine length of `%s` at compile time", e.e1.toChars()); return false; @@ -5248,7 +5280,7 @@ public: ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [] if (exceptionOrCantInterpret(e2)) return false; - if (e2.op != TOK.int64) + if (e2.op != EXP.int64) { e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars()); return false; @@ -5297,7 +5329,7 @@ public: result = CTFEExp.cantexp; return; } - if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_) + if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_) { if (goal == CTFEGoal.LValue) { @@ -5327,7 +5359,7 @@ public: Expression e1 = interpretRegion(e.e1, istate); if (exceptionOrCant(e1)) return; - if (e1.op == TOK.null_) + if (e1.op == EXP.null_) { if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable) { @@ -5355,7 +5387,7 @@ public: return; } - assert(e1.op == TOK.assocArrayLiteral); + assert(e1.op == EXP.assocArrayLiteral); UnionExp e2tmp = void; e2 = resolveSlice(e2, &e2tmp); result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2); @@ -5387,7 +5419,7 @@ public: result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess); if (exceptionOrCant(result)) return; - if (result.op == TOK.void_) + if (result.op == EXP.void_) { e.error("`%s` is used before initialized", e.toChars()); errorSupplemental(result.loc, "originally uninitialized here"); @@ -5410,7 +5442,7 @@ public: Expression e1 = interpretRegion(e.e1, istate); if (exceptionOrCant(e1)) return; - if (e1.op == TOK.int64) + if (e1.op == EXP.int64) { e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars()); result = CTFEExp.cantexp; @@ -5432,7 +5464,7 @@ public: Expression agg = getAggregateFromPointer(e1, &ofs); ilwr += ofs; iupr += ofs; - if (agg.op == TOK.null_) + if (agg.op == EXP.null_) { if (iupr == ilwr) { @@ -5444,19 +5476,19 @@ public: result = CTFEExp.cantexp; return; } - if (agg.op == TOK.symbolOffset) + if (agg.op == EXP.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_) + if (agg.op != EXP.arrayLiteral && agg.op != EXP.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_); + assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_); dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger(); //Type *pointee = ((TypePointer *)agg.type)->next; if (iupr > (len + 1) || iupr < ilwr) @@ -5503,11 +5535,11 @@ public: /* 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) + if ((e1.op == EXP.variable || e1.op == EXP.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) + if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector) { e.error("cannot determine length of `%s` at compile time", e1.toChars()); result = CTFEExp.cantexp; @@ -5546,7 +5578,7 @@ public: uinteger_t ilwr = lwr.toInteger(); uinteger_t iupr = upr.toInteger(); - if (e1.op == TOK.null_) + if (e1.op == EXP.null_) { if (ilwr == 0 && iupr == 0) { @@ -5578,7 +5610,7 @@ public: result.type = e.type; return; } - if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_) + if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_) { if (iupr < ilwr || dollar < iupr) { @@ -5604,13 +5636,13 @@ public: Expression e2 = interpretRegion(e.e2, istate); if (exceptionOrCant(e2)) return; - if (e2.op == TOK.null_) + if (e2.op == EXP.null_) { emplaceExp!(NullExp)(pue, e.loc, e.type); result = pue.exp(); return; } - if (e2.op != TOK.assocArrayLiteral) + if (e2.op != EXP.assocArrayLiteral) { e.error("`%s` cannot be interpreted at compile time", e.toChars()); result = CTFEExp.cantexp; @@ -5663,7 +5695,7 @@ public: * 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.op == EXP.string_ && e2.op == EXP.string_)) { if (e1 == ue1.exp()) e1 = ue1.copy(); @@ -5706,7 +5738,7 @@ public: if (exceptionOrCant(result)) return; - if (result.op == TOK.null_) + if (result.op == EXP.null_) { result = CTFEExp.voidexp; return; @@ -5716,7 +5748,7 @@ public: switch (tb.ty) { case Tclass: - if (result.op != TOK.classReference) + if (result.op != EXP.classReference) { e.error("`delete` on invalid class reference `%s`", result.toChars()); result = CTFEExp.cantexp; @@ -5752,8 +5784,8 @@ public: tb = (cast(TypePointer)tb).next.toBasetype(); if (tb.ty == Tstruct) { - if (result.op != TOK.address || - (cast(AddrExp)result).e1.op != TOK.structLiteral) + if (result.op != EXP.address || + (cast(AddrExp)result).e1.op != EXP.structLiteral) { e.error("`delete` on invalid struct pointer `%s`", result.toChars()); result = CTFEExp.cantexp; @@ -5776,7 +5808,7 @@ public: auto tv = tb.nextOf().baseElemOf(); if (tv.ty == Tstruct) { - if (result.op != TOK.arrayLiteral) + if (result.op != EXP.arrayLiteral) { e.error("`delete` on invalid struct array `%s`", result.toChars()); result = CTFEExp.cantexp; @@ -5819,11 +5851,11 @@ public: result = CTFEExp.voidexp; return; } - if (e.to.ty == Tpointer && e1.op != TOK.null_) + if (e.to.ty == Tpointer && e1.op != EXP.null_) { Type pointee = (cast(TypePointer)e.type).next; // Implement special cases of normally-unsafe casts - if (e1.op == TOK.int64) + if (e1.op == EXP.int64) { // Happens with Windows HANDLEs, for example. result = paintTypeOntoLiteral(pue, e.to, e1); @@ -5869,7 +5901,7 @@ public: if (auto se = e1.isSliceExp()) { - if (se.e1.op == TOK.null_) + if (se.e1.op == EXP.null_) { result = paintTypeOntoLiteral(pue, e.type, se.e1); return; @@ -5881,7 +5913,7 @@ public: result = pue.exp(); return; } - if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_) + if (e1.op == EXP.arrayLiteral || e1.op == EXP.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)); @@ -5890,7 +5922,7 @@ public: result = pue.exp(); return; } - if (e1.op == TOK.index && !(cast(IndexExp)e1).e1.type.equals(e1.type)) + if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type)) { // type painting operation IndexExp ie = cast(IndexExp)e1; @@ -5899,7 +5931,7 @@ public: // 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) + if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64) { ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1; const indx = cast(size_t)ie.e2.toInteger(); @@ -5939,7 +5971,7 @@ public: return; } - if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == TOK.index) + if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index) { // &val[idx] dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger(); @@ -5956,7 +5988,7 @@ public: } } - if (e1.op == TOK.variable || e1.op == TOK.symbolOffset) + if (e1.op == EXP.variable || e1.op == EXP.symbolOffset) { // type painting operation Type origType = (cast(SymbolExp)e1).var.type; @@ -5977,7 +6009,7 @@ public: // Check if we have a null pointer (eg, inside a struct) e1 = interpretRegion(e1, istate); - if (e1.op != TOK.null_) + if (e1.op != EXP.null_) { e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars()); result = CTFEExp.cantexp; @@ -5990,10 +6022,10 @@ public: e1 = interpretRegion(e.e1, istate); if (exceptionOrCant(e1)) return; - assert(e1.op == TOK.vector); + assert(e1.op == EXP.vector); e1 = interpretVectorToArray(pue, e1.isVectorExp()); } - if (e.to.ty == Tarray && e1.op == TOK.slice) + if (e.to.ty == Tarray && e1.op == EXP.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. @@ -6023,11 +6055,11 @@ public: auto tobt = e.to.toBasetype(); if (tobt.ty == Tbool && e1.type.ty == Tpointer) { - emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to); + emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to); result = pue.exp(); return; } - else if (tobt.isTypeBasic() && e1.op == TOK.null_) + else if (tobt.isTypeBasic() && e1.op == EXP.null_) { if (tobt.isintegral()) emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to); @@ -6051,7 +6083,7 @@ public: if (isTrueBool(e1)) { } - else if (e1.isBool(false)) + else if (e1.toBool().hasValue(false)) { if (e.msg) { @@ -6106,7 +6138,7 @@ public: // Constant fold *(&structliteral + offset) if (auto ae = e.e1.isAddExp()) { - if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64) + if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64) { AddrExp ade = cast(AddrExp)ae.e1; Expression ex = interpretRegion(ade.e1, istate); @@ -6128,7 +6160,7 @@ public: if (exceptionOrCant(result)) return; - if (result.op == TOK.function_) + if (result.op == EXP.function_) return; if (auto soe = result.isSymOffExp()) { @@ -6142,9 +6174,9 @@ public: if (result.isStringExp()) return; - if (result.op != TOK.address) + if (result.op != EXP.address) { - if (result.op == TOK.null_) + if (result.op == EXP.null_) e.error("dereference of null pointer `%s`", e.e1.toChars()); else e.error("dereference of invalid pointer `%s`", result.toChars()); @@ -6155,7 +6187,7 @@ public: // *(&x) ==> x result = (cast(AddrExp)result).e1; - if (result.op == TOK.slice && e.type.toBasetype().ty == Tsarray) + if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray) { /* aggr[lwr..upr] * upr may exceed the upper boundary of aggr, but the check is deferred @@ -6212,7 +6244,7 @@ public: return; } - if (ex.op == TOK.null_) + if (ex.op == EXP.null_) { if (ex.type.toBasetype().ty == Tclass) e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars()); @@ -6225,18 +6257,18 @@ public: StructLiteralExp se; int i; - if (ex.op != TOK.structLiteral && ex.op != TOK.classReference && ex.op != TOK.typeid_) + if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_) { return notImplementedYet(); } // We can't use getField, because it makes a copy - if (ex.op == TOK.classReference) + if (ex.op == EXP.classReference) { se = (cast(ClassReferenceExp)ex).value; i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v); } - else if (ex.op == TOK.typeid_) + else if (ex.op == EXP.typeid_) { if (v.ident == Identifier.idPool("name")) { @@ -6336,7 +6368,7 @@ public: Expression index = interpret(e.e2, istate); if (exceptionOrCant(index)) return; - if (agg.op == TOK.null_) + if (agg.op == EXP.null_) { result = CTFEExp.voidexp; return; @@ -6349,7 +6381,7 @@ public: foreach (j, evalue; *valuesx) { Expression ekey = (*keysx)[j]; - int eq = ctfeEqual(e.loc, TOK.equal, ekey, index); + int eq = ctfeEqual(e.loc, EXP.equal, ekey, index); if (eq) ++removed; else if (removed != 0) @@ -6435,11 +6467,11 @@ Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTF // 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; + case EXP.cantExpression: return CTFEExp.cantexp; + case EXP.voidExpression: return CTFEExp.voidexp; + case EXP.break_: return CTFEExp.breakexp; + case EXP.continue_: return CTFEExp.continueexp; + case EXP.goto_: return CTFEExp.gotoexp; default: break; } auto p = ctfeGlobals.region.malloc(uexp.size); @@ -6454,7 +6486,7 @@ Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTF * istate = context * Returns: * NULL continue to next statement - * TOK.cantExpression cannot interpret statement at compile time + * EXP.cantExpression cannot interpret statement at compile time * !NULL expression from return statement, or thrown exception */ Expression interpret(UnionExp* pue, Statement s, InterState* istate) @@ -6490,7 +6522,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e) */ static bool isVoid(const Expression e, bool checkArrayType = false) pure { - if (e.op == TOK.void_) + if (e.op == EXP.void_) return true; static bool isEntirelyVoid(const Expressions* elems) @@ -6539,7 +6571,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e) else { e = scrubReturnValue(loc, e); - if (CTFEExp.isCantExp(e) || e.op == TOK.error) + if (CTFEExp.isCantExp(e) || e.op == EXP.error) return e; } } @@ -6560,7 +6592,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e) return null; } - if (e.op == TOK.classReference) + if (e.op == EXP.classReference) { StructLiteralExp sle = (cast(ClassReferenceExp)e).value; if (auto ex = scrubSE(sle)) @@ -6640,7 +6672,7 @@ private Expression scrubCacheValue(Expression e) return null; } - if (e.op == TOK.classReference) + if (e.op == EXP.classReference) { if (auto ex = scrubSE((cast(ClassReferenceExp)e).value)) return ex; @@ -6717,14 +6749,14 @@ private Expression copyRegionExp(Expression e) switch (e.op) { - case TOK.classReference: + case EXP.classReference: { auto cre = e.isClassReferenceExp(); cre.value = copyRegionExp(cre.value).isStructLiteralExp(); break; } - case TOK.structLiteral: + case EXP.structLiteral: { auto sle = e.isStructLiteralExp(); @@ -6754,7 +6786,7 @@ private Expression copyRegionExp(Expression e) return slec; } - case TOK.arrayLiteral: + case EXP.arrayLiteral: { auto ale = e.isArrayLiteralExp(); ale.basis = copyRegionExp(ale.basis); @@ -6762,12 +6794,12 @@ private Expression copyRegionExp(Expression e) break; } - case TOK.assocArrayLiteral: + case EXP.assocArrayLiteral: copyArray(e.isAssocArrayLiteralExp().keys); copyArray(e.isAssocArrayLiteralExp().values); break; - case TOK.slice: + case EXP.slice: { auto se = e.isSliceExp(); se.e1 = copyRegionExp(se.e1); @@ -6776,7 +6808,7 @@ private Expression copyRegionExp(Expression e) break; } - case TOK.tuple: + case EXP.tuple: { auto te = e.isTupleExp(); te.e0 = copyRegionExp(te.e0); @@ -6784,17 +6816,17 @@ private Expression copyRegionExp(Expression e) break; } - case TOK.address: - case TOK.delegate_: - case TOK.vector: - case TOK.dotVariable: + case EXP.address: + case EXP.delegate_: + case EXP.vector: + case EXP.dotVariable: { UnaExp ue = cast(UnaExp)e; ue.e1 = copyRegionExp(ue.e1); break; } - case TOK.index: + case EXP.index: { BinExp be = cast(BinExp)e; be.e1 = copyRegionExp(be.e1); @@ -6802,30 +6834,30 @@ private Expression copyRegionExp(Expression e) 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_: + case EXP.this_: + case EXP.super_: + case EXP.variable: + case EXP.type: + case EXP.function_: + case EXP.typeid_: + case EXP.string_: + case EXP.int64: + case EXP.error: + case EXP.float64: + case EXP.complex80: + case EXP.null_: + case EXP.void_: + case EXP.symbolOffset: + case EXP.char_: break; - case TOK.cantExpression: - case TOK.voidExpression: - case TOK.showCtfeContext: + case EXP.cantExpression: + case EXP.voidExpression: + case EXP.showCtfeContext: return e; default: - printf("e: %s, %s\n", Token.toChars(e.op), e.toChars()); + printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars()); assert(0); } @@ -6848,7 +6880,7 @@ private Expression interpret_length(UnionExp* pue, InterState* istate, Expressio if (auto aae = earg.isAssocArrayLiteralExp()) len = aae.keys.dim; else - assert(earg.op == TOK.null_); + assert(earg.op == EXP.null_); emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t); return pue.exp(); } @@ -6862,12 +6894,12 @@ private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg = interpret(pue, earg, istate); if (exceptionOrCantInterpret(earg)) return earg; - if (earg.op == TOK.null_) + if (earg.op == EXP.null_) { emplaceExp!(NullExp)(pue, earg.loc, earg.type); return pue.exp(); } - if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) + if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) return null; AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp(); auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys); @@ -6885,12 +6917,12 @@ private Expression interpret_values(UnionExp* pue, InterState* istate, Expressio earg = interpret(pue, earg, istate); if (exceptionOrCantInterpret(earg)) return earg; - if (earg.op == TOK.null_) + if (earg.op == EXP.null_) { emplaceExp!(NullExp)(pue, earg.loc, earg.type); return pue.exp(); } - if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) + if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) return null; auto aae = earg.isAssocArrayLiteralExp(); auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values); @@ -6909,12 +6941,12 @@ private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression e earg = interpret(pue, earg, istate); if (exceptionOrCantInterpret(earg)) return earg; - if (earg.op == TOK.null_) + if (earg.op == EXP.null_) { emplaceExp!(NullExp)(pue, earg.loc, earg.type); return pue.exp(); } - if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) + if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray) return null; auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp(); for (size_t i = 0; i < aae.keys.dim; i++) @@ -6935,7 +6967,7 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi aa = interpret(aa, istate); if (exceptionOrCantInterpret(aa)) return aa; - if (aa.op != TOK.assocArrayLiteral) + if (aa.op != EXP.assocArrayLiteral) { emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t); return pue.exp(); @@ -7316,7 +7348,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const re } 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) + if (pthis.op == EXP.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. @@ -7383,7 +7415,7 @@ private Expression evaluatePostblit(InterState* istate, Expression e) } return null; } - if (e.op == TOK.structLiteral) + if (e.op == EXP.structLiteral) { // e.__postblit() UnionExp ue = void; @@ -7412,7 +7444,7 @@ private Expression evaluateDtor(InterState* istate, Expression e) foreach_reverse (elem; *ale.elements) e = evaluateDtor(istate, elem); } - else if (e.op == TOK.structLiteral) + else if (e.op == EXP.structLiteral) { // e.__dtor() e = interpretFunction(&ue, sd.dtor, istate, null, e); diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index c417f93..0659680 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -979,7 +979,7 @@ public: goto Lsa; } buf.writeByte('V'); - if (ea.op == TOK.tuple) + if (ea.op == EXP.tuple) { ea.error("tuple is not a valid template value argument"); continue; @@ -987,7 +987,7 @@ public: // 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) + if (ea.op == EXP.error || olderr != global.errors) continue; /* Use type mangling that matches what it would be for a function parameter diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 0925e7c..1f05642 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -522,14 +522,14 @@ private bool _isZeroInit(Expression exp) { switch (exp.op) { - case TOK.int64: + case EXP.int64: return exp.toInteger() == 0; - case TOK.null_: - case TOK.false_: + case EXP.null_: + case EXP.false_: return true; - case TOK.structLiteral: + case EXP.structLiteral: { auto sle = cast(StructLiteralExp) exp; foreach (i; 0 .. sle.sd.fields.dim) @@ -546,7 +546,7 @@ private bool _isZeroInit(Expression exp) return true; } - case TOK.arrayLiteral: + case EXP.arrayLiteral: { auto ale = cast(ArrayLiteralExp)exp; @@ -566,7 +566,7 @@ private bool _isZeroInit(Expression exp) return true; } - case TOK.string_: + case EXP.string_: { StringExp se = cast(StringExp)exp; @@ -581,14 +581,14 @@ private bool _isZeroInit(Expression exp) return true; } - case TOK.vector: + case EXP.vector: { auto ve = cast(VectorExp) exp; return _isZeroInit(ve.e1); } - case TOK.float64: - case TOK.complex80: + case EXP.float64: + case EXP.complex80: { import dmd.root.ctfloat : CTFloat; return (exp.toReal() is CTFloat.zero) && diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 9aa435d..b1d1b1d 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1785,11 +1785,11 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol Expression eold = null; for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e)) { - if (e.op == TOK.scope_) + if (e.op == EXP.scope_) { s = (cast(ScopeExp)e).sds; } - else if (e.op == TOK.type) + else if (e.op == EXP.type) { s = e.type.toDsymbol(null); } @@ -1826,14 +1826,14 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol 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 + // Discriminated using DYNCAST and, for expressions, also EXP 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); + assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array); this.sc = sc; this.arrayContent = exp; } @@ -1950,7 +1950,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol 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); + assert(exp.op == EXP.array || exp.op == EXP.slice); AggregateDeclaration ad = isAggregate(t); assert(ad); Dsymbol s = ad.search(loc, Id.opDollar); @@ -1962,11 +1962,11 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol if (TemplateDeclaration td = s.isTemplateDeclaration()) { dinteger_t dim = 0; - if (exp.op == TOK.array) + if (exp.op == EXP.array) { dim = (cast(ArrayExp)exp).currentDimension; } - else if (exp.op == TOK.slice) + else if (exp.op == EXP.slice) { dim = 0; // slices are currently always one-dimensional } @@ -1987,7 +1987,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol * 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) + if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.dim != 1) { exp.error("`%s` only defines opDollar for one dimension", ad.toChars()); return null; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 047c1eb..0bf9a80 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -133,7 +133,7 @@ AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc) 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) + if (e.op == EXP.error) errors = true; else { @@ -611,7 +611,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } Lnomatch: - if (ie && ie.op == TOK.tuple) + if (ie && ie.op == EXP.tuple) { auto te = ie.isTupleExp(); size_t tedim = te.exps.dim; @@ -652,6 +652,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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.overlapped = dsym.overlapped; + v.dsymbolSemantic(sc); if (sc.scopesym) @@ -879,11 +881,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if ((!dsym._init || dsym._init.isVoidInitializer) && !fd) { // If not mutable, initializable by constructor only - dsym.storage_class |= STC.ctorinit; + dsym.setInCtorOnly = true; } if (dsym._init) - dsym.storage_class |= STC.init; // remember we had an explicit initializer + { } // remember we had an explicit initializer else if (dsym.storage_class & STC.manifest) dsym.error("manifest constants must have initializers"); @@ -1013,7 +1015,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor exp = exp.expressionSemantic(sc); dsym.canassign--; exp = exp.optimize(WANTvalue); - if (exp.op == TOK.error) + if (exp.op == EXP.error) { dsym._init = new ErrorInitializer(); ei = null; @@ -1024,7 +1026,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (ei && dsym.isScope()) { Expression ex = ei.exp.lastComma(); - if (ex.op == TOK.blit || ex.op == TOK.construct) + if (ex.op == EXP.blit || ex.op == EXP.construct) ex = (cast(AssignExp)ex).e2; if (auto ne = ex.isNewExp()) { @@ -1057,7 +1059,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // 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) + if (init_err && init_err.exp.op == EXP.showCtfeContext) { errorSupplemental(dsym.loc, "compile time context created here"); } @@ -1085,7 +1087,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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())) + if (ei && (ei.exp.op != EXP.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage())) { if (ei.exp.type) { @@ -1241,7 +1243,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor width.error("bit-field `%s` has zero width", dsym.toChars()); dsym.errors = true; } - const max_width = dsym.type.size() * 8; + const sz = dsym.type.size(); + if (sz == SIZE_INVALID) + dsym.errors = true; + const max_width = sz * 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()); @@ -1459,7 +1464,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(AnonDeclaration scd) { - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + //printf("\tAnonDeclaration::semantic isunion:%d ptr:%p\n", scd.isunion, scd); assert(sc.parent); auto p = sc.parent.pastMixin(); auto ad = p.isAggregateDeclaration(); @@ -1479,6 +1484,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor for (size_t i = 0; i < scd.decl.dim; i++) { Dsymbol s = (*scd.decl)[i]; + if (auto var = s.isVarDeclaration) + { + if (scd.isunion) + var.overlapped = true; + } s.dsymbolSemantic(sc); } sc = sc.pop(); @@ -1651,7 +1661,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor e = resolveProperties(sc, e); sc = sc.endCTFE(); e = ctfeInterpretForPragmaMsg(e); - if (e.op == TOK.error) + if (e.op == EXP.error) { errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); return; @@ -2185,7 +2195,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor e = resolveProperties(sc, e); e = e.integralPromotions(sc); e = e.ctfeInterpret(); - if (e.op == TOK.error) + if (e.op == EXP.error) return errorReturn(em); auto ie = e.isIntegerExp(); if (!ie) @@ -2303,7 +2313,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor e = e.expressionSemantic(sc); e = resolveProperties(sc, e); e = e.ctfeInterpret(); - if (e.op == TOK.error) + if (e.op == EXP.error) return errorReturn(); if (first && !em.ed.memtype && !em.ed.isAnonymous()) { @@ -2331,7 +2341,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ev = ev.implicitCastTo(sc, em.ed.memtype); ev = ev.ctfeInterpret(); ev = ev.castTo(sc, em.ed.type); - if (ev.op == TOK.error) + if (ev.op == EXP.error) em.ed.errors = true; enm.value = ev; }); @@ -2429,7 +2439,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Set value to (eprev + 1). // But first check that (eprev != emax) assert(eprev); - Expression e = new EqualExp(TOK.equal, em.loc, eprev, emax); + Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); e = e.expressionSemantic(sc); e = e.ctfeInterpret(); if (e.toInteger()) @@ -2446,7 +2456,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor e = e.ctfeInterpret(); // save origValue (without cast) for better json output - if (e.op != TOK.error) // avoid duplicate diagnostics + if (e.op != EXP.error) // avoid duplicate diagnostics { assert(emprev.origValue); em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); @@ -2454,12 +2464,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor em.origValue = em.origValue.ctfeInterpret(); } - if (e.op == TOK.error) + if (e.op == EXP.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); + Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); etest = etest.expressionSemantic(sc); etest = etest.ctfeInterpret(); if (etest.toInteger()) @@ -4162,7 +4172,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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); + e = new EqualExp(EXP.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); @@ -4239,7 +4249,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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); + e = new EqualExp(EXP.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); @@ -4616,6 +4626,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (cldec.errors) cldec.type = Type.terror; + if (cldec.semanticRun == PASS.init) + cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class); cldec.type = cldec.type.typeSemantic(cldec.loc, sc); if (auto tc = cldec.type.isTypeClass()) if (tc.sym != cldec) @@ -6422,7 +6434,7 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc) s = getDsymbol(e); if (!s) { - if (e.op != TOK.error) + if (e.op != EXP.error) ds.error("cannot alias an expression `%s`", e.toChars()); return errorRet(); } @@ -6606,7 +6618,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) s = getDsymbol(e); if (!s) { - if (e.op != TOK.error) + if (e.op != EXP.error) ds.error("cannot alias an expression `%s`", e.toChars()); return errorRet(); } diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 9d7957a..5dedcba 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -144,7 +144,7 @@ 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); + return (e.op == EXP.error || !e.type || e.type.ty == Terror); if (const v = isTuple(o)) return arrayObjectIsError(&v.objects); const s = isDsymbol(o); @@ -297,8 +297,8 @@ private bool match(RootObject o1, RootObject o2) 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()); + printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars()); + printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars()); } // two expressions can be equal although they do not have the same @@ -421,26 +421,26 @@ private size_t expressionHash(Expression e) switch (e.op) { - case TOK.int64: + case EXP.int64: return cast(size_t) e.isIntegerExp().getInteger(); - case TOK.float64: + case EXP.float64: return CTFloat.hash(e.isRealExp().value); - case TOK.complex80: + case EXP.complex80: auto ce = e.isComplexExp(); return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary)); - case TOK.identifier: + case EXP.identifier: return cast(size_t)cast(void*) e.isIdentifierExp().ident; - case TOK.null_: + case EXP.null_: return cast(size_t)cast(void*) e.isNullExp().type; - case TOK.string_: + case EXP.string_: return calcHash(e.isStringExp.peekData()); - case TOK.tuple: + case EXP.tuple: { auto te = e.isTupleExp(); size_t hash = 0; @@ -450,7 +450,7 @@ private size_t expressionHash(Expression e) return hash; } - case TOK.arrayLiteral: + case EXP.arrayLiteral: { auto ae = e.isArrayLiteralExp(); size_t hash; @@ -459,7 +459,7 @@ private size_t expressionHash(Expression e) return hash; } - case TOK.assocArrayLiteral: + case EXP.assocArrayLiteral: { auto ae = e.isAssocArrayLiteralExp(); size_t hash; @@ -469,7 +469,7 @@ private size_t expressionHash(Expression e) return hash; } - case TOK.structLiteral: + case EXP.structLiteral: { auto se = e.isStructLiteralExp(); size_t hash; @@ -478,10 +478,10 @@ private size_t expressionHash(Expression e) return hash; } - case TOK.variable: + case EXP.variable: return cast(size_t)cast(void*) e.isVarExp().var; - case TOK.function_: + case EXP.function_: return cast(size_t)cast(void*) e.isFuncExp().fd; default: @@ -1629,7 +1629,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol farg = (*fargs)[argi + i]; // Check invalid arguments to detect errors early. - if (farg.op == TOK.error || farg.type.ty == Terror) + if (farg.op == EXP.error || farg.type.ty == Terror) return nomatch(); if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid) @@ -1825,7 +1825,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } { // Check invalid arguments to detect errors early. - if (farg.op == TOK.error || farg.type.ty == Terror) + if (farg.op == EXP.error || farg.type.ty == Terror) return nomatch(); Type att = null; @@ -1837,7 +1837,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } Type argtype = farg.type; - if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != TOK.function_) + if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != EXP.function_) return nomatch(); // https://issues.dlang.org/show_bug.cgi?id=12876 @@ -1853,17 +1853,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol 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_) + if (farg.op == EXP.string_) { StringExp se = cast(StringExp)farg; argtype = se.type.nextOf().sarrayOf(se.len); } - else if (farg.op == TOK.arrayLiteral) + else if (farg.op == EXP.arrayLiteral) { ArrayLiteralExp ae = cast(ArrayLiteralExp)farg; argtype = ae.type.nextOf().sarrayOf(ae.elements.dim); } - else if (farg.op == TOK.slice) + else if (farg.op == EXP.slice) { SliceExp se = cast(SliceExp)farg; if (Type tsa = toStaticArrayType(se)) @@ -1939,7 +1939,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { if (!farg.isLvalue()) { - if ((farg.op == TOK.string_ || farg.op == TOK.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) + if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] } @@ -2280,13 +2280,13 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Declaration d; VarDeclaration v = null; - if (ea && ea.op == TOK.type) + if (ea && ea.op == EXP.type) ta = ea.type; - else if (ea && ea.op == TOK.scope_) + else if (ea && ea.op == EXP.scope_) sa = (cast(ScopeExp)ea).sds; - else if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_)) + else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_)) sa = (cast(ThisExp)ea).var; - else if (ea && ea.op == TOK.function_) + else if (ea && ea.op == EXP.function_) { if ((cast(FuncExp)ea).td) sa = (cast(FuncExp)ea).td; @@ -3826,7 +3826,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (tparam.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)tparam; - if (tsa.dim.op == TOK.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter) + if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter) { Identifier id = (cast(VarExp)tsa.dim).var.ident; i = templateIdentifierLookup(id, parameters); @@ -4209,7 +4209,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* 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)) + if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter)) { /* * (T:Number!(e2), int e2) @@ -4847,9 +4847,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Reset inference target for the later re-semantic e.fd.treq = null; - if (ex.op == TOK.error) + if (ex.op == EXP.error) return; - if (ex.op != TOK.function_) + if (ex.op != EXP.function_) return; visit(ex.type); return; @@ -6642,13 +6642,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol else if (ea) { Lexpr: - //printf("+[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars()); + //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, 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)) + if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter)) { ea = ea.optimize(WANTvalue); } @@ -6659,7 +6659,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol ea = ea.expressionSemantic(sc); sc = sc.endCTFE(); - if (ea.op == TOK.variable) + if (ea.op == EXP.variable) { /* If the parameter is a function that is not called * explicitly, i.e. `foo!func` as opposed to `foo!func()`, @@ -6687,8 +6687,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol ea = ErrorExp.get(); } } - //printf("-[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars()); - if (ea.op == TOK.tuple) + //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars()); + if (ea.op == EXP.tuple) { // Expand tuple TupleExp te = cast(TupleExp)ea; @@ -6703,24 +6703,24 @@ extern (C++) class TemplateInstance : ScopeDsymbol j--; continue; } - if (ea.op == TOK.error) + if (ea.op == EXP.error) { err = true; continue; } (*tiargs)[j] = ea; - if (ea.op == TOK.type) + if (ea.op == EXP.type) { ta = ea.type; goto Ltype; } - if (ea.op == TOK.scope_) + if (ea.op == EXP.scope_) { sa = (cast(ScopeExp)ea).sds; goto Ldsym; } - if (ea.op == TOK.function_) + if (ea.op == EXP.function_) { FuncExp fe = cast(FuncExp)ea; /* A function literal, that is passed to template and @@ -6741,24 +6741,24 @@ extern (C++) class TemplateInstance : ScopeDsymbol //goto Ldsym; } } - if (ea.op == TOK.dotVariable && !(flags & 1)) + if (ea.op == EXP.dotVariable && !(flags & 1)) { // translate expression to dsymbol. sa = (cast(DotVarExp)ea).var; goto Ldsym; } - if (ea.op == TOK.template_) + if (ea.op == EXP.template_) { sa = (cast(TemplateExp)ea).td; goto Ldsym; } - if (ea.op == TOK.dotTemplateDeclaration && !(flags & 1)) + if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1)) { // translate expression to dsymbol. sa = (cast(DotTemplateExp)ea).td; goto Ldsym; } - if (ea.op == TOK.dot) + if (ea.op == EXP.dot) { if (auto se = (cast(DotExp)ea).e2.isScopeExp()) { @@ -7256,17 +7256,17 @@ extern (C++) class TemplateInstance : ScopeDsymbol Tuple va = isTuple(o); if (ea) { - if (ea.op == TOK.variable) + if (ea.op == EXP.variable) { sa = (cast(VarExp)ea).var; goto Lsa; } - if (ea.op == TOK.this_) + if (ea.op == EXP.this_) { sa = (cast(ThisExp)ea).var; goto Lsa; } - if (ea.op == TOK.function_) + if (ea.op == EXP.function_) { if ((cast(FuncExp)ea).td) sa = (cast(FuncExp)ea).td; @@ -7275,7 +7275,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol 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) + if (ea.op != EXP.int64 && ea.op != EXP.float64 && ea.op != EXP.complex80 && ea.op != EXP.null_ && ea.op != EXP.string_ && ea.op != EXP.arrayLiteral && ea.op != EXP.assocArrayLiteral && ea.op != EXP.structLiteral) { ea.error("expression `%s` is not a valid template value argument", ea.toChars()); errors = true; @@ -7319,6 +7319,19 @@ extern (C++) class TemplateInstance : ScopeDsymbol goto L1; // dparent is most nested } } + //https://issues.dlang.org/show_bug.cgi?id=17870 + if (dparent.isClassDeclaration() && enclosing.isClassDeclaration()) + { + auto pc = dparent.isClassDeclaration(); + auto ec = enclosing.isClassDeclaration(); + if (pc.isBaseOf(ec, null)) + goto L1; + else if (ec.isBaseOf(pc, null)) + { + enclosing = dparent; + goto L1; + } + } error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars()); errors = true; } @@ -7584,15 +7597,15 @@ void unSpeculative(Scope* sc, RootObject o) 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) + if (e.op == EXP.tuple || e.op == EXP.scope_ || + e.op == EXP.type || e.op == EXP.dotType || + e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration || + e.op == EXP.function_ || e.op == EXP.error || + e.op == EXP.this_ || e.op == EXP.super_ || + e.op == EXP.dot) return false; - if (e.op != TOK.dotVariable) + if (e.op != EXP.dotVariable) return true; /* Template instantiations involving a DotVar expression are difficult. @@ -7606,20 +7619,20 @@ bool definitelyValueParameter(Expression e) if (f) return false; - while (e.op == TOK.dotVariable) + while (e.op == EXP.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_) + if (e.op == EXP.this_ || e.op == EXP.super_) return false; // e.type.x could be an alias - if (e.op == TOK.dotType) + if (e.op == EXP.dotType) return false; // var.x.y is the only other possible form of alias - if (e.op != TOK.variable) + if (e.op != EXP.variable) return true; VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); @@ -8010,7 +8023,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ uint olderrors = global.startGagging(); ei = resolveProperties(sc, ei); ei = ei.ctfeInterpret(); - if (global.endGagging(olderrors) || ei.op == TOK.error) + if (global.endGagging(olderrors) || ei.op == EXP.error) return matchArgNoMatch(); /* https://issues.dlang.org/show_bug.cgi?id=14520 @@ -8032,7 +8045,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ m = MATCH.convert; } - if (ei && ei.op == TOK.variable) + if (ei && ei.op == EXP.variable) { // Resolve const variables that we had skipped earlier ei = ei.ctfeInterpret(); @@ -8110,9 +8123,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ 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_)) + if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_)) sa = (cast(ThisExp)ea).var; - else if (ea && ea.op == TOK.scope_) + else if (ea && ea.op == EXP.scope_) sa = (cast(ScopeExp)ea).sds; if (sa) { diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index e19adfc..51f53c8 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -21,6 +21,7 @@ import dmd.attrib; import dmd.dsymbol; import dmd.errors; import dmd.globals; +import dmd.hdrgen; import dmd.identifier; import dmd.root.filename; import dmd.visitor; @@ -2395,7 +2396,7 @@ public: { debug (Debug_DtoH) mixin(traceVisit!e); - buf.writestring(tokToString(e.op)); + buf.writestring(expToString(e.op)); e.e1.accept(this); } @@ -2405,20 +2406,20 @@ public: e.e1.accept(this); buf.writeByte(' '); - buf.writestring(tokToString(e.op)); + buf.writestring(expToString(e.op)); buf.writeByte(' '); e.e2.accept(this); } /// Translates operator `op` into the C++ representation - private extern(D) static string tokToString(const TOK op) + private extern(D) static string expToString(const EXP op) { - switch (op) with (TOK) + switch (op) with (EXP) { case identity: return "=="; case notIdentity: return "!="; default: - return Token.toString(op); + return EXPtoString(op); } } diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index d502f80..62f87e5 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -536,8 +536,8 @@ 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) + if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct && + e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign) return false; auto ae = cast(BinExp)e; Expression e1 = ae.e1; @@ -568,7 +568,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) VarDeclaration va = expToVariable(e1); - if (va && e.op == TOK.concatenateElemAssign) + if (va && e.op == EXP.concatenateElemAssign) { /* https://issues.dlang.org/show_bug.cgi?id=17842 * Draw an equivalence between: @@ -596,11 +596,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) 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 && @@ -677,7 +672,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) if (va.isScope()) continue; - if (inferScope && !va.doNotInferScope) + if (!va.doNotInferScope) { if (log) printf("inferring scope for lvalue %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; @@ -713,7 +708,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) if (va && !va.isDataseg() && !va.doNotInferScope) { - if (!va.isScope() && inferScope) + if (!va.isScope()) { /* v is scope, and va is not scope, so va needs to * infer scope */ @@ -749,7 +744,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) { if (va && !va.isDataseg() && !va.doNotInferScope) { - if (!va.isScope() && inferScope) + if (!va.isScope()) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; } @@ -840,7 +835,7 @@ ByRef: if (va && !va.isDataseg() && !va.doNotInferScope) { - if (!va.isScope() && inferScope) + if (!va.isScope()) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; } @@ -848,7 +843,7 @@ ByRef: va.storage_class |= STC.return_ | STC.returninferred; continue; } - if (e1.op == TOK.structLiteral) + if (e1.op == EXP.structLiteral) continue; if (fd.setUnsafe()) { @@ -890,7 +885,7 @@ ByRef: /* Don't infer STC.scope_ for va, because then a closure * won't be generated for fd. */ - //if (!va.isScope() && inferScope) + //if (!va.isScope()) //va.storage_class |= STC.scope_ | STC.scopeinferred; continue; } @@ -909,7 +904,7 @@ ByRef: /* 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() && + if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() && !(va && va.storage_class & STC.temp)) { if (!gag) @@ -919,7 +914,7 @@ ByRef: continue; } - if (ee.op == TOK.call && ee.type.toBasetype().isTypeStruct() && + if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() && (!va || !(va.storage_class & STC.temp)) && fd.setUnsafe()) { @@ -930,7 +925,7 @@ ByRef: continue; } - if (ee.op == TOK.structLiteral && + if (ee.op == EXP.structLiteral && (!va || !(va.storage_class & STC.temp)) && fd.setUnsafe()) { @@ -943,7 +938,7 @@ ByRef: if (va && !va.isDataseg() && !va.doNotInferScope) { - if (!va.isScope() && inferScope) + if (!va.isScope()) { //printf("inferring scope for %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; } @@ -993,17 +988,13 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag) if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown // despite being `scope` { - if (sc._module && sc._module.isRoot()) + if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029 { - // 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; + if (!gag) + error(e.loc, "scope variable `%s` may not be thrown", v.toChars()); + result = true; } + continue; } else { @@ -1051,7 +1042,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) if (v.isScope()) { - if (sc._module && sc._module.isRoot() && + if ( /* This case comes up when the ReturnStatement of a __foreachbody is * checked for escapes by the caller of __foreachbody. Skip it. * @@ -1128,9 +1119,6 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) 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) @@ -1264,7 +1252,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) continue; auto pfunc = p.isFuncDeclaration(); - if (pfunc && sc._module && sc._module.isRoot() && + if (pfunc && /* This case comes up when the ReturnStatement of a __foreachbody is * checked for escapes by the caller of __foreachbody. Skip it. * @@ -1284,7 +1272,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) ) { // 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 + // https://issues.dlang.org/show_bug.cgi?id=17029 + if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) { if (!gag) error(e.loc, "scope variable `%s` may not be returned", v.toChars()); @@ -1398,7 +1387,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { inferReturn(sc.func, v); // infer addition of 'return' } - else if (sc._module && sc._module.isRoot()) + else { // https://dlang.org/spec/function.html#return-ref-parameters // Only look for errors if in module listed on command line @@ -1528,7 +1517,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) * 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) + if (e.e1.op != EXP.structLiteral) escapeByRef(e.e1, er, live); } @@ -1768,7 +1757,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) } } // If 'this' is returned, check it too - if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction) + if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) { DotVarExp dve = e.e1.isDotVarExp(); FuncDeclaration fd = dve.var.isFuncDeclaration(); @@ -2024,7 +2013,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) } } // If 'this' is returned by ref, check it too - if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction) + if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) { DotVarExp dve = e.e1.isDotVarExp(); @@ -2051,7 +2040,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) } } // If it's a delegate, check it too - if (e.e1.op == TOK.variable && t1.ty == Tdelegate) + if (e.e1.op == EXP.variable && t1.ty == Tdelegate) { escapeByValue(e.e1, er, live); } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 2a62332..e6b7e30 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -60,6 +60,7 @@ import dmd.optimize; import dmd.root.ctfloat; import dmd.root.filename; import dmd.common.outbuffer; +import dmd.root.optional; import dmd.root.rmem; import dmd.root.rootobject; import dmd.root.string; @@ -116,7 +117,7 @@ enum ModifyFlags inout(Expression) firstComma(inout Expression e) { Expression ex = cast()e; - while (ex.op == TOK.comma) + while (ex.op == EXP.comma) ex = (cast(CommaExp)ex).e1; return cast(inout)ex; @@ -133,7 +134,7 @@ inout(Expression) firstComma(inout Expression e) inout(Expression) lastComma(inout Expression e) { Expression ex = cast()e; - while (ex.op == TOK.comma) + while (ex.op == EXP.comma) ex = (cast(CommaExp)ex).e2; return cast(inout)ex; @@ -286,7 +287,7 @@ extern (C++) void expandTuples(Expressions* exps) } // Inline expand all the tuples - while (arg.op == TOK.tuple) + while (arg.op == EXP.tuple) { TupleExp te = cast(TupleExp)arg; exps.remove(i); // remove arg @@ -356,7 +357,7 @@ int expandAliasThisTuples(Expressions* exps, size_t starti = 0) printf("expansion ->\n"); foreach (e; exps) { - printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars()); + printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars()); } } return cast(int)u; @@ -528,15 +529,15 @@ extern (C++) struct UnionExp extern (C++) Expression copy() { Expression e = exp(); - //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op)); + //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr); 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; + case EXP.cantExpression: return CTFEExp.cantexp; + case EXP.voidExpression: return CTFEExp.voidexp; + case EXP.break_: return CTFEExp.breakexp; + case EXP.continue_: return CTFEExp.continueexp; + case EXP.goto_: return CTFEExp.gotoexp; default: return e.copy(); } } @@ -610,14 +611,14 @@ VarDeclaration expToVariable(Expression e) { switch (e.op) { - case TOK.variable: + case EXP.variable: return (cast(VarExp)e).var.isVarDeclaration(); - case TOK.dotVariable: + case EXP.dotVariable: e = (cast(DotVarExp)e).e1; continue; - case TOK.index: + case EXP.index: { IndexExp ei = cast(IndexExp)e; e = ei.e1; @@ -627,7 +628,7 @@ VarDeclaration expToVariable(Expression e) return null; } - case TOK.slice: + case EXP.slice: { SliceExp ei = cast(SliceExp)e; e = ei.e1; @@ -637,8 +638,8 @@ VarDeclaration expToVariable(Expression e) return null; } - case TOK.this_: - case TOK.super_: + case EXP.this_: + case EXP.super_: return (cast(ThisExp)e).var.isVarDeclaration(); default: @@ -662,13 +663,13 @@ enum WANTexpand = 1; // expand const/immutable variables if possible */ extern (C++) abstract class Expression : ASTNode { - const TOK op; // to minimize use of dynamic_cast + const EXP 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) + extern (D) this(const ref Loc loc, EXP op, int size) { //printf("Expression::Expression(op = %d) this = %p\n", op, this); this.loc = loc; @@ -678,12 +679,12 @@ extern (C++) abstract class Expression : ASTNode 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); + CTFEExp.cantexp = new CTFEExp(EXP.cantExpression); + CTFEExp.voidexp = new CTFEExp(EXP.voidExpression); + CTFEExp.breakexp = new CTFEExp(EXP.break_); + CTFEExp.continueexp = new CTFEExp(EXP.continue_); + CTFEExp.gotoexp = new CTFEExp(EXP.goto_); + CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext); } /** @@ -874,13 +875,13 @@ extern (C++) abstract class Expression : ASTNode */ extern (D) static Expression extractLast(Expression e, out Expression e0) { - if (e.op != TOK.comma) + if (e.op != EXP.comma) { return e; } CommaExp ce = cast(CommaExp)e; - if (ce.e2.op != TOK.comma) + if (ce.e2.op != EXP.comma) { e0 = ce.e1; return ce.e2; @@ -890,11 +891,11 @@ extern (C++) abstract class Expression : ASTNode e0 = e; Expression* pce = &ce.e2; - while ((cast(CommaExp)(*pce)).e2.op == TOK.comma) + while ((cast(CommaExp)(*pce)).e2.op == EXP.comma) { pce = &(cast(CommaExp)(*pce)).e2; } - assert((*pce).op == TOK.comma); + assert((*pce).op == EXP.comma); ce = cast(CommaExp)(*pce); *pce = ce.e1; @@ -918,14 +919,14 @@ extern (C++) abstract class Expression : ASTNode dinteger_t toInteger() { - //printf("Expression %s\n", Token::toChars(op)); + //printf("Expression %s\n", EXPtoString(op).ptr); error("integer constant expression expected instead of `%s`", toChars()); return 0; } uinteger_t toUInteger() { - //printf("Expression %s\n", Token::toChars(op)); + //printf("Expression %s\n", EXPtoString(op).ptr); return cast(uinteger_t)toInteger(); } @@ -976,7 +977,7 @@ extern (C++) abstract class Expression : ASTNode else if (!loc.isValid()) loc = e.loc; - if (e.op == TOK.type) + if (e.op == EXP.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()); @@ -1079,7 +1080,7 @@ extern (C++) abstract class Expression : ASTNode extern (D) final bool checkScalar() { - if (op == TOK.error) + if (op == EXP.error) return true; if (type.toBasetype().ty == Terror) return true; @@ -1093,7 +1094,7 @@ extern (C++) abstract class Expression : ASTNode extern (D) final bool checkNoBool() { - if (op == TOK.error) + if (op == EXP.error) return true; if (type.toBasetype().ty == Terror) return true; @@ -1107,7 +1108,7 @@ extern (C++) abstract class Expression : ASTNode extern (D) final bool checkIntegral() { - if (op == TOK.error) + if (op == EXP.error) return true; if (type.toBasetype().ty == Terror) return true; @@ -1121,7 +1122,7 @@ extern (C++) abstract class Expression : ASTNode extern (D) final bool checkArithmetic() { - if (op == TOK.error) + if (op == EXP.error) return true; if (type.toBasetype().ty == Terror) return true; @@ -1492,9 +1493,9 @@ extern (C++) abstract class Expression : ASTNode extern (D) final bool checkRightThis(Scope* sc) { - if (op == TOK.error) + if (op == EXP.error) return true; - if (op == TOK.variable && type.ty != Terror) + if (op == EXP.variable && type.ty != Terror) { VarExp ve = cast(VarExp)this; if (isNeedThisScope(sc, ve.var)) @@ -1513,7 +1514,7 @@ extern (C++) abstract class Expression : ASTNode * 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) + extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null) { //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass()) @@ -1522,13 +1523,13 @@ extern (C++) abstract class Expression : ASTNode // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. switch (rmwOp) { - case TOK.plusPlus: - case TOK.prePlusPlus: - rmwOp = TOK.addAssign; + case EXP.plusPlus: + case EXP.prePlusPlus: + rmwOp = EXP.addAssign; break; - case TOK.minusMinus: - case TOK.preMinusMinus: - rmwOp = TOK.minAssign; + case EXP.minusMinus: + case EXP.preMinusMinus: + rmwOp = EXP.minAssign; break; default: break; @@ -1536,7 +1537,7 @@ extern (C++) abstract class Expression : ASTNode 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"); + EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1"); return true; } @@ -1558,7 +1559,7 @@ extern (C++) abstract class Expression : ASTNode //printf("Expression::addressOf()\n"); debug { - assert(op == TOK.error || isLvalue()); + assert(op == EXP.error || isLvalue()); } Expression e = new AddrExp(loc, this, type.pointerTo()); return e; @@ -1597,12 +1598,11 @@ extern (C++) abstract class Expression : ASTNode return .isConst(this); } - /******************************** - * Does this expression statically evaluate to a boolean 'result' (true or false)? - */ - bool isBool(bool result) + /// Statically evaluate this expression to a `bool` if possible + /// Returns: an optional thath either contains the value or is empty + Optional!bool toBool() { - return false; + return typeof(return)(); } bool hasCode() @@ -1612,127 +1612,127 @@ extern (C++) abstract class Expression : ASTNode 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 + inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; } + inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; } + inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; } + inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; } + inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; } + inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; } + inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; } + inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; } + inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; } + inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; } + inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; } + inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; } + inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; } + inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; } + inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; } + inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; } + inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; } + inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; } + inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; } + inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; } + inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; } + inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; } + inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; } + inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; } + inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; } + inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; } + inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; } + inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; } + inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; } + inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; } + inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; } + inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; } + inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; } + inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; } + inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; } + inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; } + inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; } + inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; } + inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; } + inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; } + inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; } + inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; } + inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; } + inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; } + inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; } + inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; } + inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; } + inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; } + inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; } + inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; } + inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; } + inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; } + inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; } + inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; } + inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; } + inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; } + inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; } + inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; } + inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; } + inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; } + inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; } + inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; } + inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; } + inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; } + inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; } + inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; } + inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; } + inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; } + + inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; } + inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; } + inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; } + inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; } + inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; } + inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; } + + inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; } + inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; } + inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; } + + inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign ? cast(typeof(return))this : null; } - inout(CatElemAssignExp) isCatElemAssignExp() { return op == TOK.concatenateElemAssign + inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign ? cast(typeof(return))this : null; } - inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == TOK.concatenateDcharAssign + inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.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(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; } + inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; } + inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; } + inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; } + inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; } + inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; } + inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; } + inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; } + inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; } + inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; } + inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; } + inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; } + inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; } + inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; } + //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; } + inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; } + inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; } + inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; } + inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; } + inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; } + inout(GenericExp) isGenericExp() { return op == EXP._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(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; } + inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; } + inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; } + inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; } + inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; } + inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; } + inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; } } inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc @@ -1754,7 +1754,7 @@ extern (C++) final class IntegerExp : Expression extern (D) this(const ref Loc loc, dinteger_t value, Type type) { - super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp)); + super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp)); //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : ""); assert(type); if (!type.isscalar()) @@ -1770,7 +1770,7 @@ extern (C++) final class IntegerExp : Expression extern (D) this(dinteger_t value) { - super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp)); + super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp)); this.type = Type.tint32; this.value = cast(d_int32)value; } @@ -1827,10 +1827,10 @@ extern (C++) final class IntegerExp : Expression return complex_t(toReal()); } - override bool isBool(bool result) + override Optional!bool toBool() { bool r = toInteger() != 0; - return result ? r : !r; + return typeof(return)(r); } override Expression toLvalue(Scope* sc, Expression e) @@ -1969,7 +1969,7 @@ extern (C++) final class ErrorExp : Expression { private extern (D) this() { - super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp)); + super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp)); type = Type.terror; } @@ -2015,7 +2015,7 @@ extern (C++) final class VoidInitExp : Expression extern (D) this(VarDeclaration var) { - super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp)); + super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp)); this.var = var; this.type = var.type; } @@ -2040,7 +2040,7 @@ extern (C++) final class RealExp : Expression extern (D) this(const ref Loc loc, real_t value, Type type) { - super(loc, TOK.float64, __traits(classInstanceSize, RealExp)); + super(loc, EXP.float64, __traits(classInstanceSize, RealExp)); //printf("RealExp::RealExp(%Lg)\n", value); this.value = value; this.type = type; @@ -2096,9 +2096,9 @@ extern (C++) final class RealExp : Expression return complex_t(toReal(), toImaginary()); } - override bool isBool(bool result) + override Optional!bool toBool() { - return result ? cast(bool)value : !cast(bool)value; + return typeof(return)(!!value); } override void accept(Visitor v) @@ -2115,7 +2115,7 @@ extern (C++) final class ComplexExp : Expression extern (D) this(const ref Loc loc, complex_t value, Type type) { - super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp)); + super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp)); this.value = value; this.type = type; //printf("ComplexExp::ComplexExp(%s)\n", toChars()); @@ -2171,12 +2171,9 @@ extern (C++) final class ComplexExp : Expression return value; } - override bool isBool(bool result) + override Optional!bool toBool() { - if (result) - return cast(bool)value; - else - return !value; + return typeof(return)(!!value); } override void accept(Visitor v) @@ -2193,7 +2190,7 @@ extern (C++) class IdentifierExp : Expression extern (D) this(const ref Loc loc, Identifier ident) { - super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp)); + super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp)); this.ident = ident; } @@ -2243,7 +2240,7 @@ extern (C++) final class DsymbolExp : Expression extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) { - super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp)); + super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp)); this.s = s; this.hasOverloads = hasOverloads; } @@ -2273,11 +2270,11 @@ extern (C++) class ThisExp : Expression extern (D) this(const ref Loc loc) { - super(loc, TOK.this_, __traits(classInstanceSize, ThisExp)); + super(loc, EXP.this_, __traits(classInstanceSize, ThisExp)); //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); } - this(const ref Loc loc, const TOK tok) + this(const ref Loc loc, const EXP tok) { super(loc, tok, __traits(classInstanceSize, ThisExp)); //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); @@ -2292,9 +2289,10 @@ extern (C++) class ThisExp : Expression return r; } - override final bool isBool(bool result) + override Optional!bool toBool() { - return result; + // `this` is never null (what about structs?) + return typeof(return)(true); } override final bool isLvalue() @@ -2326,7 +2324,7 @@ extern (C++) final class SuperExp : ThisExp { extern (D) this(const ref Loc loc) { - super(loc, TOK.super_); + super(loc, EXP.super_); } override void accept(Visitor v) @@ -2342,7 +2340,7 @@ extern (C++) final class NullExp : Expression { extern (D) this(const ref Loc loc, Type type = null) { - super(loc, TOK.null_, __traits(classInstanceSize, NullExp)); + super(loc, EXP.null_, __traits(classInstanceSize, NullExp)); this.type = type; } @@ -2350,7 +2348,7 @@ extern (C++) final class NullExp : Expression { if (auto e = o.isExpression()) { - if (e.op == TOK.null_ && type.equals(e.type)) + if (e.op == EXP.null_ && type.equals(e.type)) { return true; } @@ -2358,9 +2356,10 @@ extern (C++) final class NullExp : Expression return false; } - override bool isBool(bool result) + override Optional!bool toBool() { - return result ? false : true; + // null in any type is false + return typeof(return)(false); } override StringExp toStringExp() @@ -2400,7 +2399,7 @@ extern (C++) final class StringExp : Expression extern (D) this(const ref Loc loc, const(void)[] string) { - super(loc, TOK.string_, __traits(classInstanceSize, StringExp)); + super(loc, EXP.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 @@ -2408,7 +2407,7 @@ extern (C++) final class StringExp : Expression 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)); + super(loc, EXP.string_, __traits(classInstanceSize, StringExp)); this.string = cast(char*)string.ptr; // note that this.string should be const this.len = len; this.sz = sz; @@ -2681,9 +2680,11 @@ extern (C++) final class StringExp : Expression return cast(int)(len1 - len2); } - override bool isBool(bool result) + override Optional!bool toBool() { - return result; + // Keep the old behaviour for this refactoring + // Should probably match language spec instead and check for length + return typeof(return)(true); } override bool isLvalue() @@ -2810,7 +2811,7 @@ extern (C++) final class TupleExp : Expression extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) { - super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp)); + super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp)); //printf("TupleExp(this = %p)\n", this); this.e0 = e0; this.exps = exps; @@ -2818,14 +2819,14 @@ extern (C++) final class TupleExp : Expression extern (D) this(const ref Loc loc, Expressions* exps) { - super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp)); + super(loc, EXP.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)); + super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp)); this.exps = new Expressions(); this.exps.reserve(tup.objects.dim); @@ -2919,14 +2920,14 @@ extern (C++) final class ArrayLiteralExp : Expression extern (D) this(const ref Loc loc, Type type, Expressions* elements) { - super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); + super(loc, EXP.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)); + super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); this.type = type; elements = new Expressions(); elements.push(e); @@ -2934,7 +2935,7 @@ extern (C++) final class ArrayLiteralExp : Expression extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) { - super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); + super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); this.type = type; this.basis = basis; this.elements = elements; @@ -3000,10 +3001,10 @@ extern (C++) final class ArrayLiteralExp : Expression return el ? el : basis; } - override bool isBool(bool result) + override Optional!bool toBool() { size_t dim = elements ? elements.dim : 0; - return result ? (dim != 0) : (dim == 0); + return typeof(return)(dim != 0); } override StringExp toStringExp() @@ -3023,7 +3024,7 @@ extern (C++) final class ArrayLiteralExp : Expression foreach (i; 0 .. elements.dim) { auto ch = this[i]; - if (ch.op != TOK.int64) + if (ch.op != EXP.int64) return null; if (sz == 1) buf.writeByte(cast(uint)ch.toInteger()); @@ -3079,7 +3080,7 @@ extern (C++) final class AssocArrayLiteralExp : Expression extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) { - super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp)); + super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp)); assert(keys.dim == values.dim); this.keys = keys; this.values = values; @@ -3119,10 +3120,10 @@ extern (C++) final class AssocArrayLiteralExp : Expression return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values)); } - override bool isBool(bool result) + override Optional!bool toBool() { size_t dim = keys.dim; - return result ? (dim != 0) : (dim == 0); + return typeof(return)(dim != 0); } override void accept(Visitor v) @@ -3172,7 +3173,7 @@ extern (C++) final class StructLiteralExp : Expression extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) { - super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp)); + super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp)); this.sd = sd; if (!elements) elements = new Expressions(); @@ -3278,9 +3279,12 @@ extern (C++) final class StructLiteralExp : Expression */ if (elements.dim) { + const sz = type.size(); + if (sz == SIZE_INVALID) + return -1; foreach (i, v; sd.fields) { - if (offset == v.offset && type.size() == v.type.size()) + if (offset == v.offset && sz == v.type.size()) { /* context fields might not be filled. */ if (i >= sd.nonHiddenFields()) @@ -3348,7 +3352,7 @@ extern (C++) final class CompoundLiteralExp : Expression extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) { - super(loc, TOK.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp)); + super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp)); super.type = type_name; this.initializer = initializer; //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars()); @@ -3367,7 +3371,7 @@ extern (C++) final class TypeExp : Expression { extern (D) this(const ref Loc loc, Type type) { - super(loc, TOK.type, __traits(classInstanceSize, TypeExp)); + super(loc, EXP.type, __traits(classInstanceSize, TypeExp)); //printf("TypeExp::TypeExp(%s)\n", type.toChars()); this.type = type; } @@ -3409,7 +3413,7 @@ extern (C++) final class ScopeExp : Expression extern (D) this(const ref Loc loc, ScopeDsymbol sds) { - super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp)); + super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp)); //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars()); //static int count; if (++count == 38) *(char*)0=0; this.sds = sds; @@ -3464,7 +3468,7 @@ extern (C++) final class TemplateExp : Expression extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) { - super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp)); + super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp)); //printf("TemplateExp(): %s\n", td.toChars()); this.td = td; this.fd = fd; @@ -3519,7 +3523,7 @@ extern (C++) final class NewExp : Expression extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments) { - super(loc, TOK.new_, __traits(classInstanceSize, NewExp)); + super(loc, EXP.new_, __traits(classInstanceSize, NewExp)); this.thisexp = thisexp; this.newargs = newargs; this.newtype = newtype; @@ -3558,7 +3562,7 @@ extern (C++) final class NewAnonClassExp : Expression extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments) { - super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp)); + super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp)); this.thisexp = thisexp; this.newargs = newargs; this.cd = cd; @@ -3584,7 +3588,7 @@ extern (C++) class SymbolExp : Expression Dsymbol originalScope; // original scope before inlining bool hasOverloads; - extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads) + extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads) { super(loc, op, size); assert(var); @@ -3615,13 +3619,13 @@ extern (C++) final class SymOffExp : SymbolExp .error(loc, "need `this` for address of `%s`", v.toChars()); hasOverloads = false; } - super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads); + super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads); this.offset = offset; } - override bool isBool(bool result) + override Optional!bool toBool() { - return result ? true : false; + return typeof(return)(true); } override void accept(Visitor v) @@ -3641,7 +3645,7 @@ extern (C++) final class VarExp : SymbolExp if (var.isVarDeclaration()) hasOverloads = false; - super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads); + super(loc, EXP.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; @@ -3725,7 +3729,7 @@ extern (C++) final class OverExp : Expression extern (D) this(const ref Loc loc, OverloadSet s) { - super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp)); + super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp)); //printf("OverExp(this = %p, '%s')\n", this, var.toChars()); vars = s; type = Type.tvoid; @@ -3755,11 +3759,11 @@ extern (C++) final class FuncExp : Expression { FuncLiteralDeclaration fd; TemplateDeclaration td; - TOK tok; + TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_ extern (D) this(const ref Loc loc, Dsymbol s) { - super(loc, TOK.function_, __traits(classInstanceSize, FuncExp)); + super(loc, EXP.function_, __traits(classInstanceSize, FuncExp)); this.td = s.isTemplateDeclaration(); this.fd = s.isFuncLiteralDeclaration(); if (td) @@ -3927,7 +3931,7 @@ extern (C++) final class FuncExp : Expression // Reset inference target for the later re-semantic fd.treq = null; - if (ex.op == TOK.error) + if (ex.op == EXP.error) return MATCH.nomatch; if (auto ef = ex.isFuncExp()) return ef.matchType(to, sc, presult, flag); @@ -4057,7 +4061,7 @@ extern (C++) final class DeclarationExp : Expression extern (D) this(const ref Loc loc, Dsymbol declaration) { - super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp)); + super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp)); this.declaration = declaration; } @@ -4090,7 +4094,7 @@ extern (C++) final class TypeidExp : Expression extern (D) this(const ref Loc loc, RootObject o) { - super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp)); + super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp)); this.obj = o; } @@ -4115,7 +4119,7 @@ extern (C++) final class TraitsExp : Expression extern (D) this(const ref Loc loc, Identifier ident, Objects* args) { - super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp)); + super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp)); this.ident = ident; this.args = args; } @@ -4137,7 +4141,7 @@ extern (C++) final class HaltExp : Expression { extern (D) this(const ref Loc loc) { - super(loc, TOK.halt, __traits(classInstanceSize, HaltExp)); + super(loc, EXP.halt, __traits(classInstanceSize, HaltExp)); } override void accept(Visitor v) @@ -4161,7 +4165,7 @@ extern (C++) final class IsExp : Expression 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)); + super(loc, EXP.is_, __traits(classInstanceSize, IsExp)); this.targ = targ; this.id = id; this.tok = tok; @@ -4196,7 +4200,7 @@ 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) + extern (D) this(const ref Loc loc, EXP op, int size, Expression e1) { super(loc, op, size); this.e1 = e1; @@ -4221,13 +4225,13 @@ extern (C++) abstract class UnaExp : Expression if (e1.type.toBasetype() == Type.terror) return e1; - if (e1.op == TOK.type) + if (e1.op == EXP.type) { - error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op)); + error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr); } else { - error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars()); + error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars()); } return ErrorExp.get(); } @@ -4257,7 +4261,7 @@ extern (C++) abstract class UnaExp : Expression } alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression); -alias fp2_t = bool function(const ref Loc loc, TOK, Expression, Expression); +alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression); /*********************************************************** */ @@ -4268,7 +4272,7 @@ extern (C++) abstract class BinExp : Expression 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) + extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) { super(loc, op, size); this.e1 = e1; @@ -4298,22 +4302,22 @@ extern (C++) abstract class BinExp : Expression 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) + const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr; + if (e1.op == EXP.type || e2.op == EXP.type) { error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types", - e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op)); + e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr); } 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()); + e1.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]); + e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]); } return ErrorExp.get(); } @@ -4327,22 +4331,22 @@ extern (C++) abstract class BinExp : Expression // 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 (op == EXP.addAssign || op == EXP.minAssign || + op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || + op == EXP.powAssign) { if ((type.isintegral() && t2.isfloating())) { - warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars()); + warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars()); } } // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary - if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign) + if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.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); + const(char)* opstr = EXPtoString(op).ptr; 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()); @@ -4361,13 +4365,13 @@ extern (C++) abstract class BinExp : Expression } // generate an error if this is a nonsensical += or -=, eg real += imaginary - if (op == TOK.addAssign || op == TOK.minAssign) + if (op == EXP.addAssign || op == EXP.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()); + error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars()); return ErrorExp.get(); } if (type.isreal() || type.isimaginary()) @@ -4376,7 +4380,7 @@ extern (C++) abstract class BinExp : Expression e2 = e2.castTo(sc, t1); } } - if (op == TOK.mulAssign) + if (op == EXP.mulAssign) { if (t2.isfloating()) { @@ -4413,7 +4417,7 @@ extern (C++) abstract class BinExp : Expression } } } - else if (op == TOK.divAssign) + else if (op == EXP.divAssign) { if (t2.isimaginary()) { @@ -4454,7 +4458,7 @@ extern (C++) abstract class BinExp : Expression } } } - else if (op == TOK.modAssign) + else if (op == EXP.modAssign) { if (t2.iscomplex()) { @@ -4558,7 +4562,7 @@ extern (C++) abstract class BinExp : Expression */ extern (C++) class BinAssignExp : BinExp { - extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) { super(loc, op, size, e1, e2); } @@ -4600,7 +4604,7 @@ extern (C++) final class MixinExp : Expression extern (D) this(const ref Loc loc, Expressions* exps) { - super(loc, TOK.mixin_, __traits(classInstanceSize, MixinExp)); + super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp)); this.exps = exps; } @@ -4643,7 +4647,7 @@ extern (C++) final class ImportExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e); + super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e); } override void accept(Visitor v) @@ -4661,7 +4665,7 @@ extern (C++) final class AssertExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Expression msg = null) { - super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e); + super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e); this.msg = msg; } @@ -4687,7 +4691,7 @@ extern (C++) final class DotIdExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Identifier ident) { - super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e); + super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e); this.ident = ident; } @@ -4711,7 +4715,7 @@ extern (C++) final class DotTemplateExp : UnaExp extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) { - super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e); + super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e); this.td = td; } @@ -4745,7 +4749,7 @@ extern (C++) final class DotVarExp : UnaExp if (var.isVarDeclaration()) hasOverloads = false; - super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e); + super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e); //printf("DotVarExp()\n"); this.var = var; this.hasOverloads = hasOverloads; @@ -4753,7 +4757,7 @@ extern (C++) final class DotVarExp : UnaExp override bool isLvalue() { - if (e1.op != TOK.structLiteral) + if (e1.op != EXP.structLiteral) return true; auto vd = var.isVarDeclaration(); return !(vd && vd.isField()); @@ -4772,7 +4776,7 @@ extern (C++) final class DotVarExp : UnaExp } if (!isLvalue()) return Expression.toLvalue(sc, e); - if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor)) + if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor)) { if (VarDeclaration vd = var.isVarDeclaration()) { @@ -4826,14 +4830,14 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs) { - super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e); + super(loc, EXP.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); + super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e); this.ti = ti; } @@ -4853,29 +4857,29 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp Expression e = new DotIdExp(loc, e1, ti.name); e = e.expressionSemantic(sc); - if (e.op == TOK.dot) + if (e.op == EXP.dot) e = (cast(DotExp)e).e2; Dsymbol s = null; switch (e.op) { - case TOK.overloadSet: + case EXP.overloadSet: s = (cast(OverExp)e).vars; break; - case TOK.dotTemplateDeclaration: + case EXP.dotTemplateDeclaration: s = (cast(DotTemplateExp)e).td; break; - case TOK.scope_: + case EXP.scope_: s = (cast(ScopeExp)e).sds; break; - case TOK.dotVariable: + case EXP.dotVariable: s = (cast(DotVarExp)e).var; break; - case TOK.variable: + case EXP.variable: s = (cast(VarExp)e).var; break; @@ -4926,7 +4930,7 @@ extern (C++) final class DelegateExp : UnaExp 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); + super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e); this.func = f; this.hasOverloads = hasOverloads; this.vthis2 = vthis2; @@ -4946,7 +4950,7 @@ extern (C++) final class DotTypeExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Dsymbol s) { - super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e); + super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e); this.sym = s; } @@ -4969,18 +4973,18 @@ extern (C++) final class CallExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Expressions* exps) { - super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.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); + super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); } extern (D) this(const ref Loc loc, Expression e, Expression earg1) { - super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); this.arguments = new Expressions(); if (earg1) this.arguments.push(earg1); @@ -4988,7 +4992,7 @@ extern (C++) final class CallExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2) { - super(loc, TOK.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); auto arguments = new Expressions(2); (*arguments)[0] = earg1; (*arguments)[1] = earg2; @@ -5143,7 +5147,7 @@ extern (C++) final class AddrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e); + super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e); } extern (D) this(const ref Loc loc, Expression e, Type t) @@ -5164,14 +5168,14 @@ extern (C++) final class PtrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e); + super(loc, EXP.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); + super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e); type = t; } @@ -5216,7 +5220,7 @@ extern (C++) final class NegExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e); + super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e); } override void accept(Visitor v) @@ -5231,7 +5235,7 @@ extern (C++) final class UAddExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e); + super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e); } override void accept(Visitor v) @@ -5246,7 +5250,7 @@ extern (C++) final class ComExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e); + super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e); } override void accept(Visitor v) @@ -5261,7 +5265,7 @@ extern (C++) final class NotExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, TOK.not, __traits(classInstanceSize, NotExp), e); + super(loc, EXP.not, __traits(classInstanceSize, NotExp), e); } override void accept(Visitor v) @@ -5278,7 +5282,7 @@ extern (C++) final class DeleteExp : UnaExp extern (D) this(const ref Loc loc, Expression e, bool isRAII) { - super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e); + super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e); this.isRAII = isRAII; } @@ -5298,7 +5302,7 @@ extern (C++) final class CastExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Type t) { - super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e); + super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e); this.to = t; } @@ -5306,7 +5310,7 @@ extern (C++) final class CastExp : UnaExp */ extern (D) this(const ref Loc loc, Expression e, ubyte mod) { - super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e); + super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e); this.mod = mod; } @@ -5360,7 +5364,7 @@ extern (C++) final class VectorExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Type t) { - super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e); + super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e); assert(t.ty == Tvector); to = cast(TypeVector)t; } @@ -5396,7 +5400,7 @@ extern (C++) final class VectorArrayExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, TOK.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1); + super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1); } override bool isLvalue() @@ -5434,14 +5438,14 @@ extern (C++) final class SliceExp : UnaExp /************************************************************/ extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) { - super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1); + super(loc, EXP.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); + super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1); this.upr = upr; this.lwr = lwr; } @@ -5473,9 +5477,9 @@ extern (C++) final class SliceExp : UnaExp return this; } - override bool isBool(bool result) + override Optional!bool toBool() { - return e1.isBool(result); + return e1.toBool(); } override void accept(Visitor v) @@ -5490,7 +5494,7 @@ extern (C++) final class ArrayLengthExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1); + super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1); } override void accept(Visitor v) @@ -5513,7 +5517,7 @@ extern (C++) final class ArrayExp : UnaExp extern (D) this(const ref Loc loc, Expression e1, Expression index = null) { - super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1); + super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1); arguments = new Expressions(); if (index) arguments.push(index); @@ -5521,7 +5525,7 @@ extern (C++) final class ArrayExp : UnaExp extern (D) this(const ref Loc loc, Expression e1, Expressions* args) { - super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1); + super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1); arguments = args; } @@ -5558,7 +5562,7 @@ 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); + super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2); } override void accept(Visitor v) @@ -5584,7 +5588,7 @@ extern (C++) final class CommaExp : BinExp extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) { - super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2); + super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2); allowCommaExp = isGenerated = generated; } @@ -5605,9 +5609,9 @@ extern (C++) final class CommaExp : BinExp return this; } - override bool isBool(bool result) + override Optional!bool toBool() { - return e2.isBool(result); + return e2.toBool(); } override Expression addDtorHook(Scope* sc) @@ -5653,7 +5657,7 @@ extern (C++) final class IntervalExp : Expression extern (D) this(const ref Loc loc, Expression lwr, Expression upr) { - super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp)); + super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp)); this.lwr = lwr; this.upr = upr; } @@ -5673,7 +5677,7 @@ extern (C++) final class DelegatePtrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1); + super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1); } override bool isLvalue() @@ -5709,7 +5713,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1); + super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1); } override bool isLvalue() @@ -5750,7 +5754,7 @@ extern (C++) final class IndexExp : BinExp extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2); + super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2); //printf("IndexExp::IndexExp('%s')\n", toChars()); } @@ -5763,10 +5767,10 @@ extern (C++) final class IndexExp : BinExp override bool isLvalue() { - if (e1.op == TOK.assocArrayLiteral) + if (e1.op == EXP.assocArrayLiteral) return false; if (e1.type.ty == Tsarray || - (e1.op == TOK.index && e1.type.ty != Tarray)) + (e1.op == EXP.index && e1.type.ty != Tarray)) { return e1.isLvalue(); } @@ -5784,7 +5788,7 @@ extern (C++) final class IndexExp : BinExp { //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); Expression ex = markSettingAAElem(); - if (ex.op == TOK.error) + if (ex.op == EXP.error) return ex; return Expression.modifiableLvalue(sc, e); @@ -5805,7 +5809,7 @@ extern (C++) final class IndexExp : BinExp if (auto ie = e1.isIndexExp()) { Expression ex = ie.markSettingAAElem(); - if (ex.op == TOK.error) + if (ex.op == EXP.error) return ex; assert(ex == e1); } @@ -5824,10 +5828,10 @@ extern (C++) final class IndexExp : BinExp */ extern (C++) final class PostExp : BinExp { - extern (D) this(TOK op, const ref Loc loc, Expression e) + extern (D) this(EXP op, const ref Loc loc, Expression e) { super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1); - assert(op == TOK.minusMinus || op == TOK.plusPlus); + assert(op == EXP.minusMinus || op == EXP.plusPlus); } override void accept(Visitor v) @@ -5841,10 +5845,10 @@ extern (C++) final class PostExp : BinExp */ extern (C++) final class PreExp : UnaExp { - extern (D) this(TOK op, const ref Loc loc, Expression e) + extern (D) this(EXP op, const ref Loc loc, Expression e) { super(loc, op, __traits(classInstanceSize, PreExp), e); - assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus); + assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus); } override void accept(Visitor v) @@ -5867,13 +5871,13 @@ extern (C++) class AssignExp : BinExp MemorySet memset; /************************************************************/ - /* op can be TOK.assign, TOK.construct, or TOK.blit */ + /* op can be EXP.assign, EXP.construct, or EXP.blit */ extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2); + super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2); } - this(const ref Loc loc, TOK tok, Expression e1, Expression e2) + this(const ref Loc loc, EXP tok, Expression e1, Expression e2) { super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2); } @@ -5882,7 +5886,7 @@ extern (C++) class AssignExp : BinExp { // 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) + if (e1.op == EXP.slice || e1.op == EXP.arrayLength) { return false; } @@ -5891,7 +5895,7 @@ extern (C++) class AssignExp : BinExp override final Expression toLvalue(Scope* sc, Expression ex) { - if (e1.op == TOK.slice || e1.op == TOK.arrayLength) + if (e1.op == EXP.slice || e1.op == EXP.arrayLength) { return Expression.toLvalue(sc, ex); } @@ -5915,7 +5919,7 @@ extern (C++) final class ConstructExp : AssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, TOK.construct, e1, e2); + super(loc, EXP.construct, e1, e2); } // Internal use only. If `v` is a reference variable, the assignment @@ -5925,7 +5929,7 @@ extern (C++) final class ConstructExp : AssignExp auto ve = new VarExp(loc, v); assert(v.type && ve.type); - super(loc, TOK.construct, ve, e2); + super(loc, EXP.construct, ve, e2); if (v.isReference()) memset = MemorySet.referenceInit; @@ -5943,7 +5947,7 @@ extern (C++) final class BlitExp : AssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, TOK.blit, e1, e2); + super(loc, EXP.blit, e1, e2); } // Internal use only. If `v` is a reference variable, the assinment @@ -5953,7 +5957,7 @@ extern (C++) final class BlitExp : AssignExp auto ve = new VarExp(loc, v); assert(v.type && ve.type); - super(loc, TOK.blit, ve, e2); + super(loc, EXP.blit, ve, e2); if (v.isReference()) memset = MemorySet.referenceInit; @@ -5971,7 +5975,7 @@ 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); + super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2); } override void accept(Visitor v) @@ -5986,7 +5990,7 @@ 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); + super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2); } override void accept(Visitor v) @@ -6001,7 +6005,7 @@ 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); + super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2); } override void accept(Visitor v) @@ -6016,7 +6020,7 @@ 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); + super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2); } override void accept(Visitor v) @@ -6031,7 +6035,7 @@ 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); + super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2); } override void accept(Visitor v) @@ -6046,7 +6050,7 @@ 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); + super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2); } override void accept(Visitor v) @@ -6061,7 +6065,7 @@ 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); + super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2); } override void accept(Visitor v) @@ -6076,7 +6080,7 @@ 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); + super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2); } override void accept(Visitor v) @@ -6091,7 +6095,7 @@ 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); + super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2); } override void accept(Visitor v) @@ -6106,7 +6110,7 @@ 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); + super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2); } override void accept(Visitor v) @@ -6121,7 +6125,7 @@ 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); + super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2); } override void accept(Visitor v) @@ -6136,7 +6140,7 @@ 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); + super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2); } override void accept(Visitor v) @@ -6148,21 +6152,21 @@ extern (C++) final class UshrAssignExp : BinAssignExp /*********************************************************** * 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[] + * EXP.concatenateAssign - appending T[] to T[] + * EXP.concatenateElemAssign - appending T to T[] + * EXP.concatenateDcharAssign - appending dchar to T[] * - * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which + * The parser initially sets it to EXP.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); + super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2); } - extern (D) this(const ref Loc loc, TOK tok, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) { super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2); } @@ -6178,7 +6182,7 @@ 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); + super(loc, EXP.concatenateElemAssign, e1, e2); this.type = type; } @@ -6193,7 +6197,7 @@ 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); + super(loc, EXP.concatenateDcharAssign, e1, e2); this.type = type; } @@ -6210,7 +6214,7 @@ 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); + super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2); } override void accept(Visitor v) @@ -6225,7 +6229,7 @@ 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); + super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2); } override void accept(Visitor v) @@ -6241,7 +6245,7 @@ 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); + super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -6264,7 +6268,7 @@ 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); + super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2); } override void accept(Visitor v) @@ -6280,7 +6284,7 @@ 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); + super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2); } override void accept(Visitor v) @@ -6296,7 +6300,7 @@ 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); + super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2); } override void accept(Visitor v) @@ -6312,7 +6316,7 @@ 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); + super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2); } override void accept(Visitor v) @@ -6327,7 +6331,7 @@ 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); + super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2); } override void accept(Visitor v) @@ -6342,7 +6346,7 @@ 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); + super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2); } override void accept(Visitor v) @@ -6357,7 +6361,7 @@ 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); + super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2); } override void accept(Visitor v) @@ -6372,7 +6376,7 @@ 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); + super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2); } override void accept(Visitor v) @@ -6387,7 +6391,7 @@ 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); + super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2); } override void accept(Visitor v) @@ -6402,7 +6406,7 @@ 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); + super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2); } override void accept(Visitor v) @@ -6417,10 +6421,10 @@ extern (C++) final class XorExp : BinExp */ extern (C++) final class LogicalExp : BinExp { - extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2); - assert(op == TOK.andAnd || op == TOK.orOr); + assert(op == EXP.andAnd || op == EXP.orOr); } override void accept(Visitor v) @@ -6431,16 +6435,16 @@ extern (C++) final class LogicalExp : BinExp /*********************************************************** * `op` is one of: - * TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual + * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.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) + extern (D) this(EXP 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); + assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual); } override void accept(Visitor v) @@ -6455,7 +6459,7 @@ 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); + super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2); } override void accept(Visitor v) @@ -6471,7 +6475,7 @@ 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); + super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2); type = Type.tbool; } @@ -6484,16 +6488,16 @@ extern (C++) final class RemoveExp : BinExp /*********************************************************** * `==` and `!=` * - * TOK.equal and TOK.notEqual + * EXP.equal and EXP.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) + extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2); - assert(op == TOK.equal || op == TOK.notEqual); + assert(op == EXP.equal || op == EXP.notEqual); } override void accept(Visitor v) @@ -6505,16 +6509,16 @@ extern (C++) final class EqualExp : BinExp /*********************************************************** * `is` and `!is` * - * TOK.identity and TOK.notIdentity + * EXP.identity and EXP.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) + extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) { super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2); - assert(op == TOK.identity || op == TOK.notIdentity); + assert(op == EXP.identity || op == EXP.notIdentity); } override void accept(Visitor v) @@ -6534,7 +6538,7 @@ extern (C++) final class CondExp : BinExp extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) { - super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2); + super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2); this.econd = econd; } @@ -6623,9 +6627,9 @@ extern (C++) final class CondExp : BinExp //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); + v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor); else - v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor); + v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor); v.edtor = v.edtor.expressionSemantic(sc); //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); } @@ -6649,18 +6653,18 @@ extern (C++) final class CondExp : BinExp } /// Returns: if this token is the `op` for a derived `DefaultInitExp` class. -bool isDefaultInitOp(TOK op) pure nothrow @safe @nogc +bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc { - return op == TOK.prettyFunction || op == TOK.functionString || - op == TOK.line || op == TOK.moduleString || - op == TOK.file || op == TOK.fileFullPath ; + return op == EXP.prettyFunction || op == EXP.functionString || + op == EXP.line || op == EXP.moduleString || + op == EXP.file || op == EXP.fileFullPath ; } /*********************************************************** */ extern (C++) class DefaultInitExp : Expression { - extern (D) this(const ref Loc loc, TOK op, int size) + extern (D) this(const ref Loc loc, EXP op, int size) { super(loc, op, size); } @@ -6675,7 +6679,7 @@ extern (C++) class DefaultInitExp : Expression */ extern (C++) final class FileInitExp : DefaultInitExp { - extern (D) this(const ref Loc loc, TOK tok) + extern (D) this(const ref Loc loc, EXP tok) { super(loc, tok, __traits(classInstanceSize, FileInitExp)); } @@ -6684,7 +6688,7 @@ extern (C++) final class FileInitExp : DefaultInitExp { //printf("FileInitExp::resolve() %s\n", toChars()); const(char)* s; - if (op == TOK.fileFullPath) + if (op == EXP.fileFullPath) s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars()); else s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); @@ -6707,7 +6711,7 @@ extern (C++) final class LineInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, TOK.line, __traits(classInstanceSize, LineInitExp)); + super(loc, EXP.line, __traits(classInstanceSize, LineInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -6729,7 +6733,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp)); + super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -6753,7 +6757,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp)); + super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -6783,7 +6787,7 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp)); + super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp)); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -6828,7 +6832,7 @@ extern (C++) final class ObjcClassReferenceExp : Expression extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration) { - super(loc, TOK.objcClassReference, + super(loc, EXP.objcClassReference, __traits(classInstanceSize, ObjcClassReferenceExp)); this.classDeclaration = classDeclaration; type = objc.getRuntimeMetaclass(classDeclaration).getType(); @@ -6852,7 +6856,7 @@ extern (C++) final class GenericExp : Expression extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) { - super(loc, TOK._Generic, __traits(classInstanceSize, GenericExp)); + super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp)); this.cntlExp = cntlExp; this.types = types; this.exps = exps; @@ -6883,18 +6887,18 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag { switch(exp.op) { - case TOK.variable: + case EXP.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: + case EXP.dotVariable: auto dotVarExp = cast(DotVarExp)exp; //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars()); - if (dotVarExp.e1.op == TOK.this_) + if (dotVarExp.e1.op == EXP.this_) return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag); /* https://issues.dlang.org/show_bug.cgi?id=12764 @@ -6925,13 +6929,13 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag onlyUnion = false; // Another DotVarExp left? - if (!dve.e1 || dve.e1.op != TOK.dotVariable) + if (!dve.e1 || dve.e1.op != EXP.dotVariable) break; dve = cast(DotVarExp) dve.e1; } - if (dve.e1.op == TOK.this_) + if (dve.e1.op == EXP.this_) { scope v = dve.var.isVarDeclaration(); /* if v is a struct member field with no initializer, no default construction @@ -6968,7 +6972,7 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag //printf("\te1 = %s\n", e1.toChars()); return dotVarExp.e1.checkModifiable(sc, flag); - case TOK.star: + case EXP.star: auto ptrExp = cast(PtrExp)exp; if (auto se = ptrExp.e1.isSymOffExp()) { @@ -6980,33 +6984,33 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag } return Modifiable.yes; - case TOK.slice: + case EXP.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) + if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice) { return e1.checkModifiable(sc, flag); } return Modifiable.yes; - case TOK.comma: + case EXP.comma: return (cast(CommaExp)exp).e2.checkModifiable(sc, flag); - case TOK.index: + case EXP.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) + (e1.op == EXP.index && e1.type.ty != Tarray) || + e1.op == EXP.slice) { return e1.checkModifiable(sc, flag); } return Modifiable.yes; - case TOK.question: + case EXP.question: auto condExp = cast(CondExp)exp; if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no && condExp.e2.checkModifiable(sc, flag) != Modifiable.no) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 691364c..411822c 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -18,6 +18,7 @@ #include "tokens.h" #include "root/dcompat.h" +#include "root/optional.h" class Type; class TypeVector; @@ -76,7 +77,7 @@ enum class ModifyFlags class Expression : public ASTNode { public: - TOK op; // to minimize use of dynamic_cast + EXP 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 @@ -121,8 +122,7 @@ public: // A compile-time result is required. Give an error if not possible Expression *ctfeInterpret(); int isConst(); - virtual bool isBool(bool result); - + virtual Optional<bool> toBool(); virtual bool hasCode() { return true; @@ -249,7 +249,7 @@ public: real_t toReal(); real_t toImaginary(); complex_t toComplex(); - bool isBool(bool result); + Optional<bool> toBool(); Expression *toLvalue(Scope *sc, Expression *e); void accept(Visitor *v) { v->visit(this); } dinteger_t getInteger() { return value; } @@ -280,7 +280,7 @@ public: real_t toReal(); real_t toImaginary(); complex_t toComplex(); - bool isBool(bool result); + Optional<bool> toBool(); void accept(Visitor *v) { v->visit(this); } }; @@ -297,7 +297,7 @@ public: real_t toReal(); real_t toImaginary(); complex_t toComplex(); - bool isBool(bool result); + Optional<bool> toBool(); void accept(Visitor *v) { v->visit(this); } }; @@ -336,7 +336,7 @@ public: VarDeclaration *var; ThisExp *syntaxCopy(); - bool isBool(bool result); + Optional<bool> toBool(); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); @@ -353,7 +353,7 @@ class NullExp : public Expression { public: bool equals(const RootObject *o) const; - bool isBool(bool result); + Optional<bool> toBool(); StringExp *toStringExp(); void accept(Visitor *v) { v->visit(this); } }; @@ -374,7 +374,7 @@ public: bool equals(const RootObject *o) const; StringExp *toStringExp(); StringExp *toUTF8(Scope *sc); - bool isBool(bool result); + Optional<bool> toBool(); bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); @@ -420,7 +420,7 @@ public: 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); + Optional<bool> toBool(); StringExp *toStringExp(); void accept(Visitor *v) { v->visit(this); } @@ -435,7 +435,7 @@ public: bool equals(const RootObject *o) const; AssocArrayLiteralExp *syntaxCopy(); - bool isBool(bool result); + Optional<bool> toBool(); void accept(Visitor *v) { v->visit(this); } }; @@ -567,7 +567,7 @@ class SymOffExp : public SymbolExp public: dinteger_t offset; - bool isBool(bool result); + Optional<bool> toBool(); void accept(Visitor *v) { v->visit(this); } }; @@ -926,7 +926,7 @@ public: bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); - bool isBool(bool result); + Optional<bool> toBool(); void accept(Visitor *v) { v->visit(this); } }; @@ -997,7 +997,7 @@ public: bool isLvalue(); Expression *toLvalue(Scope *sc, Expression *e); Expression *modifiableLvalue(Scope *sc, Expression *e); - bool isBool(bool result); + Optional<bool> toBool(); Expression *addDtorHook(Scope *sc); void accept(Visitor *v) { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 8e152d6..ec2bce4 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -108,7 +108,7 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) // allowed to contain types as well as expressions auto e4 = ctfeInterpretForPragmaMsg(e3); - if (!e4 || e4.op == TOK.error) + if (!e4 || e4.op == EXP.error) return true; // expand tuple @@ -153,14 +153,14 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s) exp = resolveProperties(sc, exp); sc = sc.endCTFE(); - if (exp.op == TOK.error) + if (exp.op == EXP.error) return null; auto e = exp; if (exp.type.isString()) { e = e.ctfeInterpret(); - if (e.op == TOK.error) + if (e.op == EXP.error) return null; } @@ -215,7 +215,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) if (i == 0) *pe0 = extractOpDollarSideEffect(sc, ae); - if (e.op == TOK.interval && !(slice && slice.isTemplateDeclaration())) + if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration())) { Lfallback: if (ae.arguments.dim == 1) @@ -273,7 +273,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) ae.error("`%s` has no value", e.toChars()); e = ErrorExp.get(); } - if (e.op == TOK.error) + if (e.op == EXP.error) return e; (*ae.arguments)[i] = e; @@ -342,9 +342,9 @@ bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = if (e) { auto e2 = e.expressionSemantic(sc); - if (e2.op == TOK.error) + if (e2.op == EXP.error) err = true; - if (preserveErrors || e2.op != TOK.error) + if (preserveErrors || e2.op != EXP.error) e = e2; } } @@ -531,7 +531,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) { if (Expression ey = die.semanticY(sc, 1)) { - if (ey.op == TOK.error) + if (ey.op == EXP.error) return ey; ce.e1 = ey; if (isDotOpDispatch(ey)) @@ -1024,7 +1024,7 @@ 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) + if (e1.op == EXP.objcClassReference) { // We already have an Objective-C class reference, just use that as 'this'. return e1; @@ -1040,7 +1040,7 @@ L1: * 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_) + if (e1.op == EXP.this_) { FuncDeclaration f = hasThis(sc); if (f && f.isThis2) @@ -1051,7 +1051,7 @@ L1: 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) + if (e1.op == EXP.error) return e1; goto L1; } @@ -1089,7 +1089,7 @@ L1: // 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) + if (e1.op == EXP.error) return e1; goto L1; } @@ -1110,7 +1110,7 @@ L1: */ 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); + //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); Loc loc = e1.loc; OverloadSet os; @@ -1138,7 +1138,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) { e2 = e2.expressionSemantic(sc); - if (e2.op == TOK.error) + if (e2.op == EXP.error) return ErrorExp.get(); e2 = resolveProperties(sc, e2); @@ -1233,7 +1233,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = tthis = null; goto Lfd; } - else if (e1.op == TOK.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration())) + else if (e1.op == EXP.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration())) { DotVarExp dve = cast(DotVarExp)e1; s = dve.var; @@ -1241,11 +1241,11 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = tthis = dve.e1.type; goto Lfd; } - else if (sc && sc.flags & SCOPE.Cfile && e1.op == TOK.variable && !e2) + else if (sc && sc.flags & SCOPE.Cfile && e1.op == EXP.variable && !e2) { // ImportC: do not implicitly call function if no ( ) are present } - else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration())) + else if (e1.op == EXP.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration())) { s = (cast(VarExp)e1).var; tiargs = null; @@ -1255,7 +1255,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) { e2 = e2.expressionSemantic(sc); - if (e2.op == TOK.error) + if (e2.op == EXP.error) return ErrorExp.get(); e2 = resolveProperties(sc, e2); @@ -1316,7 +1316,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) goto Leprop; } - if (e1.op == TOK.variable) + if (e1.op == EXP.variable) { VarExp ve = cast(VarExp)e1; VarDeclaration v = ve.var.isVarDeclaration(); @@ -1326,7 +1326,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = if (e2) return null; - if (e1.type && e1.op != TOK.type) // function type is not a property + if (e1.type && e1.op != EXP.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 @@ -1337,13 +1337,13 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = Expression e = new CallExp(loc, e1); return e.expressionSemantic(sc); } - else if (e1.op == TOK.dotVariable) + else if (e1.op == EXP.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) + else if (e1.op == EXP.call) { CallExp ce = cast(CallExp)e1; // Check for reading overlapped pointer field in @safe code. @@ -1409,7 +1409,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) t0 = Type.terror; continue; } - if (e.op == TOK.type) + if (e.op == EXP.type) { foundType = true; // do not break immediately, there might be more errors e.checkValue(); // report an error "type T has no value" @@ -1440,9 +1440,9 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) condexp.e2 = e; condexp.loc = e.loc; Expression ex = condexp.expressionSemantic(sc); - if (ex.op == TOK.error) + if (ex.op == EXP.error) e = ex; - else if (e.op == TOK.function_ || e.op == TOK.delegate_) + else if (e.op == EXP.function_ || e.op == EXP.delegate_) { // https://issues.dlang.org/show_bug.cgi?id=21285 // Functions and delegates don't convert correctly with castTo below @@ -1458,7 +1458,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) } e0 = e; t0 = e.type; - if (e.op != TOK.error) + if (e.op != EXP.error) exps[i] = e; } @@ -1477,7 +1477,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) continue; e = e.implicitCastTo(sc, t0); - if (e.op == TOK.error) + if (e.op == EXP.error) { /* https://issues.dlang.org/show_bug.cgi?id=13024 * a workaround for the bug in typeMerge - @@ -1491,52 +1491,52 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) return t0; } -private Expression opAssignToOp(const ref Loc loc, TOK op, Expression e1, Expression e2) +private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) { Expression e; switch (op) { - case TOK.addAssign: + case EXP.addAssign: e = new AddExp(loc, e1, e2); break; - case TOK.minAssign: + case EXP.minAssign: e = new MinExp(loc, e1, e2); break; - case TOK.mulAssign: + case EXP.mulAssign: e = new MulExp(loc, e1, e2); break; - case TOK.divAssign: + case EXP.divAssign: e = new DivExp(loc, e1, e2); break; - case TOK.modAssign: + case EXP.modAssign: e = new ModExp(loc, e1, e2); break; - case TOK.andAssign: + case EXP.andAssign: e = new AndExp(loc, e1, e2); break; - case TOK.orAssign: + case EXP.orAssign: e = new OrExp(loc, e1, e2); break; - case TOK.xorAssign: + case EXP.xorAssign: e = new XorExp(loc, e1, e2); break; - case TOK.leftShiftAssign: + case EXP.leftShiftAssign: e = new ShlExp(loc, e1, e2); break; - case TOK.rightShiftAssign: + case EXP.rightShiftAssign: e = new ShrExp(loc, e1, e2); break; - case TOK.unsignedRightShiftAssign: + case EXP.unsignedRightShiftAssign: e = new UshrExp(loc, e1, e2); break; @@ -1559,9 +1559,9 @@ private Expression rewriteOpAssign(BinExp exp) { Expression e; - assert(exp.e1.op == TOK.arrayLength); + assert(exp.e1.op == EXP.arrayLength); ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1; - if (ale.e1.op == TOK.variable) + if (ale.e1.op == EXP.variable) { e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); e = new AssignExp(exp.loc, ale.syntaxCopy(), e); @@ -1604,12 +1604,12 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo Expression arg = (*exps)[i]; arg = resolveProperties(sc, arg); arg = arg.arrayFuncConv(sc); - if (arg.op == TOK.type) + if (arg.op == EXP.type) { // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 arg = resolveAliasThis(sc, arg); - if (arg.op == TOK.type) + if (arg.op == EXP.type) { if (reportErrors) { @@ -2056,7 +2056,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* Argument value cannot escape from the called function. */ Expression a = arg; - if (a.op == TOK.cast_) + if (a.op == EXP.cast_) a = (cast(CastExp)a).e1; ArrayLiteralExp ale; @@ -2071,7 +2071,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, arg = CommaExp.combine(declareTmp, castToSlice); arg = arg.expressionSemantic(sc); } - else if (a.op == TOK.function_) + else if (a.op == EXP.function_) { /* Function literals can only appear once, so if this * appearance was scoped, there cannot be any others. @@ -2079,14 +2079,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc, FuncExp fe = cast(FuncExp)a; fe.fd.tookAddressOf = 0; } - else if (a.op == TOK.delegate_) + else if (a.op == EXP.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) + if (de.e1.op == EXP.variable) { VarExp ve = cast(VarExp)de.e1; FuncDeclaration f = ve.var.isFuncDeclaration(); @@ -2185,7 +2185,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, //arg = callCpCtor(sc, arg); } // Give error for overloaded function addresses - if (arg.op == TOK.symbolOffset) + if (arg.op == EXP.symbolOffset) { SymOffExp se = cast(SymOffExp)arg; if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) @@ -2357,7 +2357,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, // edtor => (__gate || edtor) assert(tmp.edtor); Expression e = tmp.edtor; - e = new LogicalExp(e.loc, TOK.orOr, new VarExp(e.loc, gate), e); + e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e); tmp.edtor = e.expressionSemantic(sc); //printf("edtor: %s\n", tmp.edtor.toChars()); } @@ -2766,7 +2766,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } // Try Type.opDispatch (so the static version) - else if (ss.withstate.exp && ss.withstate.exp.op == TOK.type) + else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type) { if (Type t = ss.withstate.exp.isTypeExp().type) { @@ -3077,7 +3077,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.error("`%s` has no value", e.toChars()); err = true; } - else if (e.op == TOK.error) + else if (e.op == EXP.error) err = true; else (*exp.exps)[i] = e; @@ -3110,7 +3110,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (e.basis) e.basis = e.basis.expressionSemantic(sc); - if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == TOK.error)) + if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == EXP.error)) return setError(); expandTuples(e.elements); @@ -3474,7 +3474,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.thisexp) { exp.thisexp = exp.thisexp.expressionSemantic(sc); - if (exp.thisexp.op == TOK.error) + if (exp.thisexp.op == EXP.error) return setError(); cdthis = exp.thisexp.type.isClassHandle(); @@ -3619,7 +3619,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.thisexp = exp.thisexp.expressionSemantic(sc); - if (exp.thisexp.op == TOK.error) + if (exp.thisexp.op == EXP.error) return setError(); cdthis = exp.thisexp.type.isClassHandle(); } @@ -3666,9 +3666,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (AggregateDeclaration ad2 = cd.isMember2()) { Expression te = new ThisExp(exp.loc).expressionSemantic(sc); - if (te.op != TOK.error) + if (te.op != EXP.error) te = getRightThis(exp.loc, sc, ad2, te, cd); - if (te.op == TOK.error) + if (te.op == EXP.error) { exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars()); return setError(); @@ -3764,7 +3764,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - if (sd.ctor && nargs) + if (sd.hasRegularCtor() && nargs) { FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard); if (!f || f.errors) @@ -3842,10 +3842,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression arg = (*exp.arguments)[i]; arg = resolveProperties(sc, arg); arg = arg.implicitCastTo(sc, Type.tsize_t); - if (arg.op == TOK.error) + if (arg.op == EXP.error) return setError(); arg = arg.optimize(WANTvalue); - if (arg.op == TOK.int64 && cast(sinteger_t)arg.toInteger() < 0) + if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0) { exp.error("negative array index `%s`", arg.toChars()); return setError(); @@ -4104,7 +4104,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * auto foo(void function() fp) { return 1; } * assert(foo({}) == 1); * - * So, should keep fd.tok == TOKreserve if fd.treq == NULL. + * So, should keep fd.tok == TOK.reserve if fd.treq == NULL. */ if (exp.fd.treq && exp.fd.treq.ty == Tpointer) { @@ -4135,7 +4135,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor for (size_t k = 0; k < arguments.dim; k++) { Expression checkarg = (*arguments)[k]; - if (checkarg.op == TOK.error) + if (checkarg.op == EXP.error) return checkarg; } @@ -4213,7 +4213,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Type tthis = null; Expression e1org = exp.e1; - if (exp.e1.op == TOK.comma) + if (exp.e1.op == EXP.comma) { /* Rewrite (a,b)(args) as (a,(b(args))) */ @@ -4223,14 +4223,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = ce.expressionSemantic(sc); return; } - if (exp.e1.op == TOK.delegate_) + if (exp.e1.op == EXP.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 (exp.e1.op == EXP.function_) { if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) return setError(); @@ -4238,7 +4238,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -4254,7 +4254,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* This recognizes: * foo!(tiargs)(funcargs) */ - if (exp.e1.op == TOK.scope_) + if (exp.e1.op == EXP.scope_) { ScopeExp se = cast(ScopeExp)exp.e1; TemplateInstance ti = se.sds.isTemplateInstance(); @@ -4288,7 +4288,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else { Expression e1x = exp.e1.expressionSemantic(sc); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; @@ -4302,7 +4302,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * expr.foo!(tiargs)(funcargs) */ Ldotti: - if (exp.e1.op == TOK.dotTemplateInstance) + if (exp.e1.op == EXP.dotTemplateInstance) { DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1; TemplateInstance ti = se.ti; @@ -4330,7 +4330,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else { Expression e1x = exp.e1.expressionSemantic(sc); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; @@ -4343,13 +4343,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Lagain: //printf("Lagain: %s\n", toChars()); exp.f = null; - if (exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) + if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) { // semantic() run later for these } else { - if (exp.e1.op == TOK.dotIdentifier) + if (exp.e1.op == EXP.dotIdentifier) { DotIdExp die = cast(DotIdExp)exp.e1; exp.e1 = die.expressionSemantic(sc); @@ -4357,7 +4357,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * 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) + if (exp.e1.op == EXP.dotTemplateInstance) { goto Ldotti; } @@ -4382,7 +4382,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Look for e1 being a lazy parameter */ - if (exp.e1.op == TOK.variable) + if (exp.e1.op == EXP.variable) { VarExp ve = cast(VarExp)exp.e1; if (ve.var.storage_class & STC.lazy_) @@ -4400,29 +4400,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (exp.e1.op == TOK.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads) + if (exp.e1.op == EXP.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) + else if (exp.e1.op == EXP.dot) { DotExp de = cast(DotExp)exp.e1; - if (de.e2.op == TOK.overloadSet) + if (de.e2.op == EXP.overloadSet) { ethis = de.e1; tthis = de.e1.type; exp.e1 = de.e2; } } - else if (exp.e1.op == TOK.star && exp.e1.type.ty == Tfunction) + else if (exp.e1.op == EXP.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)) + else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile)) { const numArgs = exp.arguments ? exp.arguments.length : 0; if (e1org.parens && numArgs >= 1) @@ -4480,7 +4480,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null; - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -4515,7 +4515,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // First look for constructor - if (exp.e1.op == TOK.type && sd.ctor) + if (exp.e1.op == EXP.type && sd.ctor) { if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim)) goto Lx; @@ -4566,7 +4566,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (search_function(sd, Id.call)) goto L1; // overload of opCall, therefore it's a call - if (exp.e1.op != TOK.type) + if (exp.e1.op != EXP.type) { if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type)) { @@ -4595,7 +4595,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - else if (exp.e1.op == TOK.type && t1.isscalar()) + else if (exp.e1.op == EXP.type && t1.isscalar()) { Expression e; @@ -4659,7 +4659,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } bool isSuper = false; - if (exp.e1.op == TOK.dotVariable && t1.ty == Tfunction || exp.e1.op == TOK.dotTemplateDeclaration) + if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration) { UnaExp ue = cast(UnaExp)exp.e1; @@ -4667,7 +4667,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor DotVarExp dve; DotTemplateExp dte; Dsymbol s; - if (exp.e1.op == TOK.dotVariable) + if (exp.e1.op == EXP.dotVariable) { dve = cast(DotVarExp)exp.e1; dte = null; @@ -4703,7 +4703,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration(); ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f); - if (ue.e1.op == TOK.error) + if (ue.e1.op == EXP.error) { result = ue.e1; return; @@ -4720,7 +4720,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* 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()) + if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant()) { exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars()); return setError(); @@ -4737,7 +4737,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (ue1old.checkRightThis(sc)) return setError(); - if (exp.e1.op == TOK.dotVariable) + if (exp.e1.op == EXP.dotVariable) { dve.var = exp.f; exp.e1.type = exp.f.type; @@ -4746,7 +4746,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false); exp.e1 = exp.e1.expressionSemantic(sc); - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) return setError(); ue = cast(UnaExp)exp.e1; } @@ -4764,12 +4764,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ClassDeclaration cd = ue.e1.type.isClassHandle(); if (ad && cd && ad.isClassDeclaration()) { - if (ue.e1.op == TOK.dotType) + if (ue.e1.op == EXP.dotType) { ue.e1 = (cast(DotTypeExp)ue.e1).e1; exp.directcall = true; } - else if (ue.e1.op == TOK.super_) + else if (ue.e1.op == EXP.super_) exp.directcall = true; else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211 exp.directcall = true; @@ -4791,12 +4791,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } t1 = exp.e1.type; } - else if (exp.e1.op == TOK.super_ || exp.e1.op == TOK.this_) + else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_) { auto ad = sc.func ? sc.func.isThis() : null; auto cd = ad ? ad.isClassDeclaration() : null; - isSuper = exp.e1.op == TOK.super_; + isSuper = exp.e1.op == EXP.super_; if (isSuper) { // Base class constructor call @@ -4858,7 +4858,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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) + if (exp.e1.op == EXP.error) return setError(); t1 = exp.e1.type; @@ -4870,7 +4870,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (exp.e1.op == TOK.overloadSet) + else if (exp.e1.op == EXP.overloadSet) { auto os = (cast(OverExp)exp.e1).vars; exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments); @@ -4897,7 +4897,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor const(char)* p; Dsymbol s; exp.f = null; - if (exp.e1.op == TOK.function_) + if (exp.e1.op == EXP.function_) { // function literal that direct called is always inferred. assert((cast(FuncExp)exp.e1).fd); @@ -4917,7 +4917,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tf = tfx; p = "function pointer"; } - else if (exp.e1.op == TOK.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration()) + else if (exp.e1.op == EXP.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); @@ -4935,12 +4935,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e.expressionSemantic(sc); return; } - else if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.isOverDeclaration()) + else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration()) { s = (cast(VarExp)exp.e1).var; goto L2; } - else if (exp.e1.op == TOK.template_) + else if (exp.e1.op == EXP.template_) { s = (cast(TemplateExp)exp.e1).td; L2: @@ -5031,7 +5031,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } t1 = tf; } - else if (exp.e1.op == TOK.variable) + else if (exp.e1.op == EXP.variable) { // Do overload resolution VarExp ve = cast(VarExp)exp.e1; @@ -5188,9 +5188,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (AggregateDeclaration ad2 = exp.f.isMember2()) { Expression te = new ThisExp(exp.loc).expressionSemantic(sc); - if (te.op != TOK.error) + if (te.op != EXP.error) te = getRightThis(exp.loc, sc, ad2, te, exp.f); - if (te.op == TOK.error) + if (te.op == EXP.error) { exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars()); return setError(); @@ -5368,7 +5368,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ea = ea.expressionSemantic(sc); ea = resolveProperties(sc, ea); ta = ea.type; - if (ea.op == TOK.type) + if (ea.op == EXP.type) ea = null; } @@ -5644,7 +5644,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* 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) + if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.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)); } @@ -5819,7 +5819,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.e1.op == TOK.arrayLength) + if (exp.e1.op == EXP.arrayLength) { // arr.length op= e2; e = rewriteOpAssign(exp); @@ -5827,12 +5827,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) + if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); - if (exp.e1.op == TOK.slice) + if (exp.e1.op == EXP.slice) (cast(SliceExp)exp.e1).arrayop = true; // T[] op= ... @@ -5869,16 +5869,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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); + int arith = (exp.op == EXP.addAssign || exp.op == EXP.minAssign || exp.op == EXP.mulAssign || exp.op == EXP.divAssign || exp.op == EXP.modAssign || exp.op == EXP.powAssign); + int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign); + int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.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()) + if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral()) { result = scaleFactor(exp, sc); return; @@ -5907,17 +5907,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.e1.op == TOK.error || exp.e2.op == TOK.error) + if (exp.e1.op == EXP.error || exp.e2.op == EXP.error) return setError(); e = exp.checkOpAssignTypes(sc); - if (e.op == TOK.error) + if (e.op == EXP.error) { result = e; return; } - assert(e.op == TOK.assign || e == exp); + assert(e.op == EXP.assign || e == exp); result = (cast(BinExp)e).reorderSettingAAElem(sc); } @@ -6209,9 +6209,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Objects* tiargs; Loc loc = exp.e1.loc; - const tok = exp.e1.op; + const op = exp.e1.op; bool isEqualsCallExpression; - if (tok == TOK.call) + if (op == EXP.call) { const callExp = cast(CallExp) exp.e1; @@ -6225,11 +6225,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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_ || + if (op == EXP.equal || op == EXP.notEqual || + op == EXP.lessThan || op == EXP.greaterThan || + op == EXP.lessOrEqual || op == EXP.greaterOrEqual || + op == EXP.identity || op == EXP.notIdentity || + op == EXP.in_ || isEqualsCallExpression) { es = new Expressions(3); @@ -6269,7 +6269,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // template args - Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : Token.toString(exp.e1.op)); + Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op)); comp = comp.expressionSemantic(sc); (*es)[0] = comp; (*tiargs)[0] = (*es)[1].type; @@ -6277,7 +6277,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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) + else if (op != EXP.andAnd && op != EXP.orOr) { es = new Expressions(2); tiargs = new Objects(1); @@ -6343,7 +6343,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.optimize(WANTvalue); exp.e1 = exp.e1.toBoolean(sc); - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -6358,7 +6358,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor checkParamArgumentEscape(sc, null, null, exp.msg, true, false); } - if (exp.msg && exp.msg.op == TOK.error) + if (exp.msg && exp.msg.op == EXP.error) { result = exp.msg; return; @@ -6369,7 +6369,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (f1 || f2) return setError(); - if (exp.e1.isBool(false)) + if (exp.e1.toBool().hasValue(false)) { /* This is an `assert(0)` which means halt program execution */ @@ -6688,7 +6688,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration(); if (f.needThis()) e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); - if (e.e1.op == TOK.error) + if (e.e1.op == EXP.error) return setError(); /* A delegate takes the address of e.e1 in order to set the .ptr field @@ -6731,9 +6731,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (AggregateDeclaration ad2 = f.isMember2()) { Expression te = new ThisExp(e.loc).expressionSemantic(sc); - if (te.op != TOK.error) + if (te.op != EXP.error) te = getRightThis(e.loc, sc, ad2, te, f); - if (te.op == TOK.error) + if (te.op == EXP.error) { e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars()); return setError(); @@ -6806,9 +6806,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - int wasCond = exp.e1.op == TOK.question; + int wasCond = exp.e1.op == EXP.question; - if (exp.e1.op == TOK.dotTemplateInstance) + if (exp.e1.op == EXP.dotTemplateInstance) { DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1; TemplateInstance ti = dti.ti; @@ -6827,7 +6827,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } - else if (exp.e1.op == TOK.scope_) + else if (exp.e1.op == EXP.scope_) { TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance(); if (ti) @@ -6891,7 +6891,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.e1 = exp.e1.toLvalue(sc, null); - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -6913,7 +6913,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (!exp.e1.type.deco) { - if (exp.e1.op == TOK.variable) + if (exp.e1.op == EXP.variable) { VarExp ve = cast(VarExp)exp.e1; Declaration d = ve.var; @@ -6927,7 +6927,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.e1.type.pointerTo(); // See if this should really be a delegate - if (exp.e1.op == TOK.dotVariable) + if (exp.e1.op == EXP.dotVariable) { DotVarExp dve = cast(DotVarExp)exp.e1; FuncDeclaration f = dve.var.isFuncDeclaration(); @@ -6961,7 +6961,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } - else if (exp.e1.op == TOK.variable) + else if (exp.e1.op == EXP.variable) { VarExp ve = cast(VarExp)exp.e1; VarDeclaration v = ve.var.isVarDeclaration(); @@ -7023,7 +7023,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } - else if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && global.params.useDIP1000 == FeatureState.enabled) + else if ((exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) && global.params.useDIP1000 == FeatureState.enabled) { if (VarDeclaration v = expToVariable(exp.e1)) { @@ -7031,20 +7031,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (exp.e1.op == TOK.call) + else if (exp.e1.op == EXP.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()) + if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) + && tf.next.hasPointers() && 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) + else if (exp.e1.op == EXP.index) { /* For: * int[3] a; @@ -7064,12 +7065,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* a ? b : c was transformed to *(a ? &b : &c), but we still * need to do safety checks */ - assert(exp.e1.op == TOK.star); + assert(exp.e1.op == EXP.star); PtrExp pe = cast(PtrExp)exp.e1; - assert(pe.e1.op == TOK.question); + assert(pe.e1.op == EXP.question); CondExp ce = cast(CondExp)pe.e1; - assert(ce.e1.op == TOK.address); - assert(ce.e2.op == TOK.address); + assert(ce.e1.op == EXP.address); + assert(ce.e2.op == EXP.address); // Re-run semantic on the address expressions only ce.e1.type = null; @@ -7270,7 +7271,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (e.e1.op == TOK.type) + if (e.e1.op == EXP.type) e.e1 = resolveAliasThis(sc, e.e1); e.e1 = resolveProperties(sc, e.e1); @@ -7313,7 +7314,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.e1 = resolveProperties(sc, exp.e1); exp.e1 = exp.e1.modifiableLvalue(sc, null); - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -7405,8 +7406,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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)) + (exp.e1.op == EXP.address || exp.e1.op == EXP.star || + exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate)) { /* Ambiguous cases arise from CParser if type-name is just an identifier. * ( identifier ) cast-expression @@ -7457,11 +7458,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (exp.e1.op == TOK.type) + if (exp.e1.op == EXP.type) exp.e1 = resolveAliasThis(sc, exp.e1); auto e1x = resolveProperties(sc, exp.e1); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; @@ -7557,7 +7558,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Expression ex = exp.e1.castTo(sc, exp.to); - if (ex.op == TOK.error) + if (ex.op == EXP.error) { result = ex; return; @@ -7591,16 +7592,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - if(t1b.ty == Tarray && exp.e1.op != TOK.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0) + if(t1b.ty == Tarray && exp.e1.op != EXP.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) + if (exp.e1.op != EXP.string_ || !ex.isStringExp) { const uint fromSize = cast(uint)tFrom.size(); const uint toSize = cast(uint)tTo.size(); + if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID) + return setError(); // If array element sizes do not match, we must adjust the dimensions if (fromSize != toSize) @@ -7664,7 +7667,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.expressionSemantic(sc); exp.type = exp.to.typeSemantic(exp.loc, sc); - if (exp.e1.op == TOK.error || exp.type.ty == Terror) + if (exp.e1.op == EXP.error || exp.type.ty == Terror) { result = exp.e1; return; @@ -7687,7 +7690,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.optimize(WANTvalue); bool res; - if (exp.e1.op == TOK.arrayLiteral) + if (exp.e1.op == EXP.arrayLiteral) { foreach (i; 0 .. exp.dim) { @@ -7712,7 +7715,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor unaSemantic(e, sc); e.e1 = resolveProperties(sc, e.e1); - if (e.e1.op == TOK.error) + if (e.e1.op == EXP.error) { result = e.e1; return; @@ -7742,7 +7745,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } exp.e1 = resolveProperties(sc, exp.e1); - if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) + if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) { if (exp.lwr || exp.upr) { @@ -7755,7 +7758,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (!exp.lwr && !exp.upr) { - if (exp.e1.op == TOK.arrayLiteral) + if (exp.e1.op == EXP.arrayLiteral) { // Convert [a,b,c][] to [a,b,c] Type t1b = exp.e1.type.toBasetype(); @@ -7768,7 +7771,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - if (exp.e1.op == TOK.slice) + if (exp.e1.op == EXP.slice) { // Convert e[][] to e[] SliceExp se = cast(SliceExp)exp.e1; @@ -7785,7 +7788,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } } - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -7824,10 +7827,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (VarDeclaration v = expToVariable(exp.e1)) { - if (exp.e1.op == TOK.dotVariable) + if (exp.e1.op == EXP.dotVariable) { DotVarExp dve = cast(DotVarExp)exp.e1; - if ((dve.e1.op == TOK.this_ || dve.e1.op == TOK.super_) && + if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) && !(v.storage_class & STC.ref_)) { // because it's a class @@ -7912,13 +7915,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TupleExp te; TypeTuple tup; size_t length; - if (exp.e1.op == TOK.tuple) // slicing an expression tuple + if (exp.e1.op == EXP.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 + else if (exp.e1.op == EXP.type) // slicing a type tuple { te = null; tup = cast(TypeTuple)t1b; @@ -7936,7 +7939,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor size_t j1 = cast(size_t)i1; size_t j2 = cast(size_t)i2; Expression e; - if (exp.e1.op == TOK.tuple) + if (exp.e1.op == EXP.tuple) { auto exps = new Expressions(j2 - j1); for (size_t i = 0; i < j2 - j1; i++) @@ -7982,29 +7985,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression el = new ArrayLengthExp(exp.loc, exp.e1); el = el.expressionSemantic(sc); el = el.optimize(WANTvalue); - if (el.op == TOK.int64) + if (el.op == EXP.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); - if (exp.lwr.op == TOK.int64 && exp.upr.op == TOK.int64 && exp.lwr.toInteger() > exp.upr.toInteger()) + if (exp.lwr.op == EXP.int64 && exp.upr.op == EXP.int64 && exp.lwr.toInteger() > exp.upr.toInteger()) { exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger()); return setError(); } - if (exp.upr.op == TOK.int64 && exp.upr.toInteger() > length) + if (exp.upr.op == EXP.int64 && exp.upr.toInteger() > length) { exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length); return setError(); } } - else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0) + else if (exp.upr.op == EXP.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) + else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar) { // Upper slice expression is '$'. Value is always in bounds. exp.upperIsInBounds = true; @@ -8069,7 +8072,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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) + else if (exp.e1.op == EXP.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()); @@ -8090,17 +8093,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.expressionSemantic(sc); exp.e2 = exp.e2.expressionSemantic(sc); - if (exp.e1.op == TOK.type) + if (exp.e1.op == EXP.type) { result = exp.e2; return; } - if (exp.e2.op == TOK.type) + if (exp.e2.op == EXP.type) { result = exp.e2; return; } - if (exp.e2.op == TOK.template_) + if (exp.e2.op == EXP.template_) { auto td = (cast(TemplateExp)exp.e2).td; Expression e = new DotTemplateExp(exp.loc, exp.e1, td); @@ -8169,12 +8172,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ue = ue.expressionSemantic(sc); ue = resolveProperties(sc, ue); - if (le.op == TOK.error) + if (le.op == EXP.error) { result = le; return; } - if (ue.op == TOK.error) + if (ue.op == EXP.error) { result = ue; return; @@ -8198,7 +8201,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor unaSemantic(e, sc); e.e1 = resolveProperties(sc, e.e1); - if (e.e1.op == TOK.error) + if (e.e1.op == EXP.error) { result = e.e1; return; @@ -8218,7 +8221,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { unaSemantic(e, sc); e.e1 = resolveProperties(sc, e.e1); - if (e.e1.op == TOK.error) + if (e.e1.op == EXP.error) { result = e.e1; return; @@ -8244,12 +8247,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.e1.type) exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); assert(exp.e1.type); // semantic() should already be run on it - if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) + if (exp.e1.op == EXP.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) + if (exp.e2.op == EXP.type) nt = new TypeAArray(exp.e1.type, exp.e2.type); else nt = new TypeSArray(exp.e1.type, exp.e2); @@ -8257,7 +8260,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e.expressionSemantic(sc); return; } - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; @@ -8294,7 +8297,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e2 = resolveProperties(sc, exp.e2); if (t1b.ty == Ttuple) sc = sc.endCTFE(); - if (exp.e2.op == TOK.tuple) + if (exp.e2.op == EXP.tuple) { TupleExp te = cast(TupleExp)exp.e2; if (te.exps && te.exps.dim == 1) @@ -8320,7 +8323,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e2.type == Type.terror) return setError(); exp.e2 = exp.e2.optimize(WANTvalue); - if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0) + if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0) { } else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) @@ -8378,13 +8381,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TupleExp te; TypeTuple tup; size_t length; - if (exp.e1.op == TOK.tuple) + if (exp.e1.op == EXP.tuple) { te = cast(TupleExp)exp.e1; tup = null; length = te.exps.dim; } - else if (exp.e1.op == TOK.type) + else if (exp.e1.op == EXP.type) { te = null; tup = cast(TypeTuple)t1b; @@ -8399,7 +8402,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } Expression e; - if (exp.e1.op == TOK.tuple) + if (exp.e1.op == EXP.tuple) { e = (*te.exps)[cast(size_t)index]; e = Expression.combine(te.e0, e); @@ -8422,7 +8425,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression el = new ArrayLengthExp(exp.loc, exp.e1); el = el.expressionSemantic(sc); el = el.optimize(WANTvalue); - if (el.op == TOK.int64) + if (el.op == EXP.int64) { exp.e2 = exp.e2.optimize(WANTvalue); dinteger_t length = el.toInteger(); @@ -8455,7 +8458,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } Expression e1x = resolveProperties(sc, exp.e1); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; @@ -8472,15 +8475,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e1.checkReadModifyWrite(exp.op)) return setError(); - if (exp.e1.op == TOK.slice) + if (exp.e1.op == EXP.slice) { - const(char)* s = exp.op == TOK.plusPlus ? "increment" : "decrement"; + const(char)* s = exp.op == EXP.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) + if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength) { /* Check for operator overloading, * but rewrite in terms of ++e instead of e++ @@ -8489,7 +8492,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* If e1 is not trivial, take a reference to it */ Expression de = null; - if (exp.e1.op != TOK.variable && exp.e1.op != TOK.arrayLength) + if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength) { // ref v = e1; auto v = copyToTemp(STC.ref_, "__postref", exp.e1); @@ -8504,7 +8507,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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); + eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb); Expression ec = new VarExp(exp.loc, tmp); @@ -8547,7 +8550,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Rewrite as e1+=1 or e1-=1 - if (exp.op == TOK.prePlusPlus) + if (exp.op == EXP.prePlusPlus) e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); else e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); @@ -8596,8 +8599,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { 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)); + //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, EXPtoString(exp.e1.op).ptr); + //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, EXPtoString(exp.e2.op).ptr); void setResult(Expression e, int line = __LINE__) { @@ -8640,17 +8643,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor const(bool) maybeSlice = (ae.arguments.dim == 0 || - ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval); + ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == TOK.interval); + assert((*ae.arguments)[0].op == EXP.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { - if (ae.e1.op == TOK.error) + if (ae.e1.op == EXP.error) return setResult(ae.e1); Expression e0 = null; @@ -8667,11 +8670,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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) + if (res.op == EXP.error) return setResult(res); res = exp.e2.expressionSemantic(sc); - if (res.op == TOK.error) + if (res.op == EXP.error) return setResult(res); exp.e2 = res; @@ -8695,11 +8698,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // Deal with $ res = resolveOpDollar(sc, ae, ie, &e0); - if (res.op == TOK.error) + if (res.op == EXP.error) return setResult(res); res = exp.e2.expressionSemantic(sc); - if (res.op == TOK.error) + if (res.op == EXP.error) return setResult(res); exp.e2 = res; @@ -8826,9 +8829,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!t1.isTypeSArray()) e2x = e2x.arrayFuncConv(sc); e2x = resolveProperties(sc, e2x); - if (e2x.op == TOK.type) + if (e2x.op == EXP.type) e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684 - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) return setResult(e2x); // We delay checking the value for structs/classes as these might have // an opAssign defined. @@ -8844,7 +8847,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression e2x = exp.e2; Ltupleassign: - if (exp.e1.op == TOK.tuple && e2x.op == TOK.tuple) + if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple) { TupleExp tup1 = cast(TupleExp)exp.e1; TupleExp tup2 = cast(TupleExp)e2x; @@ -8877,7 +8880,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Look for form: e1 = e2.aliasthis. */ - if (exp.e1.op == TOK.tuple) + if (exp.e1.op == EXP.tuple) { TupleDeclaration td = isAliasThisTuple(e2x); if (!td) @@ -8915,7 +8918,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } e2x = new TupleExp(e2x.loc, e0, iexps); e2x = e2x.expressionSemantic(sc); - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) { result = e2x; return; @@ -8929,7 +8932,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Inside constructor, if this is the first assignment of object field, * rewrite this to initializing the field. */ - if (exp.op == TOK.assign + if (exp.op == EXP.assign && exp.e1.checkModifiable(sc) == Modifiable.initialization) { //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); @@ -8942,20 +8945,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (auto ie1 = exp.e1.isIndexExp()) { Expression e1x = ie1.markSettingAAElem(); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; } } } - else if (exp.op == TOK.construct && exp.e1.op == TOK.variable && + else if (exp.op == EXP.construct && exp.e1.op == EXP.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 + if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations { exp.e1.checkSharedAccess(sc); checkUnsafeAccess(sc, exp.e1, false, true); @@ -8977,7 +8980,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto e2x = exp.e2; auto sd = (cast(TypeStruct)t1).sym; - if (exp.op == TOK.construct) + if (exp.op == EXP.construct) { Type t2 = e2x.type.toBasetype(); if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym) @@ -8992,12 +8995,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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) + CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null; + DotVarExp dve = (ce && ce.e1.op == EXP.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 && + dve.e1.op != EXP.dotVariable && e2y.type.implicitConvTo(t1)) { /* Look for form of constructor call which is: @@ -9009,7 +9012,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * initializer */ Expression einit = getInitExp(sd, exp.loc, sc, t1); - if (einit.op == TOK.error) + if (einit.op == EXP.error) { result = einit; return; @@ -9043,7 +9046,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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) + if (e2x.op == EXP.question) { /* Rewrite as: * a ? e1 = b : e1 = c; @@ -9158,7 +9161,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * 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_) + if (exp.e2.op == EXP.new_) { auto newExp = cast(NewExp)(exp.e2); if (newExp.newtype && newExp.newtype == t1) @@ -9193,7 +9196,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e2x = e2x.expressionSemantic(sc); e2x = resolveProperties(sc, e2x); - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) { result = e2x; return; @@ -9216,9 +9219,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } - else if (exp.op == TOK.assign) + else if (exp.op == EXP.assign) { - if (e1x.op == TOK.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) + if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) { /* * Rewrite: @@ -9233,12 +9236,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ // ensure we keep the expr modifiable Expression esetting = (cast(IndexExp)e1x).markSettingAAElem(); - if (esetting.op == TOK.error) + if (esetting.op == EXP.error) { result = esetting; return; } - assert(esetting.op == TOK.index); + assert(esetting.op == EXP.index); IndexExp ie = cast(IndexExp) esetting; Type t2 = e2x.type.toBasetype(); @@ -9279,7 +9282,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ey = new ConstructExp(exp.loc, ex, ey); ey = ey.expressionSemantic(sc); - if (ey.op == TOK.error) + if (ey.op == EXP.error) { result = ey; return; @@ -9290,7 +9293,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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)) + if (!typeMerge(sc, EXP.question, ex, ey)) { ex = new CastExp(ex.loc, ex, Type.tvoid); ey = new CastExp(ey.loc, ey, Type.tvoid); @@ -9314,7 +9317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } else - assert(exp.op == TOK.blit); + assert(exp.op == EXP.blit); if (e2x.checkValue()) return setError(); @@ -9325,7 +9328,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (t1.ty == Tclass) { // Disallow assignment operator overloads for same type - if (exp.op == TOK.assign && !exp.e2.implicitConvTo(exp.e1.type)) + if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type)) { Expression e = exp.op_overload(sc); if (e) @@ -9340,13 +9343,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (t1.ty == Tsarray) { // SliceExp cannot have static array type without context inference. - assert(exp.e1.op != TOK.slice); + assert(exp.e1.op != EXP.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 (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue())) { if (e1x.checkPostblit(sc, t1)) return setError(); @@ -9392,7 +9395,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // May be block or element-wise assignment, so // convert e1 to e1[] - if (exp.op != TOK.assign) + if (exp.op != EXP.assign) { // If multidimensional static array, treat as one large array // @@ -9435,9 +9438,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sle.arrayop = true; e1x = sle.expressionSemantic(sc); } - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) return setResult(e1x); - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) return setResult(e2x); exp.e1 = e1x; @@ -9451,7 +9454,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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) + if (ale1x.op == EXP.error) return setResult(ale1x); ale.e1 = ale1x; @@ -9466,7 +9469,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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) + if(lc.op == EXP.int64 && lc.toInteger() == 0) { Expression se = new SliceExp(ale.loc, ale.e1, lc, lc); Expression as = new AssignExp(ale.loc, ale.e1, se); @@ -9507,7 +9510,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { Type tn = se.type.nextOf(); const fun = sc.func; - if (exp.op == TOK.assign && !tn.isMutable() && + if (exp.op == EXP.assign && !tn.isMutable() && // allow modifiation in module ctor, see // https://issues.dlang.org/show_bug.cgi?id=9884 (!fun || (fun && !fun.isStaticCtorDeclaration()))) @@ -9516,7 +9519,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (exp.op == TOK.assign && !tn.baseElemOf().isAssignable()) + if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable()) { exp.error("slice `%s` is not mutable, struct `%s` has immutable members", exp.e1.toChars(), tn.baseElemOf().toChars()); @@ -9525,18 +9528,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // For conditional operator, both branches need conversion. - while (se.e1.op == TOK.slice) + while (se.e1.op == EXP.slice) se = cast(SliceExp)se.e1; - if (se.e1.op == TOK.question && se.e1.type.toBasetype().ty == Tsarray) + if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray) { se.e1 = se.e1.modifiableLvalue(sc, exp.e1); - if (se.e1.op == TOK.error) + if (se.e1.op == EXP.error) return setResult(se.e1); } } else { - if (t1.ty == Tsarray && exp.op == TOK.assign) + if (t1.ty == Tsarray && exp.op == EXP.assign) { Type tn = exp.e1.type.nextOf(); if (tn && !tn.baseElemOf().isAssignable()) @@ -9552,12 +9555,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Try to do a decent error message with the expression // before it gets constant folded - if (exp.op == TOK.assign) + if (exp.op == EXP.assign) e1x = e1x.modifiableLvalue(sc, e1old); e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; @@ -9576,18 +9579,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor while (telem.ty == Tarray) telem = telem.nextOf(); - if (exp.e1.op == TOK.slice && t1.nextOf() && - (telem.ty != Tvoid || e2x.op == TOK.null_) && + if (exp.e1.op == EXP.slice && t1.nextOf() && + (telem.ty != Tvoid || e2x.op == EXP.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())) + if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf())) return setError(); } - else if (exp.e1.op == TOK.slice && + else if (exp.e1.op == EXP.slice && (t2.ty == Tarray || t2.ty == Tsarray) && t2.nextOf().implicitConvTo(t1.nextOf())) { @@ -9616,24 +9619,24 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - 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.op != EXP.blit && + (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || + e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || + e2x.op != EXP.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)) + if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && + e2x.op != EXP.slice && e2x.op != EXP.assign && + e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ && + !(e2x.op == EXP.add || e2x.op == EXP.min || + e2x.op == EXP.mul || e2x.op == EXP.div || + e2x.op == EXP.mod || e2x.op == EXP.xor || + e2x.op == EXP.and || e2x.op == EXP.or || + e2x.op == EXP.pow || + e2x.op == EXP.tilde || e2x.op == EXP.negate)) { const(char)* e1str = exp.e1.toChars(); const(char)* e2str = e2x.toChars(); @@ -9673,7 +9676,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * 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_) + if (e2x.op == EXP.string_) e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf()); else e2x = e2x.implicitCastTo(sc, exp.e1.type); @@ -9689,19 +9692,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign && + if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && t1.ty == Tarray && t2.ty == Tsarray && - e2x.op != TOK.slice && + e2x.op != EXP.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"; + const(char)* atypestr = exp.e1.op == EXP.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) + if (exp.op == EXP.blit) e2x = e2x.castTo(sc, exp.e1.type); else { @@ -9711,7 +9714,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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) + if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct) { scope sd = (cast(TypeStruct)t1).sym; Dsymbol opAssign = search_function(sd, Id.assign); @@ -9729,7 +9732,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) { result = e2x; return; @@ -9743,11 +9746,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // Look for valid array operations if (exp.memset != MemorySet.blockAssign && - exp.e1.op == TOK.slice && + exp.e1.op == EXP.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 + if (exp.op == EXP.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); @@ -9756,7 +9759,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 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)) + if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign)) return setError(); // Remains valid array assignments @@ -9766,7 +9769,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* 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) + if (exp.e1.op == EXP.variable && exp.op == EXP.assign) { VarExp ve = cast(VarExp)exp.e1; VarDeclaration vd = ve.var.isVarDeclaration(); @@ -9777,14 +9780,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe) + if (exp.e1.op == EXP.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; + auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp; Expression tmp; /* https://issues.dlang.org/show_bug.cgi?id=22366 * @@ -9792,6 +9795,84 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * `checkAssignExp` expects only AssignExps. */ checkAssignEscape(sc, Expression.extractLast(res, tmp), false); + + if (auto ae = res.isConstructExp()) + { + Type t1b = ae.e1.type.toBasetype(); + if (t1b.ty != Tsarray && t1b.ty != Tarray) + return setResult(res); + + /* Do not lower Rvalues and references, as they need to be moved, + * not copied. + * Skip the lowering when the RHS is an array literal, as e2ir + * already handles such cases more elegantly. + */ + const isArrayCtor = + (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && + ae.e2.isLvalue && + !(ae.e1.isVarExp && + ae.e1.isVarExp.var.isVarDeclaration.isReference) && + (ae.e2.isVarExp || + ae.e2.isSliceExp || + (ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) && + ae.e1.type.nextOf && + ae.e2.type.nextOf && + ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf); + + const isArraySetCtor = + (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && + ae.e2.isLvalue && + (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) && + ae.e1.type.nextOf && + ae.e1.type.nextOf.equivalent(ae.e2.type); + + if (isArrayCtor || isArraySetCtor) + { + const ts = t1b.nextOf().baseElemOf().isTypeStruct(); + if (!ts || (!ts.sym.postblit && !ts.sym.dtor)) + return setResult(res); + + auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; + const other = isArrayCtor ? "other array" : "value"; + if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object)) + return setError(); + + // Lower to object._d_array{,set}ctor(e1, e2) + Expression id = new IdentifierExp(exp.loc, Id.empty); + id = new DotIdExp(exp.loc, id, Id.object); + id = new DotIdExp(exp.loc, id, func); + id = id.expressionSemantic(sc); + + auto arguments = new Expressions(); + arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc)); + if (isArrayCtor) + { + arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc)); + Expression ce = new CallExp(exp.loc, id, arguments); + res = ce.expressionSemantic(sc); + } + else + { + Expression e0; + // If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access + if (!ae.e2.isVarExp) + { + auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2); + e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); + arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc)); + } + else + arguments.push(ae.e2); + + Expression ce = new CallExp(exp.loc, id, arguments); + res = Expression.combine(e0, ce).expressionSemantic(sc); + } + + if (global.params.verbose) + message("lowered %s =>\n %s", exp.toChars(), res.toChars()); + } + } + return setResult(res); } @@ -9814,7 +9895,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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 (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); @@ -9855,7 +9936,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e = Expression.extractLast(e, e0); assert(e == exp); - if (exp.e1.op == TOK.variable) + if (exp.e1.op == EXP.variable) { // Rewrite: e1 = e1 ^^ e2 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2); @@ -9895,7 +9976,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.e1.op == TOK.slice) + if (exp.e1.op == EXP.slice) { SliceExp se = cast(SliceExp)exp.e1; if (se.e1.type.toBasetype().ty == Tsarray) @@ -9906,12 +9987,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); - if (exp.e1.op == TOK.error) + if (exp.e1.op == EXP.error) { result = exp.e1; return; } - if (exp.e2.op == TOK.error) + if (exp.e2.op == EXP.error) { result = exp.e2; return; @@ -9925,9 +10006,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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[] + * EXP.concatenateAssign: appending T[] to T[] + * EXP.concatenateElemAssign: appending T to T[] + * EXP.concatenateDcharAssign: appending dchar to T[] */ if ((tb1.ty == Tarray) && (tb2.ty == Tarray || tb2.ty == Tsarray) && @@ -9935,8 +10016,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor (tb2.nextOf().implicitConvTo(tb1next) && (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial))))) { - // TOK.concatenateAssign - assert(exp.op == TOK.concatenateAssign); + // EXP.concatenateAssign + assert(exp.op == EXP.concatenateAssign); if (exp.e1.checkPostblit(sc, tb1next)) return setError(); @@ -10033,7 +10114,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.e1.type; auto res = exp.reorderSettingAAElem(sc); - if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) && + if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) && global.params.useDIP1000 == FeatureState.enabled) checkAssignEscape(sc, res, false); result = res; @@ -10227,6 +10308,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t); } + else if (stride == cast(d_int64)SIZE_INVALID) + e = ErrorExp.get(); else { e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t)); @@ -10336,7 +10419,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor 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))) + if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1))) { /* https://issues.dlang.org/show_bug.cgi?id=9248 * Here to avoid the case of: @@ -10360,14 +10443,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Check for: array ~ element if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) { - if (exp.e1.op == TOK.arrayLiteral) + if (exp.e1.op == EXP.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_) + else if (exp.e1.op == EXP.string_) { // No postblit call exists on character (integer) value. } @@ -10378,7 +10461,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Postblit call will be done in runtime helper function } - if (exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf())) + if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf())) { exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf()); exp.type = tb2.arrayOf(); @@ -10403,11 +10486,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Check for: element ~ array if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) { - if (exp.e2.op == TOK.arrayLiteral) + if (exp.e2.op == EXP.arrayLiteral) { exp.e1 = doCopyOrMove(sc, exp.e1); } - else if (exp.e2.op == TOK.string_) + else if (exp.e2.op == EXP.string_) { } else @@ -10416,7 +10499,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf())) + if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf())) { exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf()); exp.type = tb1.arrayOf(); @@ -10444,11 +10527,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { Type t1 = tb1next.mutableOf().constOf().arrayOf(); Type t2 = tb2next.mutableOf().constOf().arrayOf(); - if (exp.e1.op == TOK.string_ && !(cast(StringExp)exp.e1).committed) + if (exp.e1.op == EXP.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) + if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed) exp.e2.type = t2; else exp.e2 = exp.e2.castTo(sc, t2); @@ -10804,7 +10887,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // First, attempt to fold the expression. e = exp.optimize(WANTvalue); - if (e.op != TOK.pow) + if (e.op != EXP.pow) { e = e.expressionSemantic(sc); result = e; @@ -10819,7 +10902,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } e = new ScopeExp(exp.loc, mmath); - if (exp.e2.op == TOK.float64 && exp.e2.toReal() == CTFloat.half) + if (exp.e2.op == EXP.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); @@ -11126,7 +11209,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression e1x = exp.e1.expressionSemantic(sc); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (e1x.op == TOK.type) + if (e1x.op == EXP.type) e1x = resolveAliasThis(sc, e1x); e1x = resolveProperties(sc, e1x); @@ -11137,9 +11220,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* 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)) + if (e1x.toBool().hasValue(exp.op == EXP.orOr)) { - result = IntegerExp.createBool(exp.op == TOK.orOr); + result = IntegerExp.createBool(exp.op == EXP.orOr); return; } } @@ -11150,7 +11233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ctorflow.freeFieldinit(); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (e2x.op == TOK.type) + if (e2x.op == EXP.type) e2x = resolveAliasThis(sc, e2x); e2x = resolveProperties(sc, e2x); @@ -11164,17 +11247,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (e2x.type.ty != Tvoid) e2x = e2x.toBoolean(sc); - if (e2x.op == TOK.type || e2x.op == TOK.scope_) + if (e2x.op == EXP.type || e2x.op == EXP.scope_) { exp.error("`%s` is not an expression", exp.e2.toChars()); return setError(); } - if (e1x.op == TOK.error || e1x.type.ty == Tnoreturn) + if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn) { result = e1x; return; } - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) { result = e2x; return; @@ -11213,13 +11296,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } 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_) + if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_) { exp.error("do not use `null` when comparing class types"); return setError(); } - TOK cmpop; + EXP cmpop; if (auto e = exp.op_overload(sc, &cmpop)) { if (!e.type.isscalar() && e.type.equals(exp.e1.type)) @@ -11227,7 +11310,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.error("recursive `opCmp` expansion"); return setError(); } - if (e.op == TOK.call) + if (e.op == EXP.call) { e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0); e = e.expressionSemantic(sc); @@ -11298,7 +11381,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (t1.ty == Taarray || t2.ty == Taarray) { - exp.error("`%s` is not defined for associative arrays", Token.toChars(exp.op)); + exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr); return setError(); } else if (!target.isVectorOpSupported(t1, exp.op, t2)) @@ -11402,7 +11485,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - if (exp.e1.op == TOK.type || exp.e2.op == TOK.type) + if (exp.e1.op == EXP.type || exp.e2.op == EXP.type) { /* https://issues.dlang.org/show_bug.cgi?id=12520 * empty tuples are represented as types so special cases are added @@ -11411,7 +11494,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor static auto extractTypeTupAndExpTup(Expression e) { static struct Result { bool ttEmpty; bool te; } - auto tt = e.op == TOK.type ? e.isTypeExp().type.isTypeTuple() : null; + auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null; return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null); } auto tups1 = extractTypeTupAndExpTup(exp.e1); @@ -11419,19 +11502,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // AliasSeq!() == AliasSeq!(<at least a value>) if (tups1.ttEmpty && tups2.te) { - result = IntegerExp.createBool(exp.op != TOK.equal); + result = IntegerExp.createBool(exp.op != EXP.equal); return; } // AliasSeq!(<at least a value>) == AliasSeq!() else if (tups1.te && tups2.ttEmpty) { - result = IntegerExp.createBool(exp.op != TOK.equal); + result = IntegerExp.createBool(exp.op != EXP.equal); return; } // AliasSeq!() == AliasSeq!() else if (tups1.ttEmpty && tups2.ttEmpty) { - result = IntegerExp.createBool(exp.op == TOK.equal); + result = IntegerExp.createBool(exp.op == EXP.equal); return; } // otherwise, two types are really not comparable @@ -11451,18 +11534,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * 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) + if (exp.e1.op == EXP.address && exp.e2.op == EXP.address) { AddrExp ae1 = cast(AddrExp)exp.e1; AddrExp ae2 = cast(AddrExp)exp.e2; - if (ae1.e1.op == TOK.variable && ae2.e1.op == TOK.variable) + if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.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); + result = IntegerExp.createBool(exp.op == EXP.equal); return; } } @@ -11555,7 +11638,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor (*arguments)[1] = exp.e2; __equals = new CallExp(exp.loc, __equals, arguments); - if (exp.op == TOK.notEqual) + if (exp.op == EXP.notEqual) { __equals = new NotExp(exp.loc, __equals); } @@ -11611,7 +11694,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (f1 || f2) return setError(); - if (exp.e1.op == TOK.type || exp.e2.op == TOK.type) + if (exp.e1.op == EXP.type || exp.e2.op == EXP.type) { result = exp.incompatibleTypes(); return; @@ -11634,9 +11717,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.e1.op == TOK.call) + if (exp.e1.op == EXP.call) exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc); - if (exp.e2.op == TOK.call) + if (exp.e2.op == EXP.call) exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc); if (exp.e1.type.toBasetype().ty == Tsarray || @@ -11660,7 +11743,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.econd.op == TOK.dotIdentifier) + if (exp.econd.op == EXP.dotIdentifier) (cast(DotIdExp)exp.econd).noderef = true; Expression ec = exp.econd.expressionSemantic(sc); @@ -11679,7 +11762,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc.merge(exp.loc, ctorflow1); ctorflow1.freeFieldinit(); - if (ec.op == TOK.error) + if (ec.op == EXP.error) { result = ec; return; @@ -11688,7 +11771,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); exp.econd = ec; - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) { result = e1x; return; @@ -11697,7 +11780,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); exp.e1 = e1x; - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) { result = e2x; return; @@ -11957,7 +12040,7 @@ Expression unaSemantic(UnaExp e, Scope* sc) printf("UnaExp::semantic('%s')\n", e.toChars()); } Expression e1x = e.e1.expressionSemantic(sc); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) return e1x; e.e1 = e1x; return null; @@ -11977,14 +12060,14 @@ Expression binSemantic(BinExp e, Scope* 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) + if (e1x.op == EXP.type) e1x = resolveAliasThis(sc, e1x); - if (e2x.op == TOK.type) + if (e2x.op == EXP.type) e2x = resolveAliasThis(sc, e2x); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) return e1x; - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) return e2x; e.e1 = e1x; e.e2 = e2x; @@ -11997,9 +12080,9 @@ Expression binSemanticProp(BinExp e, Scope* sc) return ex; Expression e1x = resolveProperties(sc, e.e1); Expression e2x = resolveProperties(sc, e.e2); - if (e1x.op == TOK.error) + if (e1x.op == EXP.error) return e1x; - if (e2x.op == TOK.error) + if (e2x.op == EXP.error) return e2x; e.e1 = e1x; e.e2 = e2x; @@ -12049,11 +12132,11 @@ Expression semanticX(DotIdExp exp, Scope* sc) Dsymbol ds; switch (exp.e1.op) { - case TOK.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds); - case TOK.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var); - case TOK.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var); - case TOK.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars); - case TOK.template_: + case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds); + case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var); + case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var); + case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars); + case EXP.template_: { TemplateExp te = exp.e1.isTemplateExp(); return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td); @@ -12480,9 +12563,9 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) } assert(e); - if (e.op == TOK.error) + if (e.op == EXP.error) return e; - if (e.op == TOK.dotVariable) + if (e.op == EXP.dotVariable) { DotVarExp dve = cast(DotVarExp)e; if (FuncDeclaration fd = dve.var.isFuncDeclaration()) @@ -12516,7 +12599,7 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) .expressionSemantic(sc); } } - else if (e.op == TOK.variable) + else if (e.op == EXP.variable) { VarExp ve = cast(VarExp)e; if (FuncDeclaration fd = ve.var.isFuncDeclaration()) @@ -12535,7 +12618,7 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) } } - if (e.op == TOK.dotTemplateDeclaration) + if (e.op == EXP.dotTemplateDeclaration) { DotTemplateExp dte = cast(DotTemplateExp)e; exp.e1 = dte.e1; // pull semantic() result @@ -12560,17 +12643,17 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) .expressionSemantic(sc); } - else if (e.op == TOK.template_) + else if (e.op == EXP.template_) { exp.ti.tempdecl = (cast(TemplateExp)e).td; return new ScopeExp(exp.loc, exp.ti) .expressionSemantic(sc); } - else if (e.op == TOK.dot) + else if (e.op == EXP.dot) { DotExp de = cast(DotExp)e; - if (de.e2.op == TOK.overloadSet) + if (de.e2.op == EXP.overloadSet) { if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc)) { @@ -12593,7 +12676,7 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) .expressionSemantic(sc); } } - else if (e.op == TOK.overloadSet) + else if (e.op == EXP.overloadSet) { OverExp oe = cast(OverExp)e; exp.ti.tempdecl = oe.vars; @@ -12873,7 +12956,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre } s = s.toParent2(); } - if (n > 1 || e1.op == TOK.index) + if (n > 1 || e1.op == EXP.index) e1 = e1.expressionSemantic(sc); if (s && e1.type.equivalent(Type.tvoidptr)) { @@ -12967,7 +13050,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions e = resolveProperties(sc, e); if (i >= nfields) { - if (i <= sd.fields.dim && e.op == TOK.null_) + if (i <= sd.fields.dim && e.op == EXP.null_) { // CTFE sometimes creates null as hidden pointer; we'll allow this. continue; @@ -12988,7 +13071,10 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions } return false; } - offset = cast(uint)(v.offset + v.type.size()); + const vsize = v.type.size(); + if (vsize == SIZE_INVALID) + return false; + offset = cast(uint)(v.offset + vsize); Type t = v.type; if (stype) @@ -13015,7 +13101,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions * Allow this by doing an explicit cast, which will lengthen the string * literal. */ - if (e.op == TOK.string_ && tb.ty == Tsarray) + if (e.op == EXP.string_ && tb.ty == Tsarray) { StringExp se = cast(StringExp)e; Type typeb = se.type.toBasetype(); @@ -13042,7 +13128,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions e = e.implicitCastTo(sc, t); L1: - if (e.op == TOK.error) + if (e.op == EXP.error) return false; (*elements)[i] = doCopyOrMove(sc, e); @@ -13090,22 +13176,22 @@ Expression toBoolean(Expression exp, Scope* sc) { switch(exp.op) { - case TOK.delete_: + case EXP.delete_: exp.error("`delete` does not give a boolean result"); return ErrorExp.get(); - case TOK.comma: + case EXP.comma: auto ce = exp.isCommaExp(); auto ex2 = ce.e2.toBoolean(sc); - if (ex2.op == TOK.error) + if (ex2.op == EXP.error) return ex2; ce.e2 = ex2; ce.type = ce.e2.type; return ce; - case TOK.assign: - case TOK.construct: - case TOK.blit: + case EXP.assign: + case EXP.construct: + case EXP.blit: // Things like: // if (a = b) ... // are usually mistakes. @@ -13113,22 +13199,22 @@ Expression toBoolean(Expression exp, Scope* sc) return ErrorExp.get(); //LogicalExp - case TOK.andAnd: - case TOK.orOr: + case EXP.andAnd: + case EXP.orOr: auto le = exp.isLogicalExp(); auto ex2 = le.e2.toBoolean(sc); - if (ex2.op == TOK.error) + if (ex2.op == EXP.error) return ex2; le.e2 = ex2; return le; - case TOK.question: + case EXP.question: auto ce = exp.isCondExp(); auto ex1 = ce.e1.toBoolean(sc); auto ex2 = ce.e2.toBoolean(sc); - if (ex1.op == TOK.error) + if (ex1.op == EXP.error) return ex1; - if (ex2.op == TOK.error) + if (ex2.op == EXP.error) return ex2; ce.e1 = ex1; ce.e2 = ex2; diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index 9579ac7..e9a43f9 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -223,7 +223,7 @@ void foreachExpAndVar(Statement s, void visitWith(WithStatement s) { // If it is with(Enum) {...}, just execute the body. - if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type) + if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type) { } else diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 2d6a756..da33587 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -1306,7 +1306,14 @@ extern (C++) class FuncDeclaration : Declaration if (!fbody) return false; - if (isVirtualMethod()) + if (isVirtualMethod() && + /* + * https://issues.dlang.org/show_bug.cgi?id=21719 + * + * If we have an auto virtual function we can infer + * the attributes. + */ + !(inferRetType && !isCtorDeclaration())) return false; // since they may be overridden if (sc.func && diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 747a113..7409dcc 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -148,7 +148,7 @@ extern (C++) struct Param 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 + bool fix16997 = true; // 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 diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 4ff07b5..a454298 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -164,7 +164,7 @@ public: override void visit(ExpStatement s) { - if (s.exp && s.exp.op == TOK.declaration && + if (s.exp && s.exp.op == EXP.declaration && (cast(DeclarationExp)s.exp).declaration) { // bypass visit(DeclarationExp) @@ -202,7 +202,7 @@ public: foreach (sx; *s.statements) { auto ds = sx ? sx.isExpStatement() : null; - if (ds && ds.exp.op == TOK.declaration) + if (ds && ds.exp.op == EXP.declaration) { auto d = (cast(DeclarationExp)ds.exp).declaration; assert(d.isDeclaration()); @@ -1260,7 +1260,7 @@ public: { buf.writestring(" = "); ExpInitializer ie = vd._init.isExpInitializer(); - if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else vd._init.initializerToBuffer(buf, hgs); @@ -1511,7 +1511,7 @@ public: { buf.writestring(" = "); auto ie = v._init.isExpInitializer(); - if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit)) + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else v._init.initializerToBuffer(buf, hgs); @@ -1569,7 +1569,7 @@ public: buf.writestring("in"); if (auto es = frequire.isExpStatement()) { - assert(es.exp && es.exp.op == TOK.assert_); + assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); @@ -1592,7 +1592,7 @@ public: buf.writestring("out"); if (auto es = fensure.ensure.isExpStatement()) { - assert(es.exp && es.exp.op == TOK.assert_); + assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); if (fensure.id) { @@ -1749,7 +1749,7 @@ public: buf.writestring("invariant"); if(auto es = d.fbody.isExpStatement()) { - assert(es.exp && es.exp.op == TOK.assert_); + assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writestring(");"); @@ -1812,7 +1812,7 @@ public: //////////////////////////////////////////////////////////////////////////// override void visit(Expression e) { - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); } override void visit(IntegerExp e) @@ -2278,7 +2278,7 @@ public: override void visit(UnaExp e) { - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); expToBuffer(e.e1, precedence[e.op], buf, hgs); } @@ -2286,7 +2286,7 @@ public: { expToBuffer(e.e1, precedence[e.op], buf, hgs); buf.writeByte(' '); - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); buf.writeByte(' '); expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs); } @@ -2415,7 +2415,7 @@ public: override void visit(CallExp e) { - if (e.e1.op == TOK.type) + if (e.e1.op == EXP.type) { /* Avoid parens around type to prevent forbidden cast syntax: * (sometype)(arg1) @@ -2540,12 +2540,12 @@ public: override void visit(PostExp e) { expToBuffer(e.e1, precedence[e.op], buf, hgs); - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); } override void visit(PreExp e) { - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); expToBuffer(e.e1, precedence[e.op], buf, hgs); } @@ -2568,7 +2568,7 @@ public: override void visit(DefaultInitExp e) { - buf.writestring(Token.toString(e.op)); + buf.writestring(EXPtoString(e.op)); } override void visit(ClassReferenceExp e) @@ -3144,7 +3144,7 @@ private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) { buf.writeByte('@'); - bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call; + bool isAnonymous = p.userAttribDecl.atts.dim > 0 && !(*p.userAttribDecl.atts)[0].isCallExp(); if (isAnonymous) buf.writeByte('('); @@ -3253,9 +3253,9 @@ 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); + Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e); ex = ex.optimize(WANTvalue); - const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1; + const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1; if (cast(sinteger_t)uval >= 0) { dinteger_t sizemax = void; @@ -3292,7 +3292,7 @@ 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)); + printf("precedence not defined for token '%s'\n", EXPtoString(e.op).ptr); } if (e.op == 0xFF) { @@ -3422,7 +3422,7 @@ private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hg } 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_) + if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_) { buf.writestring(e.toChars()); return; @@ -3460,7 +3460,7 @@ private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs) } else if (auto e = isExpression(oarg)) { - if (e.op == TOK.variable) + if (e.op == EXP.variable) e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375 expToBuffer(e, PREC.assign, buf, hgs); } @@ -3962,3 +3962,158 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) case Ttag: return visitTag(cast(TypeTag)t); } } + +/**************************************** + * Convert EXP to char*. + */ + +string EXPtoString(EXP op) +{ + static immutable char*[EXP.max + 1] strings = + [ + EXP.type : "type", + EXP.error : "error", + EXP.objcClassReference : "class", + + EXP.typeof_ : "typeof", + EXP.mixin_ : "mixin", + + EXP.import_ : "import", + EXP.dotVariable : "dotvar", + EXP.scope_ : "scope", + EXP.identifier : "identifier", + EXP.this_ : "this", + EXP.super_ : "super", + EXP.int64 : "long", + EXP.float64 : "double", + EXP.complex80 : "creal", + EXP.null_ : "null", + EXP.string_ : "string", + EXP.arrayLiteral : "arrayliteral", + EXP.assocArrayLiteral : "assocarrayliteral", + EXP.classReference : "classreference", + EXP.file : "__FILE__", + EXP.fileFullPath : "__FILE_FULL_PATH__", + EXP.line : "__LINE__", + EXP.moduleString : "__MODULE__", + EXP.functionString : "__FUNCTION__", + EXP.prettyFunction : "__PRETTY_FUNCTION__", + EXP.typeid_ : "typeid", + EXP.is_ : "is", + EXP.assert_ : "assert", + EXP.halt : "halt", + EXP.template_ : "template", + EXP.dSymbol : "symbol", + EXP.function_ : "function", + EXP.variable : "var", + EXP.symbolOffset : "symoff", + EXP.structLiteral : "structLiteral", + EXP.compoundLiteral : "compoundliteral", + EXP.arrayLength : "arraylength", + EXP.delegatePointer : "delegateptr", + EXP.delegateFunctionPointer : "delegatefuncptr", + EXP.remove : "remove", + EXP.tuple : "tuple", + EXP.traits : "__traits", + EXP.default_ : "default", + EXP.overloadSet : "__overloadset", + EXP.void_ : "void", + EXP.vectorArray : "vectorarray", + EXP._Generic : "_Generic", + + // post + EXP.dotTemplateInstance : "dotti", + EXP.dotIdentifier : "dotid", + EXP.dotTemplateDeclaration : "dottd", + EXP.dot : ".", + EXP.dotType : "dottype", + EXP.plusPlus : "++", + EXP.minusMinus : "--", + EXP.prePlusPlus : "++", + EXP.preMinusMinus : "--", + EXP.call : "call", + EXP.slice : "..", + EXP.array : "[]", + EXP.index : "[i]", + + EXP.delegate_ : "delegate", + EXP.address : "&", + EXP.star : "*", + EXP.negate : "-", + EXP.uadd : "+", + EXP.not : "!", + EXP.tilde : "~", + EXP.delete_ : "delete", + EXP.new_ : "new", + EXP.newAnonymousClass : "newanonclass", + EXP.cast_ : "cast", + + EXP.vector : "__vector", + EXP.pow : "^^", + + EXP.mul : "*", + EXP.div : "/", + EXP.mod : "%", + + EXP.add : "+", + EXP.min : "-", + EXP.concatenate : "~", + + EXP.leftShift : "<<", + EXP.rightShift : ">>", + EXP.unsignedRightShift : ">>>", + + EXP.lessThan : "<", + EXP.lessOrEqual : "<=", + EXP.greaterThan : ">", + EXP.greaterOrEqual : ">=", + EXP.in_ : "in", + + EXP.equal : "==", + EXP.notEqual : "!=", + EXP.identity : "is", + EXP.notIdentity : "!is", + + EXP.and : "&", + EXP.xor : "^", + EXP.or : "|", + + EXP.andAnd : "&&", + EXP.orOr : "||", + + EXP.question : "?", + + EXP.assign : "=", + EXP.construct : "=", + EXP.blit : "=", + EXP.addAssign : "+=", + EXP.minAssign : "-=", + EXP.concatenateAssign : "~=", + EXP.concatenateElemAssign : "~=", + EXP.concatenateDcharAssign : "~=", + EXP.mulAssign : "*=", + EXP.divAssign : "/=", + EXP.modAssign : "%=", + EXP.powAssign : "^^=", + EXP.leftShiftAssign : "<<=", + EXP.rightShiftAssign : ">>=", + EXP.unsignedRightShiftAssign : ">>>=", + EXP.andAssign : "&=", + EXP.orAssign : "|=", + EXP.xorAssign : "^=", + + EXP.comma : ",", + EXP.declaration : "declaration", + + EXP.interval : "interval", + ]; + const p = strings[op]; + if (!p) + { + printf("error: EXP %d has no string\n", op); + return "XXXXX"; + //assert(0); + } + assert(p); + return p[0 .. strlen(p)]; +} diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 3ff0e89..cd30117 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -348,7 +348,7 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) e = (*s.constraints)[i]; e = e.expressionSemantic(sc); - assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1); + assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1); (*s.constraints)[i] = e; } } @@ -360,7 +360,7 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) { Expression e = (*s.clobbers)[i]; e = e.expressionSemantic(sc); - assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1); + assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1); (*s.clobbers)[i] = e; } } diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 1ee5153..83c89c0 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -315,6 +315,8 @@ immutable Msgtable[] msgtable = { "dup" }, { "_aaApply" }, { "_aaApply2" }, + { "_d_arrayctor" }, + { "_d_arraysetctor" }, // For pragma's { "Pinline", "inline" }, @@ -463,6 +465,7 @@ immutable Msgtable[] msgtable = { "getUnitTests" }, { "getVirtualIndex" }, { "getPointerBitmap" }, + { "initSymbol" }, { "getCppNamespaces" }, { "isReturnOnStack" }, { "isZeroInit" }, diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 5828486..c5aa0f4 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -225,7 +225,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ 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) + if (ex.op == EXP.error) { errors = true; elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors @@ -331,7 +331,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ errors = true; } length = cast(uint)idxvalue; - if (idx.op == TOK.error) + if (idx.op == EXP.error) errors = true; } Initializer val = i.value[j]; @@ -344,7 +344,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ errors = true; ei = val.isExpInitializer(); // found a tuple, expand it - if (ei && ei.exp.op == TOK.tuple) + if (ei && ei.exp.op == EXP.tuple) { TupleExp te = cast(TupleExp)ei.exp; i.index.remove(j); @@ -384,6 +384,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ return err(); const sz = t.nextOf().size(); + if (sz == SIZE_INVALID) + return err(); bool overflow; const max = mulu(i.dim, sz, overflow); if (overflow || max >= amax) @@ -403,7 +405,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = resolveProperties(sc, i.exp); if (needInterpret) sc = sc.endCTFE(); - if (i.exp.op == TOK.error) + if (i.exp.op == EXP.error) return err(); uint olderrors = global.errors; @@ -437,7 +439,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ */ i.exp = i.exp.optimize(WANTvalue); i.exp = i.exp.ctfeInterpret(); - if (i.exp.op == TOK.voidExpression) + if (i.exp.op == EXP.voidExpression) error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead."); } else @@ -455,7 +457,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = new TupleExp(i.exp.loc, new Expressions()); i.exp.type = et; } - if (i.exp.op == TOK.type) + if (i.exp.op == EXP.type) { i.exp.error("initializer must be an expression, not `%s`", i.exp.toChars()); return err(); @@ -467,7 +469,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ return err(); } Type ti = i.exp.type.toBasetype(); - if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t)) + if (i.exp.op == EXP.tuple && i.expandTuples && !i.exp.implicitConvTo(t)) { return new ExpInitializer(i.loc, i.exp); } @@ -477,7 +479,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ * Allow this by doing an explicit cast, which will lengthen the string * literal. */ - if (i.exp.op == TOK.string_ && tb.ty == Tsarray) + if (i.exp.op == EXP.string_ && tb.ty == Tsarray) { StringExp se = cast(StringExp)i.exp; Type typeb = se.type.toBasetype(); @@ -562,12 +564,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger(); uinteger_t dim2 = dim1; - if (i.exp.op == TOK.arrayLiteral) + if (i.exp.op == EXP.arrayLiteral) { ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp; dim2 = ale.elements ? ale.elements.dim : 0; } - else if (i.exp.op == TOK.slice) + else if (i.exp.op == EXP.slice) { Type tx = toStaticArrayType(cast(SliceExp)i.exp); if (tx) @@ -582,7 +584,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = i.exp.implicitCastTo(sc, t); } L1: - if (i.exp.op == TOK.error) + if (i.exp.op == EXP.error) { return i; } @@ -667,7 +669,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ auto tm = vd.type.addMod(ts.mod); auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret); auto ex = iz.initializerToExpression(); - if (ex.op == TOK.error) + if (ex.op == EXP.error) { errors = true; continue; @@ -823,6 +825,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } const sz = tn.size(); // element size + if (sz == SIZE_INVALID) + return err(); bool overflow; const max = mulu(edim, sz, overflow); if (overflow || max >= amax) @@ -930,7 +934,7 @@ Initializer inferType(Initializer init, Scope* sc) } assert(iz.isExpInitializer()); (*values)[i] = (cast(ExpInitializer)iz).exp; - assert((*values)[i].op != TOK.error); + assert(!(*values)[i].isErrorExp()); } Expression e = new AssocArrayLiteralExp(init.loc, keys, values); auto ei = new ExpInitializer(init.loc, e); @@ -953,7 +957,7 @@ Initializer inferType(Initializer init, Scope* sc) } assert(iz.isExpInitializer()); (*elements)[i] = (cast(ExpInitializer)iz).exp; - assert((*elements)[i].op != TOK.error); + assert(!(*elements)[i].isErrorExp()); } Expression e = new ArrayLiteralExp(init.loc, null, elements); auto ei = new ExpInitializer(init.loc, e); @@ -977,11 +981,11 @@ Initializer inferType(Initializer init, Scope* sc) 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) + if (init.exp.op == EXP.type) init.exp = resolveAliasThis(sc, init.exp); init.exp = resolveProperties(sc, init.exp); - if (init.exp.op == TOK.scope_) + if (init.exp.op == EXP.scope_) { ScopeExp se = cast(ScopeExp)init.exp; TemplateInstance ti = se.sds.isTemplateInstance(); @@ -1006,16 +1010,16 @@ Initializer inferType(Initializer init, Scope* sc) return new ErrorInitializer(); } } - if (init.exp.op == TOK.address) + if (init.exp.op == EXP.address) { AddrExp ae = cast(AddrExp)init.exp; - if (ae.e1.op == TOK.overloadSet) + if (ae.e1.op == EXP.overloadSet) { init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars()); return new ErrorInitializer(); } } - if (init.exp.op == TOK.error) + if (init.exp.op == EXP.error) { return new ErrorInitializer(); } @@ -1125,7 +1129,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n { if (auto e = init.index[i]) { - if (e.op == TOK.int64) + if (e.op == EXP.int64) { const uinteger_t idxval = e.toInteger(); if (idxval >= amax) @@ -1206,7 +1210,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n */ foreach (e; (*elements)[0 .. edim]) { - if (e.op == TOK.error) + if (e.op == EXP.error) { return e; } @@ -1222,7 +1226,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n { //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; + Expression e = (i.exp.op == EXP.construct || i.exp.op == EXP.blit) ? (cast(AssignExp)i.exp).e2 : i.exp; if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf())) { TypeSArray tsa = cast(TypeSArray)tb; @@ -1277,7 +1281,7 @@ private bool hasNonConstPointers(Expression e) if (e.type.ty == Terror) return false; - if (e.op == TOK.null_) + if (e.op == EXP.null_) return false; if (auto se = e.isStructLiteralExp()) { @@ -1318,11 +1322,11 @@ private bool hasNonConstPointers(Expression e) } if (e.type.ty == Tpointer && !e.type.isPtrToFunction()) { - if (e.op == TOK.symbolOffset) // address of a global is OK + if (e.op == EXP.symbolOffset) // address of a global is OK return false; - if (e.op == TOK.int64) // cast(void *)int is OK + if (e.op == EXP.int64) // cast(void *)int is OK return false; - if (e.op == TOK.string_) // "abc".ptr is OK + if (e.op == EXP.string_) // "abc".ptr is OK return false; return true; } diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index 44a6c06..336f8dd 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -26,6 +26,7 @@ import dmd.dtemplate; import dmd.expression; import dmd.func; import dmd.dmangle; +import dmd.hdrgen; import dmd.mtype; import dmd.common.outbuffer; import dmd.root.rmem; @@ -337,7 +338,7 @@ public: return; buf.writeByte('('); - buf.writestring(Token.toString(exp.op)); + buf.writestring(EXPtoString(exp.op)); exp.e1.accept(this); if (buf.length != 0) buf.writestring(")_"); @@ -370,7 +371,7 @@ public: return; buf.writeByte('('); - buf.writestring(Token.toChars(exp.op)); + buf.writestring(EXPtoString(exp.op).ptr); exp.e1.accept(this); if (buf.length == 0) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index e2b4199..d38cce4 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -386,6 +386,20 @@ class Lexer // Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile. return; case ' ': + // Skip 4 spaces at a time after aligning 'p' to a 4-byte boundary. + while ((cast(size_t)p) % uint.sizeof) + { + if (*p != ' ') + goto LendSkipFourSpaces; + p++; + } + while (*(cast(uint*)p) == 0x20202020) // ' ' == 0x20 + p += 4; + // Skip over any remaining space on the line. + while (*p == ' ') + p++; + LendSkipFourSpaces: + continue; // skip white space case '\t': case '\v': case '\f': @@ -394,19 +408,11 @@ class Lexer 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 diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index a21924b..e338a05 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -515,7 +515,7 @@ extern (C++) abstract class Type : ASTNode } else if (tp1.ty == Tdelegate) { - if (tp1.implicitConvTo(tp2)) + if (tp2.implicitConvTo(tp1)) goto Lcov; } } @@ -4783,7 +4783,7 @@ extern (C++) final class TypeFunction : TypeNext goto Nomatch; } - if (arg.op == TOK.string_ && tp.ty == Tsarray) + if (arg.op == EXP.string_ && tp.ty == Tsarray) { if (ta.ty != Tsarray) { @@ -4792,7 +4792,7 @@ extern (C++) final class TypeFunction : TypeNext ta = tn.sarrayOf(dim); } } - else if (arg.op == TOK.slice && tp.ty == Tsarray) + else if (arg.op == EXP.slice && tp.ty == Tsarray) { // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] if (ta.ty != Tsarray) @@ -4805,7 +4805,7 @@ extern (C++) final class TypeFunction : TypeNext 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) + if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) { Type tn = tp.nextOf(); dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); @@ -4988,7 +4988,7 @@ extern (C++) final class TypeFunction : TypeNext { assert(to); - if (this == to) + if (this.equals(to)) return MATCH.constant; if (this.covariant(to) == Covariant.yes) @@ -5301,7 +5301,7 @@ extern (C++) final class TypeDelegate : TypeNext //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to.toChars()); - if (this == to) + if (this.equals(to)) return MATCH.exact; if (auto toDg = to.isTypeDelegate()) @@ -5814,7 +5814,7 @@ extern (C++) final class TypeStruct : Type } else e = vd.type.defaultInitLiteral(loc); - if (e && e.op == TOK.error) + if (e && e.op == EXP.error) return e; if (e) offset = vd.offset + cast(uint)vd.type.size(); @@ -6225,7 +6225,7 @@ extern (C++) final class TypeEnum : Type override bool isZeroInit(const ref Loc loc) { - return sym.getDefaultValue(loc).isBool(false); + return sym.getDefaultValue(loc).toBool().hasValue(false); } override bool hasPointers() diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 4bb2907..31a25a7 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -136,7 +136,7 @@ public: override void visit(DeleteExp e) { - if (e.e1.op == TOK.variable) + if (e.e1.op == EXP.variable) { VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); if (v && v.onstack) @@ -189,7 +189,7 @@ public: override void visit(AssignExp e) { - if (e.e1.op == TOK.arrayLength) + if (e.e1.op == EXP.arrayLength) { if (f.setGC()) { @@ -230,7 +230,7 @@ public: Expression checkGC(Scope* sc, Expression e) { FuncDeclaration f = sc.func; - if (e && e.op != TOK.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) && + if (e && e.op != EXP.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_)) diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 605e9f3..156428e 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -1362,7 +1362,7 @@ void genKill(ref ObState obstate, ObNode* ob) override void visit(Expression e) { - //printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars()); + //printf("[%s] %s: %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars()); //assert(0); } @@ -1644,7 +1644,7 @@ void genKill(ref ObState obstate, ObNode* ob) * 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) + if (e.e1.op != EXP.structLiteral) e.e1.accept(this); } @@ -2378,7 +2378,7 @@ void checkObErrors(ref ObState obstate) * 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) + if (e.e1.op != EXP.structLiteral) e.e1.accept(this); } diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index eb4ba1d..4236381 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -540,10 +540,10 @@ extern(C++) private final class Supported : Objc override void setSelector(FuncDeclaration fd, Scope* sc) { foreachUda(fd, sc, (e) { - if (e.op != TOK.structLiteral) + if (!e.isStructLiteralExp()) return 0; - auto literal = cast(StructLiteralExp) e; + auto literal = e.isStructLiteralExp(); assert(literal.sd); if (!isCoreUda(literal.sd, Id.udaSelector)) @@ -616,10 +616,10 @@ extern(C++) private final class Supported : Objc int count; foreachUda(fd, sc, (e) { - if (e.op != TOK.type) + if (!e.isTypeExp()) return 0; - auto typeExp = cast(TypeExp) e; + auto typeExp = e.isTypeExp(); if (typeExp.type.ty != Tenum) return 0; @@ -861,10 +861,10 @@ extern(D) private: arrayExpressionSemantic(udas, sc, true); return udas.each!((uda) { - if (uda.op != TOK.tuple) + if (!uda.isTupleExp()) return 0; - auto exps = (cast(TupleExp) uda).exps; + auto exps = uda.isTupleExp().exps; return exps.each!((e) { assert(e); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index ff03a6e..4d250c0 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -29,6 +29,7 @@ import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; +import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.mtype; @@ -41,23 +42,23 @@ import dmd.visitor; * Determine if operands of binary op can be reversed * to fit operator overload. */ -bool isCommutative(TOK op) +bool isCommutative(EXP op) { switch (op) { - case TOK.add: - case TOK.mul: - case TOK.and: - case TOK.or: - case TOK.xor: + case EXP.add: + case EXP.mul: + case EXP.and: + case EXP.or: + case EXP.xor: // EqualExp - case TOK.equal: - case TOK.notEqual: + case EXP.equal: + case EXP.notEqual: // CmpExp - case TOK.lessThan: - case TOK.lessOrEqual: - case TOK.greaterThan: - case TOK.greaterOrEqual: + case EXP.lessThan: + case EXP.lessOrEqual: + case EXP.greaterThan: + case EXP.greaterOrEqual: return true; default: break; @@ -72,47 +73,47 @@ 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; + case EXP.uadd: return Id.uadd; + case EXP.negate: return Id.neg; + case EXP.tilde: return Id.com; + case EXP.cast_: return Id._cast; + case EXP.in_: return Id.opIn; + case EXP.plusPlus: return Id.postinc; + case EXP.minusMinus: return Id.postdec; + case EXP.add: return Id.add; + case EXP.min: return Id.sub; + case EXP.mul: return Id.mul; + case EXP.div: return Id.div; + case EXP.mod: return Id.mod; + case EXP.pow: return Id.pow; + case EXP.leftShift: return Id.shl; + case EXP.rightShift: return Id.shr; + case EXP.unsignedRightShift: return Id.ushr; + case EXP.and: return Id.iand; + case EXP.or: return Id.ior; + case EXP.xor: return Id.ixor; + case EXP.concatenate: return Id.cat; + case EXP.assign: return Id.assign; + case EXP.addAssign: return Id.addass; + case EXP.minAssign: return Id.subass; + case EXP.mulAssign: return Id.mulass; + case EXP.divAssign: return Id.divass; + case EXP.modAssign: return Id.modass; + case EXP.powAssign: return Id.powass; + case EXP.leftShiftAssign: return Id.shlass; + case EXP.rightShiftAssign: return Id.shrass; + case EXP.unsignedRightShiftAssign: return Id.ushrass; + case EXP.andAssign: return Id.andass; + case EXP.orAssign: return Id.orass; + case EXP.xorAssign: return Id.xorass; + case EXP.concatenateAssign: return Id.catass; + case EXP.equal: return Id.eq; + case EXP.lessThan: + case EXP.lessOrEqual: + case EXP.greaterThan: + case EXP.greaterOrEqual: return Id.cmp; + case EXP.array: return Id.index; + case EXP.star: return Id.opStar; default: assert(0); } } @@ -125,20 +126,20 @@ 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; + case EXP.in_: return Id.opIn_r; + case EXP.add: return Id.add_r; + case EXP.min: return Id.sub_r; + case EXP.mul: return Id.mul_r; + case EXP.div: return Id.div_r; + case EXP.mod: return Id.mod_r; + case EXP.pow: return Id.pow_r; + case EXP.leftShift: return Id.shl_r; + case EXP.rightShift: return Id.shr_r; + case EXP.unsignedRightShift:return Id.ushr_r; + case EXP.and: return Id.iand_r; + case EXP.or: return Id.ior_r; + case EXP.xor: return Id.ixor_r; + case EXP.concatenate: return Id.cat_r; default: return null; } } @@ -146,55 +147,55 @@ private Identifier opId_r(Expression e) /******************************************* * Helper function to turn operator into template argument list */ -Objects* opToArg(Scope* sc, TOK op) +Objects* opToArg(Scope* sc, EXP op) { /* Remove the = from op= */ switch (op) { - case TOK.addAssign: - op = TOK.add; + case EXP.addAssign: + op = EXP.add; break; - case TOK.minAssign: - op = TOK.min; + case EXP.minAssign: + op = EXP.min; break; - case TOK.mulAssign: - op = TOK.mul; + case EXP.mulAssign: + op = EXP.mul; break; - case TOK.divAssign: - op = TOK.div; + case EXP.divAssign: + op = EXP.div; break; - case TOK.modAssign: - op = TOK.mod; + case EXP.modAssign: + op = EXP.mod; break; - case TOK.andAssign: - op = TOK.and; + case EXP.andAssign: + op = EXP.and; break; - case TOK.orAssign: - op = TOK.or; + case EXP.orAssign: + op = EXP.or; break; - case TOK.xorAssign: - op = TOK.xor; + case EXP.xorAssign: + op = EXP.xor; break; - case TOK.leftShiftAssign: - op = TOK.leftShift; + case EXP.leftShiftAssign: + op = EXP.leftShift; break; - case TOK.rightShiftAssign: - op = TOK.rightShift; + case EXP.rightShiftAssign: + op = EXP.rightShift; break; - case TOK.unsignedRightShiftAssign: - op = TOK.unsignedRightShift; + case EXP.unsignedRightShiftAssign: + op = EXP.unsignedRightShift; break; - case TOK.concatenateAssign: - op = TOK.concatenate; + case EXP.concatenateAssign: + op = EXP.concatenate; break; - case TOK.powAssign: - op = TOK.pow; + case EXP.powAssign: + op = EXP.pow; break; default: break; } - Expression e = new StringExp(Loc.initial, Token.toString(op)); + Expression e = new StringExp(Loc.initial, EXPtoString(op)); e = e.expressionSemantic(sc); auto tiargs = new Objects(); tiargs.push(e); @@ -216,13 +217,13 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE BinExp be = cast(BinExp)e.copy(); // Resolve 'alias this' but in case of assigment don't resolve properties yet // because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2' - bool findOnly = (e.op == TOK.assign); + bool findOnly = (e.op == EXP.assign); be.e1 = resolveAliasThis(sc, e.e1, true, findOnly); if (!be.e1) return null; Expression result; - if (be.op == TOK.concatenateAssign) + if (be.op == EXP.concatenateAssign) result = be.op_overload(sc); else result = be.trySemantic(sc); @@ -247,7 +248,7 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE return null; Expression result; - if (be.op == TOK.concatenateAssign) + if (be.op == EXP.concatenateAssign) result = be.op_overload(sc); else result = be.trySemantic(sc); @@ -269,17 +270,17 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE * `null` if not an operator overload, * otherwise the lowered expression */ -Expression op_overload(Expression e, Scope* sc, TOK* pop = null) +Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { extern (C++) final class OpOverload : Visitor { alias visit = Visitor.visit; public: Scope* sc; - TOK* pop; + EXP* pop; Expression result; - extern (D) this(Scope* sc, TOK* pop) + extern (D) this(Scope* sc, EXP* pop) { this.sc = sc; this.pop = pop; @@ -293,22 +294,22 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) override void visit(UnaExp e) { //printf("UnaExp::op_overload() (%s)\n", e.toChars()); - if (e.e1.op == TOK.array) + if (e.e1.op == EXP.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); + const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == TOK.interval); + assert((*ae.arguments)[0].op == EXP.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { - if (ae.e1.op == TOK.error) + if (ae.e1.op == EXP.error) { result = ae.e1; return; @@ -326,7 +327,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) 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) + if (result.op == EXP.error) return; /* Rewrite op(a[arguments]) as: * a.opIndexUnary!(op)(arguments) @@ -350,7 +351,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == TOK.error) + if (result.op == EXP.error) return; /* Rewrite op(a[i..j]) as: * a.opSliceUnary!(op)(i, j) @@ -385,7 +386,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) } e.e1 = e.e1.expressionSemantic(sc); e.e1 = resolveProperties(sc, e.e1); - if (e.e1.op == TOK.error) + if (e.e1.op == EXP.error) { result = e.e1; return; @@ -407,7 +408,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) return; } // D1-style operator overloads, deprecated - if (e.op != TOK.prePlusPlus && e.op != TOK.preMinusMinus) + if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus) { auto id = opId(e); fd = search_function(ad, id); @@ -416,7 +417,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) // @@@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)); + e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); // Rewrite +e1 as e1.add() result = build_overload(e.loc, sc, e.e1, null, fd); return; @@ -428,7 +429,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - //printf("att una %s e1 = %s\n", Token::toChars(op), this.e1.type.toChars()); + //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars()); Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident); UnaExp ue = cast(UnaExp)e.copy(); ue.e1 = e1; @@ -444,16 +445,16 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) 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); + const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == TOK.interval); + assert((*ae.arguments)[0].op == EXP.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { - if (ae.e1.op == TOK.error) + if (ae.e1.op == EXP.error) { result = ae.e1; return; @@ -467,7 +468,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) { // 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) + if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type) { // Convert to SliceExp if (maybeSlice) @@ -492,7 +493,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) result = resolveOpDollar(sc, ae, &e0); if (!result) // a[i..j] might be: a.opSlice(i, j) goto Lfallback; - if (result.op == TOK.error) + if (result.op == EXP.error) return; /* Rewrite e1[arguments] as: * e1.opIndex(arguments) @@ -511,7 +512,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) } } Lfallback: - if (maybeSlice && ae.e1.op == TOK.type) + if (maybeSlice && ae.e1.op == EXP.type) { result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); @@ -522,7 +523,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == TOK.error) + if (result.op == EXP.error) return; /* Rewrite a[i..j] as: * a.opSlice(i, j) @@ -615,7 +616,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) int argsset = 0; AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); - if (e.op == TOK.assign && ad1 == ad2) + if (e.op == EXP.assign && ad1 == ad2) { StructDeclaration sd = ad1.isStructDeclaration(); if (sd && @@ -632,13 +633,13 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) Dsymbol s = null; Dsymbol s_r = null; Objects* tiargs = null; - if (e.op == TOK.plusPlus || e.op == TOK.minusMinus) + if (e.op == EXP.plusPlus || e.op == EXP.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) + if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus) { /* Try opBinary and opBinaryRight */ @@ -684,9 +685,9 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) // 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)); + e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); else - e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op)); + e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); } } if (ad2 && id_r) @@ -702,7 +703,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) // @@@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)); + e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); } } } @@ -751,7 +752,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) goto L1; m.lastf = null; } - if (e.op == TOK.plusPlus || e.op == TOK.minusMinus) + if (e.op == EXP.plusPlus || e.op == EXP.minusMinus) { // Kludge because operator overloading regards e++ and e-- // as unary, but it's implemented as a binary. @@ -855,7 +856,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) } Expression tempResult; - if (!(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 + if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { result = checkAliasThisForLhs(ad1, sc, e); if (result) @@ -871,7 +872,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) * one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis` * condition. */ - if (e.op != TOK.assign || e.e1.op == TOK.type) + if (e.op != EXP.assign || e.e1.op == EXP.type) return; if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis)) @@ -888,7 +889,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) tempResult = result; } } - if (!(e.op == TOK.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 + if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { result = checkAliasThisForRhs(ad2, sc, e); if (result) @@ -925,12 +926,12 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) /* 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_) + if (t1.ty == Tclass && e.e2.op == EXP.null_ || + t2.ty == Tclass && e.e1.op == EXP.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)); + EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, + EXPtoString(e.op).ptr); result = ErrorExp.get(); return; } @@ -968,7 +969,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) 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) + if (e.op == EXP.notEqual) result = new NotExp(e.loc, result); result = result.expressionSemantic(sc); return; @@ -978,7 +979,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) result = compare_overload(e, sc, Id.eq, null); if (result) { - if (lastComma(result).op == TOK.call && e.op == TOK.notEqual) + if (lastComma(result).op == EXP.call && e.op == EXP.notEqual) { result = new NotExp(result.loc, result); result = result.expressionSemantic(sc); @@ -998,7 +999,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) * This is just a rewriting for deterministic AST representation * as the backend input. */ - auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity; + auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity; result = new IdentityExp(op2, e.loc, e.e1, e.e2); result = result.expressionSemantic(sc); return; @@ -1016,7 +1017,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) if (!global.params.fieldwise && !needOpEquals(sd)) { // Use bitwise equality. - auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity; + auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity; result = new IdentityExp(op2, e.loc, e.e1, e.e2); result = result.expressionSemantic(sc); return; @@ -1063,7 +1064,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) /* Check for tuple equality. */ - if (e.e1.op == TOK.tuple && e.e2.op == TOK.tuple) + if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple) { auto tup1 = cast(TupleExp)e.e1; auto tup2 = cast(TupleExp)e.e2; @@ -1079,7 +1080,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) if (dim == 0) { // zero-length tuple comparison should always return true or false. - result = IntegerExp.createBool(e.op == TOK.equal); + result = IntegerExp.createBool(e.op == EXP.equal); } else { @@ -1093,10 +1094,10 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) if (!result) result = eeq; - else if (e.op == TOK.equal) - result = new LogicalExp(e.loc, TOK.andAnd, result, eeq); + else if (e.op == EXP.equal) + result = new LogicalExp(e.loc, EXP.andAnd, result, eeq); else - result = new LogicalExp(e.loc, TOK.orOr, result, eeq); + result = new LogicalExp(e.loc, EXP.orOr, result, eeq); } assert(result); } @@ -1119,22 +1120,22 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) override void visit(BinAssignExp e) { //printf("BinAssignExp::op_overload() (%s)\n", e.toChars()); - if (e.e1.op == TOK.array) + if (e.e1.op == EXP.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); + const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval); IntervalExp ie = null; if (maybeSlice && ae.arguments.dim) { - assert((*ae.arguments)[0].op == TOK.interval); + assert((*ae.arguments)[0].op == EXP.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } while (true) { - if (ae.e1.op == TOK.error) + if (ae.e1.op == EXP.error) { result = ae.e1; return; @@ -1152,10 +1153,10 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) 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) + if (result.op == EXP.error) return; result = e.e2.expressionSemantic(sc); - if (result.op == TOK.error) + if (result.op == EXP.error) return; e.e2 = result; /* Rewrite a[arguments] op= e2 as: @@ -1181,10 +1182,10 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == TOK.error) + if (result.op == EXP.error) return; result = e.e2.expressionSemantic(sc); - if (result.op == TOK.error) + if (result.op == EXP.error) return; e.e2 = result; /* Rewrite (a[i..j] op= e2) as: @@ -1261,7 +1262,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) // @@@DEPRECATED_2.098@@@. // Deprecated in 2.088 // Make an error in 2.098 - scope char[] op = Token.toString(e.op).dup; + scope char[] op = EXPtoString(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); } @@ -1319,7 +1320,7 @@ Expression op_overload(Expression e, Scope* sc, TOK* pop = null) /****************************************** * Common code for overloading of EqualExp and CmpExp */ -private Expression compare_overload(BinExp e, Scope* sc, Identifier id, TOK* pop) +private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop) { //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars()); AggregateDeclaration ad1 = isAggregate(e.e1.type); @@ -1415,7 +1416,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, TOK* pop * 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) + if ((e.op == EXP.equal || e.op == EXP.notEqual) && ad1 == ad2) return null; Expression result = checkAliasThisForLhs(ad1, sc, e); return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e); @@ -1482,7 +1483,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out aggr = aggr.expressionSemantic(sc); aggr = resolveProperties(sc, aggr); aggr = aggr.optimize(WANTvalue); - if (!aggr.type || aggr.op == TOK.error) + if (!aggr.type || aggr.op == EXP.error) return false; Type tab = aggr.type.toBasetype(); switch (tab.ty) @@ -1507,7 +1508,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out // opApply aggregate break; } - if (feaggr.op != TOK.type) + if (feaggr.op != EXP.type) { /* See if rewriting `aggr` to `aggr[]` will work */ @@ -1538,7 +1539,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out } case Tdelegate: // https://dlang.org/spec/statement.html#foreach_over_delegates - if (aggr.op == TOK.delegate_) + if (aggr.op == EXP.delegate_) { sapply = (cast(DelegateExp)aggr).func; } @@ -1590,7 +1591,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) ethis = fes.aggr; else { - assert(tab.ty == Tdelegate && fes.aggr.op == TOK.delegate_); + assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_); ethis = (cast(DelegateExp)fes.aggr).e1; } @@ -1854,14 +1855,14 @@ private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool * Returns: * reverse of op */ -private TOK reverseRelation(TOK op) pure +private EXP reverseRelation(EXP 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; + case EXP.greaterOrEqual: op = EXP.lessOrEqual; break; + case EXP.greaterThan: op = EXP.lessThan; break; + case EXP.lessOrEqual: op = EXP.greaterOrEqual; break; + case EXP.lessThan: op = EXP.greaterThan; break; default: break; } return op; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 9f116fe..6b2176b 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -103,14 +103,14 @@ Expression expandVar(int result, VarDeclaration v) } return nullReturn(); } - if (ei.op == TOK.construct || ei.op == TOK.blit) + if (ei.op == EXP.construct || ei.op == EXP.blit) { AssignExp ae = cast(AssignExp)ei; ei = ae.e2; if (ei.isConst() == 1) { } - else if (ei.op == TOK.string_) + else if (ei.op == EXP.string_) { // https://issues.dlang.org/show_bug.cgi?id=14459 // Do not constfold the string literal @@ -136,8 +136,8 @@ Expression expandVar(int result, VarDeclaration v) } else if (!(v.storage_class & STC.manifest) && ei.isConst() != 1 && - ei.op != TOK.string_ && - ei.op != TOK.address) + ei.op != EXP.string_ && + ei.op != EXP.address) { return nullReturn(); } @@ -179,9 +179,8 @@ 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) + if (auto ve = e1.isVarExp()) { - VarExp ve = cast(VarExp)e1; VarDeclaration v = ve.var.isVarDeclaration(); e = expandVar(result, v); if (e) @@ -189,7 +188,7 @@ private Expression fromConstInitializer(int result, Expression e1) // 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) + if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp()) e = e1; else if (e.type != e1.type && e1.type && e1.type.ty != Tident) { @@ -207,9 +206,13 @@ private Expression fromConstInitializer(int result, Expression e1) return e; } -/* It is possible for constant folding to change an array expression of +/*** + * 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. + * Params: + * lengthVar = variable declaration for the `.length` property + * arr = String, ArrayLiteral, or of TypeSArray */ package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr) { @@ -217,37 +220,39 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr) 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; + d_uns64 len; + if (auto se = arr.isStringExp()) + len = se.len; + else if (auto ale = arr.isArrayLiteralExp()) + len = ale.elements.dim; else { - Type t = arr.type.toBasetype(); - if (t.ty == Tsarray) - len = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); - else + auto tsa = arr.type.toBasetype().isTypeSArray(); + if (!tsa) return; // we don't know the length yet + len = tsa.dim.toInteger(); } 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'. */ +/*** + * Same as above, but determines the length from 'type'. + * Params: + * lengthVar = variable declaration for the `.length` property + * type = TypeSArray + */ 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 + auto tsa = type.toBasetype().isTypeSArray(); + if (!tsa) return; // we don't know the length yet + d_uns64 len = tsa.dim.toInteger(); Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t); lengthVar._init = new ExpInitializer(Loc.initial, dollar); lengthVar.storage_class |= STC.static_ | STC.const_; @@ -265,579 +270,477 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) */ 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; + Expression ret = e; - 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(); + } - void error() + /* Returns: true if error + */ + bool expOptimize(ref Expression e, int flags, bool keepLvalue = false) + { + if (!e) + return false; + Expression ex = Expression_optimize(e, flags, keepLvalue); + if (ex.op == EXP.error) { - ret = ErrorExp.get(); + ret = ex; // store error result + return true; } - - bool expOptimize(ref Expression e, int flags, bool keepLvalue = false) + else { - 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; - } + e = ex; // modify original + return false; } + } - bool unaOptimize(UnaExp e, int flags) - { - return expOptimize(e.e1, flags); - } + 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; - } + bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false) + { + return expOptimize(e.e1, flags, keepLhsLvalue) | + expOptimize(e.e2, flags); + } - override void visit(Expression e) - { - //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars()); - } + void visitExp(Expression e) + { + //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars()); + } - override void visit(VarExp e) - { - VarDeclaration v = e.var.isVarDeclaration(); + void visitVar(VarExp e) + { + VarDeclaration v = e.var.isVarDeclaration(); - if (!(keepLvalue && v && !(v.storage_class & STC.manifest))) - ret = fromConstInitializer(result, e); + 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) + // 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) { - // prevent infinite recursion (`<var>.~this()`) - if (!v.inuse) - { - v.inuse++; - expOptimize(v.edtor, WANTvalue); - v.inuse--; - } + v.inuse++; + expOptimize(v.edtor, WANTvalue); + v.inuse--; } } + } - override void visit(TupleExp e) + void visitTuple(TupleExp e) + { + expOptimize(e.e0, WANTvalue); + for (size_t i = 0; i < e.exps.dim; i++) { - expOptimize(e.e0, WANTvalue); - for (size_t i = 0; i < e.exps.dim; i++) - { - expOptimize((*e.exps)[i], WANTvalue); - } + expOptimize((*e.exps)[i], WANTvalue); } + } - override void visit(ArrayLiteralExp e) + void visitArrayLiteral(ArrayLiteralExp e) + { + if (e.elements) { - if (e.elements) + expOptimize(e.basis, result & WANTexpand); + for (size_t i = 0; i < e.elements.dim; i++) { - expOptimize(e.basis, result & WANTexpand); - for (size_t i = 0; i < e.elements.dim; i++) - { - expOptimize((*e.elements)[i], result & WANTexpand); - } + expOptimize((*e.elements)[i], result & WANTexpand); } } + } - override void visit(AssocArrayLiteralExp e) + void visitAssocArrayLiteral(AssocArrayLiteralExp e) + { + assert(e.keys.dim == e.values.dim); + for (size_t i = 0; i < e.keys.dim; i++) { - 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); - } + expOptimize((*e.keys)[i], result & WANTexpand); + expOptimize((*e.values)[i], result & WANTexpand); } + } - override void visit(StructLiteralExp e) + void visitStructLiteral(StructLiteralExp e) + { + if (e.stageflags & stageOptimize) + return; + int old = e.stageflags; + e.stageflags |= stageOptimize; + if (e.elements) { - 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++) { - for (size_t i = 0; i < e.elements.dim; i++) - { - expOptimize((*e.elements)[i], result & WANTexpand); - } + expOptimize((*e.elements)[i], result & WANTexpand); } - e.stageflags = old; } + e.stageflags = old; + } - override void visit(UnaExp e) - { - //printf("UnaExp::optimize() %s\n", e.toChars()); - if (unaOptimize(e, result)) - return; - } + void visitUna(UnaExp e) + { + //printf("UnaExp::optimize() %s\n", e.toChars()); + if (unaOptimize(e, result)) + return; + } - override void visit(NegExp e) + void visitNeg(NegExp e) + { + if (unaOptimize(e, result)) + return; + if (e.e1.isConst() == 1) { - if (unaOptimize(e, result)) - return; - if (e.e1.isConst() == 1) - { - ret = Neg(e.type, e.e1).copy(); - } + ret = Neg(e.type, e.e1).copy(); } + } - override void visit(ComExp e) + void visitCom(ComExp e) + { + if (unaOptimize(e, result)) + return; + if (e.e1.isConst() == 1) { - if (unaOptimize(e, result)) - return; - if (e.e1.isConst() == 1) - { - ret = Com(e.type, e.e1).copy(); - } + ret = Com(e.type, e.e1).copy(); } + } - override void visit(NotExp e) + void visitNop(NotExp e) + { + if (unaOptimize(e, result)) + return; + if (e.e1.isConst() == 1) { - if (unaOptimize(e, result)) - return; - if (e.e1.isConst() == 1) - { - ret = Not(e.type, e.e1).copy(); - } + ret = Not(e.type, e.e1).copy(); } + } - override void visit(SymOffExp e) + void visitSymOff(SymOffExp e) + { + assert(e.var); + } + + void visitAddr(AddrExp e) + { + //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars()); + /* Rewrite &(a,b) as (a,&b) + */ + if (auto ce = e.e1.isCommaExp()) { - assert(e.var); + auto ae = new AddrExp(e.loc, ce.e2, e.type); + ret = new CommaExp(ce.loc, ce.e1, ae); + ret.type = e.type; + return; } - - override void visit(AddrExp e) + // Keep lvalue-ness + if (expOptimize(e.e1, result, true)) + return; + // Convert &*ex to ex + if (auto pe = e.e1.isPtrExp()) { - //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars()); - /* Rewrite &(a,b) as (a,&b) - */ - if (e.e1.op == TOK.comma) + Expression ex = pe.e1; + if (e.type.equals(ex.type)) + ret = ex; + else if (e.type.toBasetype().equivalent(ex.type.toBasetype())) { - 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 = ex.copy(); 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; - } - } } + return; } - - override void visit(PtrExp e) + if (auto ve = e.e1.isVarExp()) { - //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) + if (!ve.var.isReference() && !ve.var.isImportedSymbol()) { - 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) + ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads); + ret.type = e.type; 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) + } + if (auto ae = e.e1.isIndexExp()) + { + // Convert &array[n] to &array+n + if (ae.e2.op == EXP.int64 && ae.e1.isVarExp()) { - SymOffExp se = cast(SymOffExp)e.e1; - VarDeclaration v = se.var.isVarDeclaration(); - Expression ex = expandVar(result, v); - if (ex && ex.op == TOK.structLiteral) + sinteger_t index = ae.e2.toInteger(); + VarExp ve = ae.e1.isVarExp(); + if (ve.type.isTypeSArray() && !ve.var.isImportedSymbol()) { - StructLiteralExp sle = cast(StructLiteralExp)ex; - ex = sle.getField(e.type, cast(uint)se.offset); - if (ex && !CTFEExp.isCantExp(ex)) + TypeSArray ts = ve.type.isTypeSArray(); + sinteger_t dim = ts.dim.toInteger(); + if (index < 0 || index >= dim) { - ret = ex; - return; + e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); + return error(); } - } - } - } - 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)) + import core.checkedint : mulu; + bool overflow; + const offset = mulu(index, ts.nextOf().size(e.loc), overflow); + if (overflow) { - ret = ex; - return; + e.error("array offset overflow"); + return error(); } + + ret = new SymOffExp(e.loc, ve.var, offset); + ret.type = e.type; + return; } } } + } - override void visit(NewExp e) + void visitPtr(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 (auto ey = e.e1.isAddrExp()) { - expOptimize(e.thisexp, WANTvalue); - // Optimize parameters - if (e.newargs) + Expression ex = ey.e1; + if (e.type.equals(ex.type)) + ret = ex; + else if (e.type.toBasetype().equivalent(ex.type.toBasetype())) { - for (size_t i = 0; i < e.newargs.dim; i++) - { - expOptimize((*e.newargs)[i], WANTvalue); - } + ret = ex.copy(); + ret.type = e.type; } - if (e.arguments) + } + if (keepLvalue) + return; + // Constant fold *(&structliteral + offset) + if (e.e1.op == EXP.add) + { + Expression ex = Ptr(e.type, e.e1).copy(); + if (!CTFEExp.isCantExp(ex)) { - for (size_t i = 0; i < e.arguments.dim; i++) - { - expOptimize((*e.arguments)[i], WANTvalue); - } + ret = ex; + return; } } - - override void visit(CallExp e) + if (auto se = e.e1.isSymOffExp()) { - //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) + VarDeclaration v = se.var.isVarDeclaration(); + Expression ex = expandVar(result, v); + if (ex && ex.isStructLiteralExp()) { - 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()) + StructLiteralExp sle = ex.isStructLiteralExp(); + ex = sle.getField(e.type, cast(uint)se.offset); + if (ex && !CTFEExp.isCantExp(ex)) { - 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); - } + ret = ex; + return; } } } + } - override void visit(CastExp e) + void visitDotVar(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 (auto ve = ex.isVarExp()) { - //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)) + VarDeclaration v = ve.var.isVarDeclaration(); + ex = expandVar(result, v); + } + if (ex && ex.isStructLiteralExp()) + { + StructLiteralExp sle = ex.isStructLiteralExp(); + VarDeclaration vf = e.var.isVarDeclaration(); + if (vf && !vf.overlapped) { - 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=13021 + * Prevent optimization if vf has overlapped fields. + */ + ex = sle.getField(e.type, vf.offset); + if (ex && !CTFEExp.isCantExp(ex)) { - // 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()); + ret = ex; 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 (cdfrom.errors || cdto.errors) - return error(); - 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())) + void visitNew(NewExp e) + { + expOptimize(e.thisexp, WANTvalue); + // Optimize parameters + if (e.newargs) + { + for (size_t i = 0; i < e.newargs.dim; i++) { - //printf(" returning5 %s\n", e.e1.toChars()); - goto L1; + expOptimize((*e.newargs)[i], WANTvalue); } - if (e.e1.isConst()) + } + if (e.arguments) + { + for (size_t i = 0; i < e.arguments.dim; i++) { - 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(); - } + expOptimize((*e.arguments)[i], WANTvalue); } - //printf(" returning6 %s\n", ret.toChars()); } + } - override void visit(BinAssignExp e) + void visitCall(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) { - //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) + 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()) { - if (e.e2.isConst() == 1) + for (size_t i = 0; i < e.arguments.dim; i++) { - 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(); - } + Parameter p = tf.parameterList[i]; + bool keep = p && p.isReference(); + expOptimize((*e.arguments)[i], WANTvalue, keep); } } } + } - override void visit(BinExp e) + void visitCast(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); + const 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 == EXP.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray) { - //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); + // Casting this will result in the same expression, and + // infinite loop because of Expression::implicitCastTo() + return; // no change } - - override void visit(AddExp e) + if ((e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral) && + (e.type.ty == Tpointer || e.type.ty == Tarray)) { - //printf("AddExp::optimize(%s)\n", e.toChars()); - if (binOptimize(e, result)) - return; - if (e.e1.isConst() && e.e2.isConst()) + 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) { - if (e.e1.op == TOK.symbolOffset && e.e2.op == TOK.symbolOffset) + // 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 = Add(e.loc, e.type, e.e1, e.e2).copy(); + ret = e.e1.castTo(null, e.type); + //printf(" returning1 %s\n", ret.toChars()); + return; } } - override void visit(MinExp e) + if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) { - 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(); - } + //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; } - - override void visit(MulExp e) + /* The first test here is to prevent infinite loops + */ + if (op1 != EXP.arrayLiteral && e.e1.op == EXP.arrayLiteral) { - //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(); - } + ret = e.e1.castTo(null, e.to); + return; } - - override void visit(DivExp e) + if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray)) { - //printf("DivExp::optimize(%s)\n", e.toChars()); - if (binOptimize(e, result)) - return; - if (e.e1.isConst() == 1 && e.e2.isConst() == 1) + //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 (cdfrom.errors || cdto.errors) + return error(); + 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) { - ret = Div(e.loc, e.type, e.e1, e.e2).copy(); + //printf(" returning4 %s\n", e.e1.toChars()); + goto L1; } } - - override void visit(ModExp e) + if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf())) { - if (binOptimize(e, result)) + //printf(" returning5 %s\n", e.e1.toChars()); + goto L1; + } + if (e.e1.isConst()) + { + if (e.e1.op == EXP.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.e1.isConst() == 1 && e.e2.isConst() == 1) + } + if (e.to.toBasetype().ty != Tvoid) { - ret = Mod(e.loc, e.type, e.e1, e.e2).copy(); + 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()); + } - extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift) + void visitBinAssign(BinAssignExp e) + { + //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars()); + if (binOptimize(e, result, /*keepLhsLvalue*/ true)) + return; + if (e.op == EXP.leftShiftAssign || e.op == EXP.rightShiftAssign || e.op == EXP.unsignedRightShiftAssign) { - if (binOptimize(e, result)) - return; if (e.e2.isConst() == 1) { sinteger_t i2 = e.e2.toInteger(); @@ -846,329 +749,410 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) sz *= 8; if (i2 < 0 || i2 >= sz) { - e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1); + e.error("shift assign 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); - } + void visitBin(BinExp e) + { + //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars()); + const keepLhsLvalue = e.op == EXP.construct || e.op == EXP.blit || e.op == EXP.assign + || e.op == EXP.plusPlus || e.op == EXP.minusMinus + || e.op == EXP.prePlusPlus || e.op == EXP.preMinusMinus; + binOptimize(e, result, keepLhsLvalue); + } - override void visit(ShrExp e) + void visitAdd(AddExp e) + { + //printf("AddExp::optimize(%s)\n", e.toChars()); + if (binOptimize(e, result)) + return; + if (e.e1.isConst() && e.e2.isConst()) { - //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars()); - shift_optimize(e, &Shr); + if (e.e1.op == EXP.symbolOffset && e.e2.op == EXP.symbolOffset) + return; + ret = Add(e.loc, e.type, e.e1, e.e2).copy(); } + } - override void visit(UshrExp e) + void visitMin(MinExp e) + { + if (binOptimize(e, result)) + return; + if (e.e1.isConst() && e.e2.isConst()) { - //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); - shift_optimize(e, &Ushr); + if (e.e2.op == EXP.symbolOffset) + return; + ret = Min(e.loc, e.type, e.e1, e.e2).copy(); } + } - override void visit(AndExp e) + void visitMul(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) { - 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(); + ret = Mul(e.loc, e.type, e.e1, e.e2).copy(); } + } - override void visit(OrExp e) + void visitDiv(DivExp e) + { + //printf("DivExp::optimize(%s)\n", e.toChars()); + if (binOptimize(e, result)) + return; + if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { - 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(); + ret = Div(e.loc, e.type, e.e1, e.e2).copy(); } + } - override void visit(XorExp e) + void visitMod(ModExp e) + { + if (binOptimize(e, result)) + return; + if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { - 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(); + ret = Mod(e.loc, e.type, e.e1, e.e2).copy(); } + } - override void visit(PowExp e) + 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) { - 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) + 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("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()); + e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1); 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; - } - } + if (e.e1.isConst() == 1) + ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy(); } + } + + void visitShl(ShlExp e) + { + //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars()); + shift_optimize(e, &Shl); + } + + void visitShr(ShrExp e) + { + //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars()); + shift_optimize(e, &Shr); + } + + void visitUshr(UshrExp e) + { + //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); + shift_optimize(e, &Ushr); + } - override void visit(CommaExp e) + void visitAnd(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 visitOr(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 visitXor(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 visitPow(PowExp e) + { + if (binOptimize(e, result)) + return; + // All negative integral powers are illegal. + if (e.e1.type.isintegral() && (e.e2.op == EXP.int64) && cast(sinteger_t)e.e2.toInteger() < 0) { - //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()); + 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(); } - - override void visit(ArrayLengthExp e) + // If e2 *could* have been an integer, make it one. + if (e.e2.op == EXP.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal())) { - //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(); - } + // 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); } - - override void visit(EqualExp e) + if (e.e1.isConst() == 1 && e.e2.isConst() == 1) { - //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) + Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy(); + if (!CTFEExp.isCantExp(ex)) { - ret = e1; + ret = ex; 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) + void visitComma(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 == EXP.error) + return; + if (!e.e1 || e.e1.op == EXP.int64 || e.e1.op == EXP.float64 || !hasSideEffect(e.e1)) { - //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 = e.e2; + if (ret) + ret.type = e.type; + } + //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars()); + } + + void visitArrayLength(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 (auto ve = e.e1.isVarExp()) + { + VarDeclaration v = ve.var.isVarDeclaration(); + if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init) { - ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy(); - if (CTFEExp.isCantExp(ret)) - ret = e; + if (Expression ci = v.getConstInitializer()) + e.e1 = ci; } } + if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray) + { + ret = ArrayLength(e.type, e.e1).copy(); + } + } - override void visit(IndexExp e) + void visitEqual(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 == EXP.error) { - //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; + ret = e1; + return; + } + if (e2.op == EXP.error) + { + ret = e2; + return; } + ret = Equal(e.op, e.loc, e.type, e1, e2).copy(); + if (CTFEExp.isCantExp(ret)) + ret = e; + } - override void visit(SliceExp e) + void visitIdentity(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 == EXP.null_ && e.e2.op == EXP.null_)) { - //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 = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy(); + if (CTFEExp.isCantExp(ret)) ret = e; - } - //printf("-SliceExp::optimize() %s\n", ret.toChars()); } + } + + void visitIndex(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 == EXP.arrayLiteral) + return; + ret = Index(e.type, ex, e.e2).copy(); + if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue())) + ret = e; + } - override void visit(LogicalExp e) + void visitSlice(SliceExp e) + { + //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars()); + if (expOptimize(e.e1, result & WANTexpand)) + return; + if (!e.lwr) { - //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.e1.op == EXP.string_) { - 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; - } - } + // 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()); } } - - override void visit(CmpExp e) + else { - //printf("CmpExp::optimize() %s\n", e.toChars()); - if (binOptimize(e, WANTvalue)) + 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 == EXP.error) return; - Expression e1 = fromConstInitializer(result, e.e1); - Expression e2 = fromConstInitializer(result, e.e2); - ret = Cmp(e.op, e.loc, e.type, e1, e2).copy(); + 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 == EXP.string_) + { + e.e1 = ret; + e.lwr = null; + e.upr = null; + ret = e; + } + //printf("-SliceExp::optimize() %s\n", ret.toChars()); + } - override void visit(CatExp e) + void visitLogical(LogicalExp e) + { + //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars()); + if (expOptimize(e.e1, WANTvalue)) + return; + const oror = e.op == EXP.orOr; + if (e.e1.toBool().hasValue(oror)) { - //printf("CatExp::optimize(%d) %s\n", result, e.toChars()); - if (binOptimize(e, result)) - return; - if (e.e1.op == TOK.concatenate) + // Replace with (e1, oror) + ret = IntegerExp.createBool(oror); + ret = Expression.combine(e.e1, ret); + if (e.type.toBasetype().ty == Tvoid) { - // 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; - } + ret = new CastExp(e.loc, ret, Type.tvoid); + ret.type = e.type; } - // optimize "str"[] -> "str" - if (e.e1.op == TOK.slice) + ret = Expression_optimize(ret, result, false); + return; + } + expOptimize(e.e2, WANTvalue); + if (e.e1.isConst()) + { + const e1Opt = e.e1.toBool(); + if (e.e2.isConst()) { - SliceExp se1 = cast(SliceExp)e.e1; - if (se1.e1.op == TOK.string_ && !se1.lwr) - e.e1 = se1.e1; + bool n1 = e1Opt.hasValue(true); + bool n2 = e.e2.toBool().hasValue(true); + ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type); } - if (e.e2.op == TOK.slice) + else if (e1Opt.hasValue(!oror)) { - SliceExp se2 = cast(SliceExp)e.e2; - if (se2.e1.op == TOK.string_ && !se2.lwr) - e.e2 = se2.e1; + if (e.type.toBasetype().ty == Tvoid) + ret = e.e2; + else + { + ret = new CastExp(e.loc, e.e2, e.type); + ret.type = e.type; + } } - ret = Cat(e.loc, e.type, e.e1, e.e2).copy(); - if (CTFEExp.isCantExp(ret)) - ret = e; } + } - override void visit(CondExp e) + void visitCmp(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 visitCat(CatExp e) + { + //printf("CatExp::optimize(%d) %s\n", result, e.toChars()); + if (binOptimize(e, result)) + return; + if (auto ce1 = e.e1.isCatExp()) { - 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 + // https://issues.dlang.org/show_bug.cgi?id=12798 + // optimize ((expr ~ str1) ~ str2) + 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) { - expOptimize(e.e1, result, keepLvalue); - expOptimize(e.e2, result, keepLvalue); + e.e1 = ce1.e1; + e.e2 = ex; } } + // optimize "str"[] -> "str" + if (auto se1 = e.e1.isSliceExp()) + { + if (se1.e1.op == EXP.string_ && !se1.lwr) + e.e1 = se1.e1; + } + if (auto se2 = e.e2.isSliceExp()) + { + if (se2.e1.op == EXP.string_ && !se2.lwr) + e.e2 = se2.e1; + } + ret = Cat(e.loc, e.type, e.e1, e.e2).copy(); + if (CTFEExp.isCantExp(ret)) + ret = e; } - scope OptimizeVisitor v = new OptimizeVisitor(e, result, keepLvalue); + void visitCond(CondExp e) + { + if (expOptimize(e.econd, WANTvalue)) + return; + const opt = e.econd.toBool(); + if (opt.hasValue(true)) + ret = Expression_optimize(e.e1, result, keepLvalue); + else if (opt.hasValue(false)) + ret = Expression_optimize(e.e2, result, keepLvalue); + else + { + expOptimize(e.e1, result, keepLvalue); + expOptimize(e.e2, result, keepLvalue); + } + } // Optimize the expression until it can no longer be simplified. size_t b; @@ -1179,10 +1163,103 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) e.error("infinite loop while optimizing expression"); fatal(); } - auto ex = v.ret; - ex.accept(v); - if (ex == v.ret) + + auto ex = ret; + switch (ex.op) + { + case EXP.variable: visitVar(ex.isVarExp()); break; + case EXP.tuple: visitTuple(ex.isTupleExp()); break; + case EXP.arrayLiteral: visitArrayLiteral(ex.isArrayLiteralExp()); break; + case EXP.assocArrayLiteral: visitAssocArrayLiteral(ex.isAssocArrayLiteralExp()); break; + case EXP.structLiteral: visitStructLiteral(ex.isStructLiteralExp()); break; + + case EXP.import_: + case EXP.assert_: + case EXP.dotIdentifier: + case EXP.dotTemplateDeclaration: + case EXP.dotTemplateInstance: + case EXP.delegate_: + case EXP.dotType: + case EXP.uadd: + case EXP.delete_: + case EXP.vector: + case EXP.vectorArray: + case EXP.array: + case EXP.delegatePointer: + case EXP.delegateFunctionPointer: + case EXP.preMinusMinus: + case EXP.prePlusPlus: visitUna(cast(UnaExp)ex); break; + + case EXP.negate: visitNeg(ex.isNegExp()); break; + case EXP.tilde: visitCom(ex.isComExp()); break; + case EXP.not: visitNop(ex.isNotExp()); break; + case EXP.symbolOffset: visitSymOff(ex.isSymOffExp()); break; + case EXP.address: visitAddr(ex.isAddrExp()); break; + case EXP.star: visitPtr(ex.isPtrExp()); break; + case EXP.dotVariable: visitDotVar(ex.isDotVarExp()); break; + case EXP.new_: visitNew(ex.isNewExp()); break; + case EXP.call: visitCall(ex.isCallExp()); break; + case EXP.cast_: visitCast(ex.isCastExp()); break; + + case EXP.addAssign: + case EXP.minAssign: + case EXP.mulAssign: + case EXP.divAssign: + case EXP.modAssign: + case EXP.andAssign: + case EXP.orAssign: + case EXP.xorAssign: + case EXP.powAssign: + case EXP.leftShiftAssign: + case EXP.rightShiftAssign: + case EXP.unsignedRightShiftAssign: + case EXP.concatenateElemAssign: + case EXP.concatenateDcharAssign: + case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break; + + case EXP.minusMinus: + case EXP.plusPlus: + case EXP.assign: + case EXP.construct: + case EXP.blit: + case EXP.in_: + case EXP.remove: + case EXP.dot: visitBin(cast(BinExp)ex); break; + + case EXP.add: visitAdd(ex.isAddExp()); break; + case EXP.min: visitMin(ex.isMinExp()); break; + case EXP.mul: visitMul(ex.isMulExp()); break; + case EXP.div: visitDiv(ex.isDivExp()); break; + case EXP.mod: visitMod(ex.isModExp()); break; + case EXP.leftShift: visitShl(ex.isShlExp()); break; + case EXP.rightShift: visitShr(ex.isShrExp()); break; + case EXP.unsignedRightShift: visitUshr(ex.isUshrExp()); break; + case EXP.and: visitAnd(ex.isAndExp()); break; + case EXP.or: visitOr(ex.isOrExp()); break; + case EXP.xor: visitXor(ex.isXorExp()); break; + case EXP.pow: visitPow(ex.isPowExp()); break; + case EXP.comma: visitComma(ex.isCommaExp()); break; + case EXP.arrayLength: visitArrayLength(ex.isArrayLengthExp()); break; + case EXP.notEqual: + case EXP.equal: visitEqual(ex.isEqualExp()); break; + case EXP.notIdentity: + case EXP.identity: visitIdentity(ex.isIdentityExp()); break; + case EXP.index: visitIndex(ex.isIndexExp()); break; + case EXP.slice: visitSlice(ex.isSliceExp()); break; + case EXP.andAnd: + case EXP.orOr: visitLogical(ex.isLogicalExp()); break; + case EXP.lessThan: + case EXP.lessOrEqual: + case EXP.greaterThan: + case EXP.greaterOrEqual: visitCmp(cast(CmpExp)ex); break; + case EXP.concatenate: visitCat(ex.isCatExp()); break; + case EXP.question: visitCond(ex.isCondExp()); break; + + default: visitExp(ex); break; + } + + if (ex == ret) break; } - return v.ret; + return ret; } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index f00ceb6..2229e78 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -50,146 +50,146 @@ private enum CARRAYDECL = 1; * * Used by hdrgen */ -immutable PREC[TOK.max + 1] precedence = +immutable PREC[EXP.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, + EXP.type : PREC.expr, + EXP.error : PREC.expr, + EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type + + EXP.typeof_ : PREC.primary, + EXP.mixin_ : PREC.primary, + + EXP.import_ : PREC.primary, + EXP.dotVariable : PREC.primary, + EXP.scope_ : PREC.primary, + EXP.identifier : PREC.primary, + EXP.this_ : PREC.primary, + EXP.super_ : PREC.primary, + EXP.int64 : PREC.primary, + EXP.float64 : PREC.primary, + EXP.complex80 : PREC.primary, + EXP.null_ : PREC.primary, + EXP.string_ : PREC.primary, + EXP.arrayLiteral : PREC.primary, + EXP.assocArrayLiteral : PREC.primary, + EXP.classReference : PREC.primary, + EXP.file : PREC.primary, + EXP.fileFullPath : PREC.primary, + EXP.line : PREC.primary, + EXP.moduleString : PREC.primary, + EXP.functionString : PREC.primary, + EXP.prettyFunction : PREC.primary, + EXP.typeid_ : PREC.primary, + EXP.is_ : PREC.primary, + EXP.assert_ : PREC.primary, + EXP.halt : PREC.primary, + EXP.template_ : PREC.primary, + EXP.dSymbol : PREC.primary, + EXP.function_ : PREC.primary, + EXP.variable : PREC.primary, + EXP.symbolOffset : PREC.primary, + EXP.structLiteral : PREC.primary, + EXP.compoundLiteral : PREC.primary, + EXP.arrayLength : PREC.primary, + EXP.delegatePointer : PREC.primary, + EXP.delegateFunctionPointer : PREC.primary, + EXP.remove : PREC.primary, + EXP.tuple : PREC.primary, + EXP.traits : PREC.primary, + EXP.default_ : PREC.primary, + EXP.overloadSet : PREC.primary, + EXP.void_ : PREC.primary, + EXP.vectorArray : PREC.primary, + EXP._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, + EXP.dotTemplateInstance : PREC.primary, + EXP.dotIdentifier : PREC.primary, + EXP.dotTemplateDeclaration : PREC.primary, + EXP.dot : PREC.primary, + EXP.dotType : PREC.primary, + EXP.plusPlus : PREC.primary, + EXP.minusMinus : PREC.primary, + EXP.prePlusPlus : PREC.primary, + EXP.preMinusMinus : PREC.primary, + EXP.call : PREC.primary, + EXP.slice : PREC.primary, + EXP.array : PREC.primary, + EXP.index : PREC.primary, + + EXP.delegate_ : PREC.unary, + EXP.address : PREC.unary, + EXP.star : PREC.unary, + EXP.negate : PREC.unary, + EXP.uadd : PREC.unary, + EXP.not : PREC.unary, + EXP.tilde : PREC.unary, + EXP.delete_ : PREC.unary, + EXP.new_ : PREC.unary, + EXP.newAnonymousClass : PREC.unary, + EXP.cast_ : PREC.unary, + + EXP.vector : PREC.unary, + EXP.pow : PREC.pow, + + EXP.mul : PREC.mul, + EXP.div : PREC.mul, + EXP.mod : PREC.mul, + + EXP.add : PREC.add, + EXP.min : PREC.add, + EXP.concatenate : PREC.add, + + EXP.leftShift : PREC.shift, + EXP.rightShift : PREC.shift, + EXP.unsignedRightShift : PREC.shift, + + EXP.lessThan : PREC.rel, + EXP.lessOrEqual : PREC.rel, + EXP.greaterThan : PREC.rel, + EXP.greaterOrEqual : PREC.rel, + EXP.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, + EXP.equal : PREC.rel, + EXP.notEqual : PREC.rel, + EXP.identity : PREC.rel, + EXP.notIdentity : PREC.rel, + + EXP.and : PREC.and, + EXP.xor : PREC.xor, + EXP.or : PREC.or, + + EXP.andAnd : PREC.andand, + EXP.orOr : PREC.oror, + + EXP.question : PREC.cond, + + EXP.assign : PREC.assign, + EXP.construct : PREC.assign, + EXP.blit : PREC.assign, + EXP.addAssign : PREC.assign, + EXP.minAssign : PREC.assign, + EXP.concatenateAssign : PREC.assign, + EXP.concatenateElemAssign : PREC.assign, + EXP.concatenateDcharAssign : PREC.assign, + EXP.mulAssign : PREC.assign, + EXP.divAssign : PREC.assign, + EXP.modAssign : PREC.assign, + EXP.powAssign : PREC.assign, + EXP.leftShiftAssign : PREC.assign, + EXP.rightShiftAssign : PREC.assign, + EXP.unsignedRightShiftAssign : PREC.assign, + EXP.andAssign : PREC.assign, + EXP.orAssign : PREC.assign, + EXP.xorAssign : PREC.assign, + + EXP.comma : PREC.expr, + EXP.declaration : PREC.expr, + + EXP.interval : PREC.assign, ]; enum ParseStatementFlags : int @@ -4079,7 +4079,7 @@ class Parser(AST) : Lexer // Handle delegate declaration: // t delegate(parameter list) nothrow pure // t function(parameter list) nothrow pure - TOK save = token.value; + const save = token.value; nextToken(); auto parameterList = parseParameterList(null); @@ -5752,7 +5752,7 @@ LagainStc: * 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) + if (token.value == TOK.identifier && exp.op == EXP.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(); @@ -5911,7 +5911,7 @@ LagainStc: // mixin(string) AST.Expression e = parseAssignExp(); check(TOK.semicolon); - if (e.op == TOK.mixin_) + if (e.op == EXP.mixin_) { AST.MixinExp cpe = cast(AST.MixinExp)e; s = new AST.CompileStatement(loc, cpe.exps); @@ -6816,8 +6816,8 @@ LagainStc: { 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.file: e = new AST.FileInitExp(token.loc, EXP.file); break; + case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.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; @@ -8470,14 +8470,14 @@ LagainStc: nextToken(); e = parseUnaryExp(); //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - e = new AST.PreExp(TOK.prePlusPlus, loc, e); + e = new AST.PreExp(EXP.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); + e = new AST.PreExp(EXP.preMinusMinus, loc, e); break; case TOK.mul: @@ -8785,11 +8785,11 @@ LagainStc: break; case TOK.plusPlus: - e = new AST.PostExp(TOK.plusPlus, loc, e); + e = new AST.PostExp(EXP.plusPlus, loc, e); break; case TOK.minusMinus: - e = new AST.PostExp(TOK.minusMinus, loc, e); + e = new AST.PostExp(EXP.minusMinus, loc, e); break; case TOK.leftParenthesis: @@ -8946,21 +8946,18 @@ LagainStc: const loc = token.loc; auto e = parseShiftExp(); - TOK op = token.value; + EXP op = EXP.reserved; - switch (op) + switch (token.value) { - case TOK.equal: - case TOK.notEqual: + case TOK.equal: op = EXP.equal; goto Lequal; + case TOK.notEqual: op = EXP.notEqual; goto Lequal; + Lequal: 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' @@ -8977,19 +8974,21 @@ LagainStc: if (tv != TOK.is_) break; nextToken(); - op = TOK.notIdentity; - goto L1; + op = EXP.notIdentity; + goto Lidentity; } - L1: + case TOK.is_: op = EXP.identity; goto Lidentity; + Lidentity: 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: + case TOK.lessThan: op = EXP.lessThan; goto Lcmp; + case TOK.lessOrEqual: op = EXP.lessOrEqual; goto Lcmp; + case TOK.greaterThan: op = EXP.greaterThan; goto Lcmp; + case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp; + Lcmp: nextToken(); auto e2 = parseShiftExp(); e = new AST.CmpExp(op, loc, e, e2); @@ -9064,7 +9063,7 @@ LagainStc: { nextToken(); auto e2 = parseOrExp(); - e = new AST.LogicalExp(loc, TOK.andAnd, e, e2); + e = new AST.LogicalExp(loc, EXP.andAnd, e, e2); } return e; } @@ -9078,7 +9077,7 @@ LagainStc: { nextToken(); auto e2 = parseAndAndExp(); - e = new AST.LogicalExp(loc, TOK.orOr, e, e2); + e = new AST.LogicalExp(loc, EXP.orOr, e, e2); } return e; } @@ -9107,92 +9106,109 @@ LagainStc: 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)); + void checkRequiredParens() + { + if (e.op == EXP.question && !e.parens) + 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: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.AssignExp(loc, e, e2); break; case TOK.addAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.AddAssignExp(loc, e, e2); break; case TOK.minAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.MinAssignExp(loc, e, e2); break; case TOK.mulAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.MulAssignExp(loc, e, e2); break; case TOK.divAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.DivAssignExp(loc, e, e2); break; case TOK.modAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.ModAssignExp(loc, e, e2); break; case TOK.powAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.PowAssignExp(loc, e, e2); break; case TOK.andAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.AndAssignExp(loc, e, e2); break; case TOK.orAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.OrAssignExp(loc, e, e2); break; case TOK.xorAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.XorAssignExp(loc, e, e2); break; case TOK.leftShiftAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.ShlAssignExp(loc, e, e2); break; case TOK.rightShiftAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.ShrAssignExp(loc, e, e2); break; case TOK.unsignedRightShiftAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.UshrAssignExp(loc, e, e2); break; case TOK.concatenateAssign: + checkRequiredParens(); nextToken(); auto e2 = parseAssignExp(); e = new AST.CatAssignExp(loc, e, e2); diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index 414d6f6..b9f0c5e 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -16,6 +16,7 @@ import core.stdc.stdio; import dmd.expression; import dmd.tokens; import dmd.visitor; +import dmd.hdrgen; /******************** * Print AST data structure in a nice format. @@ -45,7 +46,8 @@ extern (C++) final class PrintASTVisitor : Visitor override void visit(Expression e) { printIndent(indent); - printf("%s %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : ""); + auto s = EXPtoString(e.op); + printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : ""); } override void visit(IntegerExp e) @@ -68,7 +70,8 @@ extern (C++) final class PrintASTVisitor : Visitor override void visit(StructLiteralExp e) { printIndent(indent); - printf("%s %s, %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "", e.toChars()); + auto s = EXPtoString(e.op); + printf("%.*s %s, %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "", e.toChars()); } override void visit(SymbolExp e) diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h index 88f2095..8b0bcf2 100644 --- a/gcc/d/dmd/root/dcompat.h +++ b/gcc/d/dmd/root/dcompat.h @@ -43,6 +43,9 @@ typedef unsigned d_size_t; __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; +#elif defined(__OpenBSD__) && !defined(__LP64__) +// size_t is 'unsigned long', which makes it mangle differently than D's 'uint' +typedef unsigned d_size_t; #else typedef size_t d_size_t; #endif diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index 64e9571..2722529 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -120,11 +120,10 @@ nothrow: 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; + // Always store a wchar ^Z past end of buffer so scanner has a + // sentinel, although ^Z got obselete, so fill with two 0s and add + // two more so lexer doesn't read pass the buffer. + buffer[size .. size + 4] = 0; result.success = true; result.buffer.data = buffer[0 .. size]; @@ -160,11 +159,10 @@ nothrow: 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; + // Always store a wchar ^Z past end of buffer so scanner has a + // sentinel, although ^Z got obselete, so fill with two 0s and add + // two more so lexer doesn't read pass the buffer. + buffer[size .. size + 4] = 0; result.success = true; result.buffer.data = buffer[0 .. size]; return result; diff --git a/gcc/d/dmd/root/optional.d b/gcc/d/dmd/root/optional.d new file mode 100644 index 0000000..a593ddd --- /dev/null +++ b/gcc/d/dmd/root/optional.d @@ -0,0 +1,86 @@ +/** + * Optional 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/optional.d, root/_optional.d) + * Documentation: https://dlang.org/phobos/dmd_root_optional.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.d + */ +module dmd.root.optional; + +/// +unittest +{ + import core.exception : AssertError; + + Optional!int opt; + assert( opt.isEmpty()); + assert(!opt.isPresent()); + assert(!opt.hasValue(1)); + assert(!opt.hasValue(2)); + + bool caught; + try + cast(void) opt.get(); + catch (AssertError) + caught = true; + assert(caught); + + opt = Optional!int(1); + assert(!opt.isEmpty()); + assert( opt.isPresent()); + assert( opt.get() == 1); + assert( opt.hasValue(1)); + assert(!opt.hasValue(2)); +} + +/// Optional type that is either `empty` or contains a value of type `T` +extern (C++) struct Optional(T) +{ + /// the value (if present) + private T value; + + /// whether `value` is set + private bool present; + + /// Creates an `Optional` with the given value + this(T value) + { + this.value = value; + this.present = true; + } + + // Ctor wrapper for the C++ interface (required by older host compilers) + /// ditto + static Optional!T create(T val) + { + return Optional!T(val); + } + + /// Returns: Whether this `Optional` contains a value + bool isPresent() const + { + return this.present; + } + + /// Returns: Whether this `Optional` does not contain a value + bool isEmpty() const + { + return !this.present; + } + + /// Returns: The value if present + inout(T) get() inout + { + assert(present); + return value; + } + + /// Returns: Whether this `Optional` contains the supplied value + bool hasValue(const T exp) const + { + return present && value == exp; + } +} diff --git a/gcc/d/dmd/root/optional.h b/gcc/d/dmd/root/optional.h new file mode 100644 index 0000000..fa52b58 --- /dev/null +++ b/gcc/d/dmd/root/optional.h @@ -0,0 +1,42 @@ +#pragma once + +/** + * Optional 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/optional.h, root/_optional.h) + * Documentation: https://dlang.org/phobos/dmd_root_optional.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.h + */ + +/// Optional type that is either `empty` or contains a value of type `T` +template<typename T> +struct Optional final +{ +private: + /** the value (if present) **/ + T value; + + /** whether `value` is set **/ + bool present; + +public: + /** Creates an `Optional` with the given value **/ + Optional(T); + + /** Creates an `Optional` with the given value **/ + static Optional<T> create(T); + + /** Checks whether this `Optional` contains a value **/ + bool isPresent() const; + + /** Checks whether this `Optional` does not contain a value **/ + bool isEmpty() const; + + /** Returns: The value if present **/ + T get(); + + bool hasValue(const T) const; +}; diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 8904959..7eb3e23 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -46,7 +46,7 @@ import dmd.tokens; 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) + if (e.op != EXP.dotVariable) return false; DotVarExp dve = cast(DotVarExp)e; if (VarDeclaration v = dve.var.isVarDeclaration()) @@ -170,7 +170,7 @@ bool isSafeCast(Expression e, Type tfrom, Type tto) */ if (tfromn.ty == Tvoid && ttobn.isMutable()) { - if (ttob.ty == Tarray && e.op == TOK.arrayLiteral) + if (ttob.ty == Tarray && e.op == EXP.arrayLiteral) return true; return false; } diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 993db90..c3fe752 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -278,15 +278,15 @@ private extern(C++) final class Semantic2Visitor : Visitor return false; } - if (e.op == TOK.classReference) + if (e.op == EXP.classReference) return true; - if (e.op == TOK.address && (cast(AddrExp)e).e1.op == TOK.structLiteral) + if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral) return true; - if (e.op == TOK.arrayLiteral) + if (e.op == EXP.arrayLiteral) return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements); - if (e.op == TOK.structLiteral) + if (e.op == EXP.structLiteral) return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements); - if (e.op == TOK.assocArrayLiteral) + if (e.op == EXP.assocArrayLiteral) { AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; return arrayHasInvalidEnumInitializer(ae.values) || @@ -306,13 +306,13 @@ private extern(C++) final class Semantic2Visitor : Visitor if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared()) { ExpInitializer ei = vd._init.isExpInitializer(); - if (ei && ei.exp.op == TOK.classReference) + if (ei && ei.exp.op == EXP.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) + if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral) vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead."); } } @@ -569,7 +569,7 @@ private extern(C++) final class Semantic2Visitor : Visitor e = e.expressionSemantic(sc); if (definitelyValueParameter(e)) e = e.ctfeInterpret(); - if (e.op == TOK.tuple) + if (e.op == EXP.tuple) { TupleExp te = cast(TupleExp)e; eval(sc, te.exps, lastTag); @@ -697,7 +697,7 @@ 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) + if (e.op == EXP.type) { e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars()); return; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 3852d0b..893f96b 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -611,7 +611,7 @@ private extern(C++) final class Semantic3Visitor : Visitor 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 (exp.op == EXP.variable && (cast(VarExp)exp).var == funcdecl.vresult) { if (addReturn0()) exp.type = Type.tint32; @@ -817,7 +817,7 @@ private extern(C++) final class Semantic3Visitor : Visitor { ReturnStatement rs = (*funcdecl.returns)[i]; Expression exp = rs.exp; - if (exp.op == TOK.error) + if (exp.op == EXP.error) continue; if (tret.ty == Terror) { diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index d238150..99833b5 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -47,7 +47,7 @@ extern (C++) bool isTrivialExp(Expression e) * CallExp is always non trivial expression, * especially for inlining. */ - if (e.op == TOK.call) + if (e.op == EXP.call) { stop = true; return; @@ -153,36 +153,36 @@ 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: + case EXP.assign: + case EXP.plusPlus: + case EXP.minusMinus: + case EXP.declaration: + case EXP.construct: + case EXP.blit: + case EXP.addAssign: + case EXP.minAssign: + case EXP.concatenateAssign: + case EXP.concatenateElemAssign: + case EXP.concatenateDcharAssign: + case EXP.mulAssign: + case EXP.divAssign: + case EXP.modAssign: + case EXP.leftShiftAssign: + case EXP.rightShiftAssign: + case EXP.unsignedRightShiftAssign: + case EXP.andAssign: + case EXP.orAssign: + case EXP.xorAssign: + case EXP.powAssign: + case EXP.in_: + case EXP.remove: + case EXP.assert_: + case EXP.halt: + case EXP.delete_: + case EXP.new_: + case EXP.newAnonymousClass: return true; - case TOK.call: + case EXP.call: { if (assumeImpureCalls) return true; @@ -207,13 +207,13 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false) } break; } - case TOK.cast_: + case EXP.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) + if (ce.to.ty == Tclass && ce.e1.op == EXP.call && ce.e1.type.ty == Tclass) return true; break; } @@ -235,7 +235,7 @@ bool discardValue(Expression e) return false; switch (e.op) { - case TOK.cast_: + case EXP.cast_: { CastExp ce = cast(CastExp)e; if (ce.to.equals(Type.tvoid)) @@ -247,9 +247,9 @@ bool discardValue(Expression e) } break; // complain } - case TOK.error: + case EXP.error: return false; - case TOK.variable: + case EXP.variable: { VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); if (v && (v.storage_class & STC.temp)) @@ -260,7 +260,7 @@ bool discardValue(Expression e) } break; } - case TOK.call: + case EXP.call: /* Issue 3882: */ if (global.params.warnings != DiagnosticReporting.off && !global.gag) { @@ -285,7 +285,7 @@ bool discardValue(Expression e) const(char)* s; if (ce.f) s = ce.f.toPrettyChars(); - else if (ce.e1.op == TOK.star) + else if (ce.e1.op == EXP.star) { // print 'fp' if ce.e1 is (*fp) s = (cast(PtrExp)ce.e1).e1.toChars(); @@ -297,13 +297,13 @@ bool discardValue(Expression e) } } return false; - case TOK.andAnd: - case TOK.orOr: + case EXP.andAnd: + case EXP.orOr: { LogicalExp aae = cast(LogicalExp)e; return discardValue(aae.e2); } - case TOK.question: + case EXP.question: { CondExp ce = cast(CondExp)e; /* https://issues.dlang.org/show_bug.cgi?id=6178 @@ -333,7 +333,7 @@ bool discardValue(Expression e) } return false; } - case TOK.comma: + case EXP.comma: { CommaExp ce = cast(CommaExp)e; // Don't complain about compiler-generated comma expressions @@ -344,7 +344,7 @@ bool discardValue(Expression e) // This is concretely done in expressionSemantic, if a CommaExp has Tvoid as type return discardValue(ce.e2); } - case TOK.tuple: + case EXP.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. diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 9eba2ff..6979cdf 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -125,7 +125,7 @@ private LabelStatement checkLabeledLoop(Scope* sc, Statement statement) private Expression checkAssignmentAsCondition(Expression e) { auto ec = lastComma(e); - if (ec.op == TOK.assign) + if (ec.op == EXP.assign) { ec.error("assignment cannot be used as a condition, perhaps `==` was meant?"); return ErrorExp.get(); @@ -213,7 +213,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor s.exp = s.exp.optimize(WANTvalue); s.exp = checkGC(sc, s.exp); - if (s.exp.op == TOK.error) + if (s.exp.op == EXP.error) return setError(); result = s; } @@ -546,7 +546,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor ds._body = ds._body.semanticScope(sc, ds, ds, null); sc.inLoop = inLoopSave; - if (ds.condition.op == TOK.dotIdentifier) + if (ds.condition.op == EXP.dotIdentifier) (cast(DotIdExp)ds.condition).noderef = true; // check in syntax level @@ -561,7 +561,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor ds.condition = ds.condition.toBoolean(sc); - if (ds.condition.op == TOK.error) + if (ds.condition.op == EXP.error) return setError(); if (ds._body && ds._body.isErrorStatement()) { @@ -619,7 +619,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (fs.condition) { - if (fs.condition.op == TOK.dotIdentifier) + if (fs.condition.op == EXP.dotIdentifier) (cast(DotIdExp)fs.condition).noderef = true; // check in syntax level @@ -652,406 +652,13 @@ private extern (C++) final class StatementSemanticVisitor : Visitor sc.pop(); - if (fs.condition && fs.condition.op == TOK.error || - fs.increment && fs.increment.op == TOK.error || + if (fs.condition && fs.condition.op == EXP.error || + fs.increment && fs.increment.op == EXP.error || fs._body && fs._body.isErrorStatement()) return setError(); result = fs; } - - /******************* - * 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. - */ - auto makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, Dsymbols* dbody, bool needExpansion) - { - // Voldemort return type - union U - { - Statement statement; - Dsymbols* decl; - } - - U result; - - auto returnEarly() - { - if (isDecl) - result.decl = null; - else - result.statement = new ErrorStatement(); - return result; - } - - 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.foreach_ | 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); - v.storage_class |= STC.foreach_; - if (storageClass & STC.ref_) - v.storage_class |= STC.ref_; - 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); - result.statement = res; - } - else static if (!isDecl) - { - result.statement = new CompoundStatement(loc, statements); - } - else - { - result.decl = declarations; - } - return result; - } - override void visit(ForeachStatement fs) { /* https://dlang.org/spec/statement.html#foreach-statement @@ -1090,12 +697,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor fs.aggr = fs.aggr.expressionSemantic(sc); fs.aggr = resolveProperties(sc, fs.aggr); fs.aggr = fs.aggr.optimize(WANTvalue); - if (fs.aggr.op == TOK.error) + if (fs.aggr.op == EXP.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()) + !fs.aggr.isTypeExp() && !fs.aggr.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=14653 // Extend the life of rvalue aggregate till the end of foreach. @@ -1178,7 +785,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (tab.ty == Ttuple) // don't generate new scope for tuple loops { - Statement s = makeTupleForeach!(false,false)(fs, null, false).statement; + Statement s = makeTupleForeach(sc, false, false, fs, null, false).statement; if (vinit) s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s); result = s.statementSemantic(sc); @@ -1283,7 +890,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor { e = new DeclarationExp(loc, vinit); e = e.expressionSemantic(sc2); - if (e.op == TOK.error) + if (e.op == EXP.error) return null; } @@ -1421,7 +1028,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (var.storage_class & STC.ref_) { if (fs.aggr.checkModifiable(sc2, ModifyFlags.noError) == Modifiable.initialization) - var.storage_class |= STC.ctorinit; + var.setInCtorOnly = true; Type t = tab.nextOf(); if (t.constConv(p.type) == MATCH.nomatch) @@ -1446,7 +1053,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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) + if (fs.aggr.op == EXP.arrayLiteral && !valueIsRef) { auto ale = cast(ArrayLiteralExp)fs.aggr; size_t edim = ale.elements ? ale.elements.dim : 0; @@ -1456,7 +1063,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor // 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) + if (fs.aggr.op == EXP.error) return retError(); // for (T[edim] tmp = a, ...) @@ -1498,12 +1105,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (fs.op == TOK.foreach_reverse_) { // key-- - cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key)); + cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key)); } else { // key < tmp.length - cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), tmp_length); + cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), tmp_length); } Expression increment = null; @@ -1603,7 +1210,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor */ VarDeclaration r; Statement _init; - if (vinit && fs.aggr.op == TOK.variable && (cast(VarExp)fs.aggr).var == vinit) + if (vinit && fs.aggr.op == EXP.variable && (cast(VarExp)fs.aggr).var == vinit) { r = vinit; _init = new ExpStatement(loc, vinit); @@ -1788,7 +1395,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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) + if (ec.op == EXP.error) return null; if (ec.type != Type.tint32) { @@ -1805,7 +1412,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor /* Call: * aggr(flde) */ - if (fs.aggr.op == TOK.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && + if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && !(cast(DelegateExp)fs.aggr).func.needThis()) { // https://issues.dlang.org/show_bug.cgi?id=3560 @@ -1813,7 +1420,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor } ec = new CallExp(fs.loc, fs.aggr, flde); ec = ec.expressionSemantic(sc2); - if (ec.op == TOK.error) + if (ec.op == EXP.error) return null; if (ec.type != Type.tint32) { @@ -2063,7 +1670,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor Expression flde = new FuncExp(fs.loc, fld); flde = flde.expressionSemantic(sc); fld.tookAddressOf = 0; - if (flde.op == TOK.error) + if (flde.op == EXP.error) return null; return cast(FuncExp)flde; } @@ -2143,7 +1750,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor } 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) + if (fs.prm.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error) { return setError(); } @@ -2187,16 +1794,16 @@ private extern (C++) final class StatementSemanticVisitor : Visitor Expression cond; if (fs.op == TOK.foreach_reverse_) { - cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key)); + cond = new PostExp(EXP.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)); + cond = new CmpExp(EXP.greaterThan, loc, cond, new VarExp(loc, tmp)); } else { // key-- != tmp - cond = new EqualExp(TOK.notEqual, loc, cond, new VarExp(loc, tmp)); + cond = new EqualExp(EXP.notEqual, loc, cond, new VarExp(loc, tmp)); } } else @@ -2204,12 +1811,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (fs.prm.type.isscalar()) { // key < tmp - cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp)); + cond = new CmpExp(EXP.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)); + cond = new EqualExp(EXP.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp)); } } @@ -2218,7 +1825,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor { // 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)); + increment = new PreExp(EXP.prePlusPlus, loc, new VarExp(loc, fs.key)); } if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type)) { @@ -2300,7 +1907,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor } else { - if (ifs.condition.op == TOK.dotIdentifier) + if (ifs.condition.op == EXP.dotIdentifier) (cast(DotIdExp)ifs.condition).noderef = true; ifs.condition = ifs.condition.expressionSemantic(scd); @@ -2337,7 +1944,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor ctorflow_then.freeFieldinit(); // free extra copy of the data - if (ifs.condition.op == TOK.error || + if (ifs.condition.op == EXP.error || (ifs.ifbody && ifs.ifbody.isErrorStatement()) || (ifs.elsebody && ifs.elsebody.isErrorStatement())) { @@ -2396,7 +2003,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor // pragma(msg) is allowed to contain types as well as expressions e = ctfeInterpretForPragmaMsg(e); - if (e.op == TOK.error) + if (e.op == EXP.error) { errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); return setError(); @@ -2506,9 +2113,10 @@ private extern (C++) final class StatementSemanticVisitor : Visitor return setError(); } - if (e.isBool(true)) + const opt = e.toBool(); + if (opt.hasValue(true)) inlining = PINLINE.always; - else if (e.isBool(false)) + else if (opt.hasValue(false)) inlining = PINLINE.never; FuncDeclaration fd = sc.func; @@ -2565,7 +2173,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor Type att = null; TypeEnum te = null; - while (ss.condition.op != TOK.error) + while (!ss.condition.isErrorExp()) { // preserve enum type for final switches if (ss.condition.type.ty == Tenum) @@ -2581,7 +2189,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor break; } ss.condition = integralPromotions(ss.condition, sc); - if (ss.condition.op != TOK.error && ss.condition.type.isintegral()) + if (!ss.condition.isErrorExp() && ss.condition.type.isintegral()) break; auto ad = isAggregate(ss.condition.type); @@ -2594,7 +2202,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor } } - if (ss.condition.op != TOK.error) + if (!ss.condition.isErrorExp()) { ss.error("`%s` must be of integral or string type, it is a `%s`", ss.condition.toChars(), ss.condition.type.toChars()); @@ -2606,7 +2214,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor ss.condition = ErrorExp.get(); ss.condition = ss.condition.optimize(WANTvalue); ss.condition = checkGC(sc, ss.condition); - if (ss.condition.op == TOK.error) + if (ss.condition.op == EXP.error) conditionError = true; bool needswitcherror = false; @@ -2869,12 +2477,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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_) + while (e.op == EXP.cast_) e = (cast(CastExp)e).e1; /* This is where variables are allowed as case expressions. */ - if (e.op == TOK.variable) + if (e.op == EXP.variable) { VarExp ve = cast(VarExp)e; VarDeclaration v = ve.var.isVarDeclaration(); @@ -2924,7 +2532,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (StringExp se = cs.exp.toStringExp()) cs.exp = se; - else if (cs.exp.op != TOK.int64 && cs.exp.op != TOK.error) + else if (!cs.exp.isIntegerExp() && !cs.exp.isErrorExp()) { cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars()); errors = true; @@ -2982,7 +2590,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor result = cs.statement; return; } - if (errors || cs.exp.op == TOK.error) + if (errors || cs.exp.op == EXP.error) return setError(); cs.lastVar = sc.lastVar; @@ -3020,7 +2628,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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.first.op == EXP.error || crs.last.op == EXP.error || errors) { if (crs.statement) crs.statement.statementSemantic(sc); @@ -3151,7 +2759,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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) + if (gcs.exp.op == EXP.error) return setError(); } @@ -3173,7 +2781,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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) + if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult) { // return vresult; if (sc.fes) @@ -3250,7 +2858,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor rs.exp.checkSharedAccess(sc, returnSharedRef); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (rs.exp.op == TOK.type) + if (rs.exp.op == EXP.type) rs.exp = resolveAliasThis(sc, rs.exp); rs.exp = resolveProperties(sc, rs.exp); @@ -3266,7 +2874,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor // Extract side-effect part rs.exp = Expression.extractLast(rs.exp, e0); - if (rs.exp.op == TOK.call) + if (rs.exp.op == EXP.call) rs.exp = valueNoDtor(rs.exp); if (e0) @@ -3322,7 +2930,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor else if (m1 && !m2) { } - else if (rs.exp.op != TOK.error) + else if (!rs.exp.isErrorExp()) { rs.error("expected return type of `%s`, not `%s`:", tret.toChars(), @@ -3508,7 +3116,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor } if (e0) { - if (e0.op == TOK.declaration || e0.op == TOK.comma) + if (e0.op == EXP.declaration || e0.op == EXP.comma) { rs.exp = Expression.combine(e0, rs.exp); } @@ -3702,7 +3310,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor 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.exp.op == EXP.error) { if (ss._body) ss._body = ss._body.statementSemantic(sc); @@ -3826,15 +3434,15 @@ private extern (C++) final class StatementSemanticVisitor : Visitor ws.exp = resolveProperties(sc, ws.exp); ws.exp = ws.exp.optimize(WANTvalue); ws.exp = checkGC(sc, ws.exp); - if (ws.exp.op == TOK.error) + if (ws.exp.op == EXP.error) return setError(); - if (ws.exp.op == TOK.scope_) + if (ws.exp.op == EXP.scope_) { sym = new WithScopeSymbol(ws); sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } - else if (ws.exp.op == TOK.type) + else if (ws.exp.op == EXP.type) { Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc); if (!s || !s.isScopeDsymbol()) @@ -4133,7 +3741,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor FuncDeclaration fd = sc.parent.isFuncDeclaration(); fd.hasReturnExp |= 2; - if (ts.exp.op == TOK.new_) + if (ts.exp.op == EXP.new_) { NewExp ne = cast(NewExp)ts.exp; ne.thrownew = true; @@ -4142,7 +3750,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor ts.exp = ts.exp.expressionSemantic(sc); ts.exp = resolveProperties(sc, ts.exp); ts.exp = checkGC(sc, ts.exp); - if (ts.exp.op == TOK.error) + if (ts.exp.op == EXP.error) return setError(); checkThrowEscape(sc, ts.exp, false); @@ -4499,7 +4107,7 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St { if (auto es = statement.isExpStatement()) { - if (es.exp && es.exp.op == TOK.declaration) + if (es.exp && es.exp.op == EXP.declaration) { auto de = cast(DeclarationExp)es.exp; auto v = de.declaration.isVarDeclaration(); @@ -4565,15 +4173,373 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St return statement; } - /******************* - * See StatementSemanticVisitor.makeTupleForeach. This is a simple - * wrapper that returns the generated statements/declarations. + * 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. */ -auto makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, Dsymbols* dbody, bool needExpansion) +public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachStatement fs, Dsymbols* dbody, bool needExpansion) { - scope v = new StatementSemanticVisitor(sc); - return v.makeTupleForeach!(isStatic, isDecl)(fs, dbody, needExpansion); + // Voldemort return type + union U + { + Statement statement; + Dsymbols* decl; + } + + U result; + + auto returnEarly() + { + if (isDecl) + result.decl = null; + else + result.statement = new ErrorStatement(); + return result; + } + + auto loc = fs.loc; + size_t dim = fs.parameters.dim; + const bool skipCheck = isStatic && needExpansion; + if (!skipCheck && (dim < 1 || dim > 2)) + { + fs.error("only one (value) or two (key,value) arguments for tuple `foreach`"); + return returnEarly(); + } + + Type paramtype = (*fs.parameters)[dim - 1].type; + if (paramtype) + { + paramtype = paramtype.typeSemantic(loc, sc); + if (paramtype.ty == Terror) + { + return returnEarly(); + } + } + + Type tab = fs.aggr.type.toBasetype(); + TypeTuple tuple = cast(TypeTuple)tab; + + Statements* statements; + Dsymbols* declarations; + if (isDecl) + declarations = new Dsymbols(); + else + statements = new Statements(); + + //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars()); + size_t n; + TupleExp te = null; + if (fs.aggr.op == EXP.tuple) // expression tuple + { + te = cast(TupleExp)fs.aggr; + n = te.exps.dim; + } + else if (fs.aggr.op == EXP.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]; + + Statements* stmts; + Dsymbols* decls; + if (isDecl) + decls = new Dsymbols(); + else + stmts = new Statements(); + + const bool skip = isStatic && needExpansion; + 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()); + return returnEarly(); + } + + 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()); + 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); + 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.foreach_ | STC.manifest; + if (isStatic) + var.storage_class |= STC.local; + + if (isDecl) + decls.push(var); + else + stmts.push(new ExpStatement(loc, 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()); + 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 == EXP.variable) + ds = (cast(VarExp)e).var; + else if (e.op == EXP.template_) + ds = (cast(TemplateExp)e).td; + else if (e.op == EXP.scope_) + ds = (cast(ScopeExp)e).sds; + else if (e.op == EXP.function_) + { + auto fe = cast(FuncExp)e; + ds = fe.td ? cast(Dsymbol)fe.td : fe.fd; + } + else if (e.op == EXP.overloadSet) + ds = (cast(OverExp)e).vars; + } + else if (storageClass & STC.alias_) + { + fs.error("`foreach` loop variable cannot be both `enum` and `alias`"); + return false; + } + + if (ds) + { + var = new AliasDeclaration(loc, ident, ds); + if (storageClass & STC.ref_) + { + 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 == EXP.type) + { + 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.initial, e); + auto v = new VarDeclaration(loc, type, ident, ie, storageClass); + v.storage_class |= STC.foreach_; + if (storageClass & STC.ref_) + v.storage_class |= STC.ref_; + if (isStatic || storageClass&STC.manifest || e.isConst() || + e.op == EXP.string_ || + e.op == EXP.structLiteral || + e.op == EXP.arrayLiteral) + { + if (v.storage_class & STC.ref_) + { + 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()); + } + } + 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()); + return false; + } + } + if (isStatic) + { + var.storage_class |= STC.local; + } + + if (isDecl) + decls.push(var); + else + stmts.push(new ExpStatement(loc, var)); + return true; + } + + 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); + } + } + } + + Statement s; + Dsymbol d; + if (isDecl) + decls.append(Dsymbol.arraySyntaxCopy(dbody)); + else + { + if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646 + stmts.push(fs._body.syntaxCopy()); + s = new CompoundStatement(loc, stmts); + } + + if (!isStatic) + { + s = new ScopeStatement(loc, s, fs.endloc); + } + else if (isDecl) + { + import dmd.attrib: ForwardingAttribDeclaration; + d = new ForwardingAttribDeclaration(decls); + } + else + { + s = new ForwardingStatement(loc, s); + } + + if (isDecl) + declarations.push(d); + else + statements.push(s); + } + + 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); + result.statement = res; + } + else if (isDecl) + result.decl = declarations; + else + result.statement = new CompoundStatement(loc, statements); + + return result; } /********************************* @@ -4611,16 +4577,16 @@ private Statements* flatten(Statement statement, Scope* sc) * expand template mixin in statement scope * to handle variable destructors. */ - if (!es.exp || es.exp.op != TOK.declaration) + if (!es.exp || !es.exp.isDeclarationExp()) return null; - Dsymbol d = (cast(DeclarationExp)es.exp).declaration; + Dsymbol d = es.exp.isDeclarationExp().declaration; auto tm = d.isTemplateMixin(); if (!tm) return null; Expression e = es.exp.expressionSemantic(sc); - if (e.op == TOK.error || tm.errors) + if (e.op == EXP.error || tm.errors) return errorStatements(); assert(tm.members); @@ -4697,7 +4663,7 @@ private Statements* flatten(Statement statement, Scope* sc) sfs.sfe.prepare(sc); if (sfs.sfe.ready()) { - Statement s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement; + Statement s = makeTupleForeach(sc, true, false, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement; auto result = s.flatten(sc); if (result) { diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d index d1578ec..6d74ad2 100644 --- a/gcc/d/dmd/staticcond.d +++ b/gcc/d/dmd/staticcond.d @@ -48,19 +48,19 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool bool impl(Expression e) { - if (e.op == TOK.not) + if (e.isNotExp()) { NotExp ne = cast(NotExp)e; return !impl(ne.e1); } - if (e.op == TOK.andAnd || e.op == TOK.orOr) + if (e.op == EXP.andAnd || e.op == EXP.orOr) { LogicalExp aae = cast(LogicalExp)e; bool result = impl(aae.e1); if (errors) return false; - if (e.op == TOK.andAnd) + if (e.op == EXP.andAnd) { if (!result) return false; @@ -74,7 +74,7 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool return !errors && result; } - if (e.op == TOK.question) + if (e.op == EXP.question) { CondExp ce = cast(CondExp)e; bool result = impl(ce.econd); @@ -99,7 +99,7 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool e = e.optimize(WANTvalue); if (nerrors != global.errors || - e.op == TOK.error || + e.isErrorExp() || e.type.toBasetype() == Type.terror) { errors = true; @@ -108,9 +108,10 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool e = e.ctfeInterpret(); - if (e.isBool(true)) + const opt = e.toBool(); + if (opt.hasValue(true)) return true; - else if (e.isBool(false)) + else if (opt.hasValue(false)) { if (negatives) negatives.push(before); @@ -171,27 +172,27 @@ private uint visualizeFull(Expression original, Expression instantiated, // returns true if satisfied bool impl(Expression orig, Expression e, bool inverted, bool orOperand, bool unreached) { - TOK op = orig.op; + EXP 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 == EXP.andAnd) + op = EXP.orOr; + else if (op == EXP.orOr) + op = EXP.andAnd; } - if (op == TOK.not) + if (op == EXP.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) + else if (op == EXP.andAnd) { BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; @@ -200,7 +201,7 @@ private uint visualizeFull(Expression original, Expression instantiated, const r2 = impl(bo.e2, be.e2, inverted, false, unreached || !r1); return r1 && r2; } - else if (op == TOK.orOr) + else if (op == EXP.orOr) { if (!orOperand) // do not indent A || B || C twice indent++; @@ -214,7 +215,7 @@ private uint visualizeFull(Expression original, Expression instantiated, indent--; return r1 || r2; } - else if (op == TOK.question) + else if (op == EXP.question) { CondExp co = cast(CondExp)orig; CondExp ce = cast(CondExp)e; @@ -308,24 +309,24 @@ private uint visualizeShort(Expression original, Expression instantiated, bool impl(Expression orig, Expression e, bool inverted) { - TOK op = orig.op; + EXP op = orig.op; if (inverted) { - if (op == TOK.andAnd) - op = TOK.orOr; - else if (op == TOK.orOr) - op = TOK.andAnd; + if (op == EXP.andAnd) + op = EXP.orOr; + else if (op == EXP.orOr) + op = EXP.andAnd; } - if (op == TOK.not) + if (op == EXP.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) + else if (op == EXP.andAnd) { BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; @@ -334,7 +335,7 @@ private uint visualizeShort(Expression original, Expression instantiated, r = r && impl(bo.e2, be.e2, inverted); return r; } - else if (op == TOK.orOr) + else if (op == EXP.orOr) { BinExp bo = cast(BinExp)orig; BinExp be = cast(BinExp)e; @@ -346,7 +347,7 @@ private uint visualizeShort(Expression original, Expression instantiated, stack.setDim(lbefore); // purge added positive items return r; } - else if (op == TOK.question) + else if (op == EXP.question) { CondExp co = cast(CondExp)orig; CondExp ce = cast(CondExp)e; diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index 16739ad..7a875a5 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -27,7 +27,7 @@ module dmd.target; import dmd.globals : Param; -enum CPU +enum CPU : ubyte { x87, mmx, @@ -66,6 +66,7 @@ extern (C++) struct Target import dmd.mtype : Type, TypeFunction, TypeTuple; import dmd.root.ctfloat : real_t; import dmd.statement : Statement; + import dmd.tokens : EXP; /// Bit decoding of the Target.OS enum OS : ubyte @@ -213,7 +214,7 @@ extern (C++) struct Target * Returns: * true if the operation is supported or type is not a vector */ - extern (C++) bool isVectorOpSupported(Type type, uint op, Type t2 = null); + extern (C++) bool isVectorOpSupported(Type type, EXP op, Type t2 = null); /** * Default system linkage for the target. diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index 6a75ccc..1363693 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -26,7 +26,7 @@ class Type; class TypeTuple; class TypeFunction; -enum class CPU +enum class CPU : unsigned char { x87, mmx, @@ -194,7 +194,7 @@ public: 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, unsigned op, Type *t2 = NULL); + bool isVectorOpSupported(Type *type, EXP op, Type *t2 = NULL); // ABI and backend. LINK systemLinkage(); TypeTuple *toArgTypes(Type *t); diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index 620492f..b462742 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -87,8 +87,8 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor 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_) + if (e.op == EXP.int64 || e.op == EXP.float64 || + e.op == EXP.complex80 || e.op == EXP.null_ || e.op == EXP.string_) tvp.specValue = e; } @@ -100,7 +100,7 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor sc = sc.endCTFE(); e = e.implicitCastTo(sc, tvp.valType); e = e.ctfeInterpret(); - if (e.op == TOK.int64) + if (e.op == EXP.int64) tvp.defaultValue = e; } } diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 1ea51a8..2609af5 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -318,6 +318,157 @@ enum TOK : ushort __attribute__, } +/// Expression nodes +enum EXP : ubyte +{ + reserved, + + // Other + negate, + cast_, + null_, + assert_, + true_, + false_, + array, + call, + address, + type, + throw_, + new_, + delete_, + star, + symbolOffset, + variable, + dotVariable, + dotIdentifier, + dotTemplateInstance, + dotType, + slice, + arrayLength, + version_, + dollar, + template_, + dotTemplateDeclaration, + declaration, + typeof_, + pragma_, + dSymbol, + typeid_, + uadd, + remove, + newAnonymousClass, + arrayLiteral, + assocArrayLiteral, + structLiteral, + classReference, + thrownException, + delegatePointer, + delegateFunctionPointer, + + // Operators + lessThan, + greaterThan, + lessOrEqual, + greaterOrEqual, + equal, + notEqual, + identity, + notIdentity, + index, + is_, + + leftShift, + 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, + + // Leaf operators + identifier, + string_, + this_, + super_, + halt, + tuple, + error, + + // Basic types + void_, + int64, + float64, + complex80, + char_, + import_, + delegate_, + function_, + mixin_, + in_, + default_, + break_, + continue_, + goto_, + scope_, + + traits, + overloadSet, + line, + file, + fileFullPath, + moduleString, // __MODULE__ + functionString, // __FUNCTION__ + prettyFunction, // __PRETTY_FUNCTION__ + shared_, + pow, + powAssign, + vector, + + voidExpression, + cantExpression, + showCtfeContext, + objcClassReference, + vectorArray, + arrow, // -> + compoundLiteral, // ( type-name ) { initializer-list } + _Generic, + interval, +} + enum FirstCKeyword = TOK.inline; // Assert that all token enum members have consecutive values and @@ -1009,12 +1160,17 @@ nothrow: return p; } - static const(char)* toChars(uint value) + static const(char)* toChars(TOK value) { return toString(value).ptr; } - extern (D) static string toString(uint value) pure nothrow @nogc @safe + static const(char)* toChars(ushort value) + { + return toString(cast(TOK)value).ptr; + } + + extern (D) static string toString(TOK value) pure nothrow @nogc @safe { return tochars[value]; } diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index d14d0aa..f3e4411 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -32,187 +32,453 @@ class Identifier; ? && || */ -typedef unsigned short TOK; -enum +enum class TOK : unsigned short { - TOKreserved, - - // Other - TOKlparen, TOKrparen, - TOKlbracket, TOKrbracket, - TOKlcurly, TOKrcurly, - TOKcolon, TOKneg, - TOKsemicolon, TOKdotdotdot, - TOKeof, TOKcast, - TOKnull, TOKassert, - TOKtrue, TOKfalse, - TOKarray, TOKcall, - TOKaddress, - TOKtype, TOKthrow, - TOKnew, TOKdelete, - TOKstar, TOKsymoff, - TOKvar, TOKdotvar, - TOKdotid, TOKdotti, - TOKdottype, TOKslice, - TOKarraylength, TOKversion, - TOKmodule, TOKdollar, - TOKtemplate, TOKdottd, - TOKdeclaration, TOKtypeof, - TOKpragma, TOKdsymbol, - TOKtypeid, TOKuadd, - TOKremove, - TOKnewanonclass, TOKcomment, - TOKarrayliteral, TOKassocarrayliteral, - TOKstructliteral, - TOKclassreference, - TOKthrownexception, - TOKdelegateptr, - TOKdelegatefuncptr, - -// 54 - // Operators - TOKlt, TOKgt, - TOKle, TOKge, - TOKequal, TOKnotequal, - TOKidentity, TOKnotidentity, - TOKindex, TOKis, - -// 64 - TOKshl, TOKshr, - TOKshlass, TOKshrass, - TOKushr, TOKushrass, - TOKcat, TOKcatass, TOKcatelemass, TOKcatdcharass, // ~ ~= - TOKadd, TOKmin, TOKaddass, TOKminass, - TOKmul, TOKdiv, TOKmod, - TOKmulass, TOKdivass, TOKmodass, - TOKand, TOKor, TOKxor, - TOKandass, TOKorass, TOKxorass, - TOKassign, TOKnot, TOKtilde, - TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, - TOKdot, TOKcomma, - TOKquestion, TOKandand, TOKoror, - TOKpreplusplus, TOKpreminusminus, - -// 105 - // Numeric literals - TOKint32v, TOKuns32v, - TOKint64v, TOKuns64v, - TOKint128v, TOKuns128v, - TOKfloat32v, TOKfloat64v, TOKfloat80v, - TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, - - // Char constants - TOKcharv, TOKwcharv, TOKdcharv, - - // Leaf operators - TOKidentifier, TOKstring, TOKxstring, - TOKthis, TOKsuper, - TOKhalt, TOKtuple, - TOKerror, - - // Basic types - TOKvoid, - TOKint8, TOKuns8, - TOKint16, TOKuns16, - TOKint32, TOKuns32, - TOKint64, TOKuns64, - TOKint128, TOKuns128, - TOKfloat32, TOKfloat64, TOKfloat80, - TOKimaginary32, TOKimaginary64, TOKimaginary80, - TOKcomplex32, TOKcomplex64, TOKcomplex80, - TOKchar, TOKwchar, TOKdchar, TOKbool, - -// 152 - // Aggregates - TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, - TOKalias, TOKoverride, TOKdelegate, TOKfunction, - TOKmixin, - - TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, - TOKstatic, TOKfinal, TOKconst, TOKabstract, - TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, - TOKauto, TOKpackage, TOKimmutable, - -// 182 - // Statements - TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, - TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, - TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, - TOKasm, TOKforeach, TOKforeach_reverse, - TOKscope, - TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, - -// 206 - // Contracts - TOKinvariant, - - // Testing - TOKunittest, - - // Added after 1.0 - TOKargTypes, - TOKref, - TOKmacro, - -// 211 - TOKparameters, - TOKtraits, - TOKoverloadset, - TOKpure, - TOKnothrow, - TOKgshared, - TOKline, - TOKfile, - TOKfilefullpath, - TOKmodulestring, - TOKfuncstring, - TOKprettyfunc, - TOKshared, - TOKat, - TOKpow, - TOKpowass, - TOKgoesto, - TOKvector, - TOKpound, - -// 230 - TOKinterval, - TOKvoidexp, - TOKcantexp, - TOKshowctfecontext, - - TOKobjc_class_reference, - TOKvectorarray, - - TOKarrow, - TOKcolonColon, - TOKwchar_tLiteral, - TOKcompoundLiteral, - - 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 + 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__, + + MAX, +}; + +enum class EXP : unsigned char +{ + reserved, + + // Other + negate, + cast_, + null_, + assert_, + true_, + false_, + array, + call, + address, + type, + throw_, + new_, + delete_, + star, + symbolOffset, + variable, + dotVariable, + dotIdentifier, + dotTemplateInstance, + dotType, + slice, + arrayLength, + version_, + dollar, + template_, + dotTemplateDeclaration, + declaration, + typeof_, + pragma_, + dSymbol, + typeid_, + uadd, + remove, + newAnonymousClass, + arrayLiteral, + assocArrayLiteral, + structLiteral, + classReference, + thrownException, + delegatePointer, + delegateFunctionPointer, + + // Operators + lessThan, + greaterThan, + lessOrEqual, + greaterOrEqual, + equal, + notEqual, + identity, + notIdentity, + index, + is_, + + leftShift, + 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, + + // Leaf operators + identifier, + string_, + this_, + super_, + halt, + tuple, + error, + + // Basic types + void_, + int64, + float64, + complex80, + char_, + import_, + delegate_, + function_, + mixin_, + in_, + default_, + break_, + continue_, + goto_, + scope_, + + traits, + overloadSet, + line, + file, + fileFullPath, + moduleString, // __MODULE__ + functionString, // __FUNCTION__ + prettyFunction, // __PRETTY_FUNCTION__ + shared_, + pow, + powAssign, + vector, + + voidExpression, + cantExpression, + showCtfeContext, + objcClassReference, + vectorArray, + arrow, // -> + compoundLiteral, // ( type-name ) { initializer-list } + _Generic_, + interval, + + MAX }; #define TOKwild TOKinout @@ -255,7 +521,7 @@ struct Token int isKeyword(); const char *toChars() const; - static const char *toChars(unsigned value); + static const char *toChars(TOK value); }; #if defined(__GNUC__) diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index cc1d2e3..7b9a8c8 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -80,9 +80,9 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) { if (auto e = isExpression(oarg)) { - if (e.op == TOK.dotVariable) + if (e.op == EXP.dotVariable) return (cast(DotVarExp)e).var; - if (e.op == TOK.dotTemplateDeclaration) + if (e.op == EXP.dotTemplateDeclaration) return (cast(DotTemplateExp)e).td; } return getDsymbol(oarg); @@ -569,7 +569,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (global.params.vcomplex) { - if (isTypeX(t => t.iscomplex() || t.isimaginary()).isBool(true)) + if (isTypeX(t => t.iscomplex() || t.isimaginary()).toBool().hasValue(true)) return True(); } return isDsymX(t => t.isDeprecated()); @@ -998,7 +998,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) 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); + includeTemplates = b.toBool().hasValue(true); } StringExp se = ex.toStringExp(); @@ -1055,7 +1055,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } else if (e.ident == Id.getMember) { - if (ex.op == TOK.dotIdentifier) + if (ex.op == EXP.dotIdentifier) // Prevent semantic() from replacing Symbol with its initializer (cast(DotIdExp)ex).wantsym = true; ex = ex.expressionSemantic(scx); @@ -1085,7 +1085,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration()) f = dve.var; - if (dve.e1.op == TOK.dotType || dve.e1.op == TOK.this_) + if (dve.e1.op == EXP.dotType || dve.e1.op == EXP.this_) ex = null; else ex = dve.e1; @@ -1105,7 +1105,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (td && td.funcroot) f = td.funcroot; ex = null; - if (dte.e1.op != TOK.dotType && dte.e1.op != TOK.this_) + if (dte.e1.op != EXP.dotType && dte.e1.op != EXP.this_) ex = dte.e1; } bool[string] funcTypeHash; @@ -1290,7 +1290,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) Expression x = isExpression(o); Type t = isType(o); if (x) - printf("e = %s %s\n", Token.toChars(x.op), x.toChars()); + printf("e = %s %s\n", EXPtoString(x.op).ptr, x.toChars()); if (t) printf("t = %d %s\n", t.ty, t.toChars()); } @@ -1792,7 +1792,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) err |= tf.isnothrow && canThrow(ex, sc2.func, false); } ex = checkGC(sc2, ex); - if (ex.op == TOK.error) + if (ex.op == EXP.error) err = true; } } @@ -1919,6 +1919,27 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { return pointerBitmap(e); } + if (e.ident == Id.initSymbol) + { + if (dim != 1) + return dimError(1); + + auto o = (*e.args)[0]; + Type t = isType(o); + AggregateDeclaration ad = t ? isAggregate(t) : null; + + // Interfaces don't have an init symbol and hence cause linker errors + if (!ad || ad.isInterfaceDeclaration()) + { + e.error("struct / class type expected as argument to __traits(initSymbol) instead of `%s`", o.toChars()); + return ErrorExp.get(); + } + + Declaration d = new SymbolDeclaration(ad.loc, ad); + d.type = Type.tvoid.arrayOf().constOf(); + d.storage_class |= STC.rvalue; + return new VarExp(e.loc, d); + } if (e.ident == Id.isZeroInit) { if (dim != 1) @@ -2105,7 +2126,7 @@ private bool isSame(RootObject o1, RootObject o2, Scope* sc) } else if (auto ea = isExpression(oarg)) { - if (ea.op == TOK.function_) + if (ea.op == EXP.function_) { if (auto fe = cast(FuncExp)ea) return fe.fd; diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index f75ae0e..417d2c1 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -153,7 +153,7 @@ private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expr eindex = semanticLength(sc, tup, eindex); eindex = eindex.ctfeInterpret(); - if (eindex.op == TOK.error) + if (eindex.op == EXP.error) { pt = Type.terror; return; @@ -386,7 +386,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb * 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, + * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable, * // because getDsymbol() need to work in AliasDeclaration::semantic(). */ if (!v.type || @@ -602,7 +602,7 @@ Expression typeToExpression(Type t) */ Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0) { - //printf("toExpressionHelper(e = %s %s)\n", Token.toChars(e.op), e.toChars()); + //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars()); foreach (id; t.idents[i .. t.idents.dim]) { //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars()); @@ -722,7 +722,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { mtype.dim = semanticLength(sc, tup, mtype.dim); mtype.dim = mtype.dim.ctfeInterpret(); - if (mtype.dim.op == TOK.error) + if (mtype.dim.op == EXP.error) return error(); uinteger_t d = mtype.dim.toUInteger(); @@ -758,7 +758,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) mtype.dim = mtype.dim.optimize(WANTvalue); mtype.dim = mtype.dim.ctfeInterpret(); - if (mtype.dim.op == TOK.error) + if (mtype.dim.op == EXP.error) return error(); errors = global.errors; @@ -768,7 +768,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t); mtype.dim = mtype.dim.optimize(WANTvalue); - if (mtype.dim.op == TOK.error) + if (mtype.dim.op == EXP.error) return error(); errors = global.errors; @@ -776,7 +776,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (errors != global.errors) return error(); - if (mtype.dim.op == TOK.error) + if (mtype.dim.op == EXP.error) return error(); Type overflowError() @@ -1273,7 +1273,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret); e = iz.initializerToExpression(); } - if (e.op == TOK.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 + if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { FuncExp fe = cast(FuncExp)e; // Replace function literal with a function symbol, @@ -1299,7 +1299,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) e = e.toLvalue(sc, e); fparam.defaultArg = e; - return (e.op != TOK.error); + return (e.op != EXP.error); } ubyte wildparams = 0; @@ -1707,7 +1707,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) .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 + else if (e.op == EXP.variable) // special case: variable is used as a type { Dsymbol varDecl = mtype.toDsymbol(sc); const(Loc) varDeclLoc = varDecl.getLoc(); @@ -1814,29 +1814,29 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { switch (e.op) { - case TOK.dotVariable: + case EXP.dotVariable: mtype.sym = (cast(DotVarExp)e).var; break; - case TOK.variable: + case EXP.variable: mtype.sym = (cast(VarExp)e).var; break; - case TOK.function_: + case EXP.function_: auto fe = cast(FuncExp)e; mtype.sym = fe.td ? fe.td : fe.fd; break; - case TOK.dotTemplateDeclaration: + case EXP.dotTemplateDeclaration: mtype.sym = (cast(DotTemplateExp)e).td; break; - case TOK.dSymbol: + case EXP.dSymbol: mtype.sym = (cast(DsymbolExp)e).s; break; - case TOK.template_: + case EXP.template_: mtype.sym = (cast(TemplateExp)e).td; break; - case TOK.scope_: + case EXP.scope_: mtype.sym = (cast(ScopeExp)e).sds; break; - case TOK.tuple: + case EXP.tuple: TupleExp te = e.toTupleExp(); Objects* elems = new Objects(te.exps.dim); foreach (i; 0 .. elems.dim) @@ -1844,13 +1844,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) auto src = (*te.exps)[i]; switch (src.op) { - case TOK.type: + case EXP.type: (*elems)[i] = (cast(TypeExp)src).type; break; - case TOK.dotType: + case EXP.dotType: (*elems)[i] = (cast(DotTypeExp)src).sym.isType(); break; - case TOK.overloadSet: + case EXP.overloadSet: (*elems)[i] = (cast(OverExp)src).type; break; default: @@ -1863,13 +1863,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems); mtype.sym = td; break; - case TOK.dotType: + case EXP.dotType: result = (cast(DotTypeExp)e).sym.isType(); break; - case TOK.type: + case EXP.type: result = (cast(TypeExp)e).type; break; - case TOK.overloadSet: + case EXP.overloadSet: result = (cast(OverExp)e).type; break; default: @@ -1979,7 +1979,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) 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) + if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error) return error(); uinteger_t i1 = mtype.lwr.toUInteger(); @@ -2861,7 +2861,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type { mt.dim = semanticLength(sc, tup, mt.dim); mt.dim = mt.dim.ctfeInterpret(); - if (mt.dim.op == TOK.error) + if (mt.dim.op == EXP.error) return returnError(); const d = mt.dim.toUInteger(); @@ -2879,7 +2879,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type if (o.dyncast() == DYNCAST.expression) { Expression e = cast(Expression)o; - if (e.op == TOK.dSymbol) + if (e.op == EXP.dSymbol) return returnSymbol((cast(DsymbolExp)e).s); else return returnExp(e); @@ -3124,7 +3124,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type exp2 = resolvePropertiesOnly(sc2, exp2); sc2.pop(); - if (exp2.op == TOK.error) + if (exp2.op == EXP.error) { if (!global.gag) mt.exp = exp2; @@ -3132,8 +3132,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type } mt.exp = exp2; - if (mt.exp.op == TOK.type || - mt.exp.op == TOK.scope_) + if (mt.exp.op == EXP.type || + mt.exp.op == EXP.scope_) { if (mt.exp.checkType()) goto Lerr; @@ -3145,8 +3145,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type * 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) + if (auto f = mt.exp.op == EXP.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration() + : mt.exp.op == EXP.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 @@ -3377,12 +3377,12 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } Expression ex = e.lastComma(); - if (ex.op == TOK.dotVariable) + if (ex.op == EXP.dotVariable) { DotVarExp dv = cast(DotVarExp)ex; v = dv.var.isVarDeclaration(); } - else if (ex.op == TOK.variable) + else if (ex.op == EXP.variable) { VarExp ve = cast(VarExp)ex; v = ve.var.isVarDeclaration(); @@ -3552,9 +3552,9 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } - if (ident == Id.ptr && e.op == TOK.call) + if (ident == Id.ptr && e.op == EXP.call) { - /* The trouble with TOK.call is the return ABI for float[4] is different from + /* The trouble with EXP.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); @@ -3618,7 +3618,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } else if (ident == Id.ptr) { - if (e.op == TOK.type) + if (e.op == EXP.type) { e.error("`%s` is not an expression", e.toChars()); return ErrorExp.get(); @@ -3644,19 +3644,19 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } - if (e.op == TOK.type && (ident == Id.length || ident == Id.ptr)) + if (e.op == EXP.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_) + if (e.op == EXP.string_) { StringExp se = cast(StringExp)e; return new IntegerExp(se.loc, se.len, Type.tsize_t); } - if (e.op == TOK.null_) + if (e.op == EXP.null_) { return new IntegerExp(e.loc, 0, Type.tsize_t); } @@ -3864,7 +3864,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) if (!gagError) { global.endGagging(errors); - if (exp && exp.op == TOK.error) + if (exp && exp.op == EXP.error) exp = null; } @@ -3886,7 +3886,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } - assert(e.op != TOK.dot); + assert(e.op != EXP.dot); // https://issues.dlang.org/show_bug.cgi?id=14010 if (ident == Id._mangleof) @@ -3909,7 +3909,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } Expression e0; - Expression ev = e.op == TOK.type ? null : e; + Expression ev = e.op == EXP.type ? null : e; if (ev) ev = extractSideEffect(sc, "__tup", e0, ev); @@ -4003,7 +4003,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) TemplateDeclaration td = s.isTemplateDeclaration(); if (td) { - if (e.op == TOK.type) + if (e.op == EXP.type) e = new TemplateExp(e.loc, td); else e = new DotTemplateExp(e.loc, e, td); @@ -4024,7 +4024,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) s = ti.inst.toAlias(); if (!s.isTemplateInstance()) goto L1; - if (e.op == TOK.type) + if (e.op == EXP.type) e = new ScopeExp(e.loc, ti); else e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); @@ -4040,7 +4040,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) if (o) { auto oe = new OverExp(e.loc, o); - if (e.op == TOK.type) + if (e.op == EXP.type) { return oe; } @@ -4054,7 +4054,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) return ErrorExp.get(); } - if (e.op == TOK.type) + if (e.op == EXP.type) { /* It's: * Struct.d @@ -4084,7 +4084,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) return ve; } - bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField(); + bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField(); if (d.isDataseg() || unreal && d.isField()) { // (e, d) @@ -4146,7 +4146,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); } - assert(e.op != TOK.dot); + assert(e.op != EXP.dot); // https://issues.dlang.org/show_bug.cgi?id=12543 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof) @@ -4167,7 +4167,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) mt.sym.size(e.loc); // do semantic of type Expression e0; - Expression ev = e.op == TOK.type ? null : e; + Expression ev = e.op == EXP.type ? null : e; if (ev) ev = extractSideEffect(sc, "__tup", e0, ev); @@ -4207,7 +4207,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) // See if it's a 'this' class or a base class if (mt.sym.ident == ident) { - if (e.op == TOK.type) + if (e.op == EXP.type) { return mt.Type.getProperty(sc, e.loc, ident, 0); } @@ -4217,7 +4217,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } if (auto cbase = mt.sym.searchBase(ident)) { - if (e.op == TOK.type) + if (e.op == EXP.type) { return mt.Type.getProperty(sc, e.loc, ident, 0); } @@ -4238,7 +4238,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } Type t = Type.typeinfoclass.type; - if (e.op == TOK.type || e.op == TOK.dotType) + if (e.op == EXP.type || e.op == EXP.dotType) { /* For type.classinfo, we know the classinfo * at compile time. @@ -4412,7 +4412,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) Expression toTemplateExp(TemplateDeclaration td) { - if (e.op == TOK.type) + if (e.op == EXP.type) e = new TemplateExp(e.loc, td); else e = new DotTemplateExp(e.loc, e, td); @@ -4439,7 +4439,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) s = ti.inst.toAlias(); if (!s.isTemplateInstance()) goto L1; - if (e.op == TOK.type) + if (e.op == EXP.type) e = new ScopeExp(e.loc, ti); else e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti)); @@ -4456,7 +4456,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) if (o) { auto oe = new OverExp(e.loc, o); - if (e.op == TOK.type) + if (e.op == EXP.type) { return oe; } @@ -4470,7 +4470,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) return ErrorExp.get(); } - if (e.op == TOK.type) + if (e.op == EXP.type) { /* It's: * Class.d @@ -4589,7 +4589,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) assert(0); } - bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField(); + bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField(); if (d.isDataseg() || unreal && d.isField()) { // (e, d) @@ -4750,7 +4750,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc) Parameter p = (*mt.arguments)[i]; assert(p.type); Expression e = p.type.defaultInitLiteral(loc); - if (e.op == TOK.error) + if (e.op == EXP.error) { return e; } @@ -4818,7 +4818,7 @@ private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identif static Expression pvalToResult(Expression e, const ref Loc loc) { - if (e.op != TOK.error) + if (e.op != EXP.error) { e = e.copy(); e.loc = loc; @@ -4902,12 +4902,12 @@ private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identif * maxval = e; */ Expression e = em.value; - Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval); + Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval); ed.inuse++; ec = ec.expressionSemantic(em._scope); ed.inuse--; ec = ec.ctfeInterpret(); - if (ec.op == TOK.error) + if (ec.op == EXP.error) { ed.errors = true; continue; diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 8e1d43e..f1c014d 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -88,7 +88,7 @@ lvalue_p (Expression *e) if (ce != NULL && ce->e1->isLvalue ()) return true; - return (e->op != TOKslice && e->isLvalue ()); + return (e->op != EXP::slice && e->isLvalue ()); } /* Build an expression of code CODE, data type TYPE, and operands ARG0 and @@ -162,7 +162,7 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2) { /* Skip casts for lhs assignment. */ Expression *e1b = e1; - while (e1b->op == TOKcast) + while (e1b->op == EXP::cast_) { CastExp *ce = e1b->isCastExp (); gcc_assert (same_type_p (ce->type, ce->to)); @@ -264,7 +264,7 @@ public: void visit (IdentityExp *e) { - tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR; + tree_code code = (e->op == EXP::identity) ? EQ_EXPR : NE_EXPR; Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); @@ -331,7 +331,7 @@ public: { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); - tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR; + tree_code code = (e->op == EXP::equal) ? EQ_EXPR : NE_EXPR; if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray) && (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray)) @@ -391,7 +391,7 @@ public: Otherwise for inequality: (e1.length != 0 && memcmp); */ tree tsizecmp = build_boolop (code, t1len, size_zero_node); - if (e->op == TOKequal) + if (e->op == EXP::equal) result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result); else result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result); @@ -404,7 +404,7 @@ public: else { tree tlencmp = build_boolop (code, t1len, t2len); - if (e->op == TOKequal) + if (e->op == EXP::equal) result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result); else result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result); @@ -428,7 +428,7 @@ public: d_array_convert (e->e2), build_typeinfo (e->loc, t1array)); - if (e->op == TOKnotequal) + if (e->op == EXP::notEqual) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); this->result_ = result; @@ -453,7 +453,7 @@ public: build_expr (e->e1), build_expr (e->e2)); - if (e->op == TOKnotequal) + if (e->op == EXP::notEqual) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); this->result_ = result; @@ -499,19 +499,19 @@ public: switch (e->op) { - case TOKle: + case EXP::lessOrEqual: code = LE_EXPR; break; - case TOKlt: + case EXP::lessThan: code = LT_EXPR; break; - case TOKge: + case EXP::greaterOrEqual: code = GE_EXPR; break; - case TOKgt: + case EXP::greaterThan: code = GT_EXPR; break; @@ -540,7 +540,7 @@ public: void visit (LogicalExp *e) { - tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; + tree_code code = (e->op == EXP::andAnd) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; if (e->e2->type->toBasetype ()->ty != TY::Tvoid) { @@ -559,7 +559,7 @@ public: tree t2 = build_expr_dtor (e->e2); /* Invert condition for logical or if expression. */ - if (e->op == TOKoror) + if (e->op == EXP::orOr) t1 = build1 (TRUTH_NOT_EXPR, d_bool_type, t1); this->result_ = build_condition (build_ctype (e->type), @@ -576,8 +576,8 @@ public: switch (e->op) { - case TOKadd: - case TOKmin: + case EXP::add: + case EXP::min: if ((e->e1->type->isreal () && e->e2->type->isimaginary ()) || (e->e1->type->isimaginary () && e->e2->type->isreal ())) { @@ -586,7 +586,7 @@ public: tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); - if (e->op == TOKmin) + if (e->op == EXP::min) t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2); if (e->e1->type->isreal ()) @@ -597,22 +597,22 @@ public: return; } else - code = (e->op == TOKadd) + code = (e->op == EXP::add) ? PLUS_EXPR : MINUS_EXPR; break; - case TOKmul: + case EXP::mul: code = MULT_EXPR; break; - case TOKdiv: + case EXP::div: /* Determine if the div expression is a lowered pointer diff operation. The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'. */ if (MinExp *me = e->e1->isMinExp ()) { if (me->e1->type->ty == TY::Tpointer && me->e2->type->ty == TY::Tpointer - && e->e2->op == TOKint64) + && e->e2->op == EXP::int64) { code = EXACT_DIV_EXPR; break; @@ -623,32 +623,32 @@ public: ? TRUNC_DIV_EXPR : RDIV_EXPR; break; - case TOKmod: + case EXP::mod: code = e->e1->type->isfloating () ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR; break; - case TOKand: + case EXP::and_: code = BIT_AND_EXPR; break; - case TOKor: + case EXP::or_: code = BIT_IOR_EXPR; break; - case TOKxor: + case EXP::xor_: code = BIT_XOR_EXPR; break; - case TOKshl: + case EXP::leftShift: code = LSHIFT_EXPR; break; - case TOKshr: + case EXP::rightShift: code = RSHIFT_EXPR; break; - case TOKushr: + case EXP::unsignedRightShift: code = UNSIGNED_RSHIFT_EXPR; break; @@ -678,15 +678,15 @@ public: tree result; - if (e->e1->op == TOKcat) + if (e->e1->op == EXP::concatenate) { /* Flatten multiple concatenations to an array. So the expression ((a ~ b) ~ c) becomes [a, b, c] */ int ndims = 2; - for (Expression *ex = e->e1; ex->op == TOKcat;) + for (Expression *ex = e->e1; ex->op == EXP::concatenate;) { - if (ex->op == TOKcat) + if (ex->op == EXP::concatenate) { ex = ex->isCatExp ()->e1; ndims++; @@ -703,7 +703,7 @@ public: int dim = ndims - 1; for (Expression *oe = ce->e2; oe != NULL; - (ce->e1->op != TOKcat + (ce->e1->op != EXP::concatenate ? (oe = ce->e1) : (ce = ce->e1->isCatExp (), oe = ce->e2))) { @@ -751,59 +751,59 @@ public: switch (e->op) { - case TOKaddass: + case EXP::addAssign: code = PLUS_EXPR; break; - case TOKminass: + case EXP::minAssign: code = MINUS_EXPR; break; - case TOKmulass: + case EXP::mulAssign: code = MULT_EXPR; break; - case TOKdivass: + case EXP::divAssign: code = e->e1->type->isintegral () ? TRUNC_DIV_EXPR : RDIV_EXPR; break; - case TOKmodass: + case EXP::modAssign: code = e->e1->type->isfloating () ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR; break; - case TOKandass: + case EXP::andAssign: code = BIT_AND_EXPR; break; - case TOKorass: + case EXP::orAssign: code = BIT_IOR_EXPR; break; - case TOKxorass: + case EXP::xorAssign: code = BIT_XOR_EXPR; break; - case TOKpowass: + case EXP::powAssign: gcc_unreachable (); - case TOKshlass: + case EXP::leftShiftAssign: code = LSHIFT_EXPR; break; - case TOKshrass: - case TOKushrass: + case EXP::rightShiftAssign: + case EXP::unsignedRightShiftAssign: /* Use the original lhs type before it was promoted. The left operand of `>>>=' does not undergo integral promotions before shifting. Strip off casts just incase anyway. */ - while (e1b->op == TOKcast) + while (e1b->op == EXP::cast_) { CastExp *ce = e1b->isCastExp (); gcc_assert (same_type_p (ce->type, ce->to)); e1b = ce->e1; } - code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR; + code = (e->op == EXP::rightShiftAssign) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR; break; default: @@ -908,7 +908,7 @@ public: /* First, handle special assignment semantics. */ /* Look for array.length = n; */ - if (e->e1->op == TOKarraylength) + if (e->e1->op == EXP::arrayLength) { /* This case should have been rewritten to `_d_arraysetlengthT` in the semantic phase. */ @@ -916,7 +916,7 @@ public: } /* Look for array[] = n; */ - if (e->e1->op == TOKslice) + if (e->e1->op == EXP::slice) { SliceExp *se = e->e1->isSliceExp (); Type *stype = se->e1->type->toBasetype (); @@ -937,15 +937,18 @@ public: tree init = stabilize_expr (&t1); t1 = d_save_expr (t1); - if ((postblit || destructor) && e->op != TOKblit) + if ((postblit || destructor) && e->op != EXP::blit) { - libcall_fn libcall = (e->op == TOKconstruct) - ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN; + /* Need to call postblit/destructor as part of assignment. + Construction has already been handled by the front-end. */ + gcc_assert (e->op != EXP::construct); + /* So we can call postblits on const/immutable objects. */ Type *tm = etype->unSharedOf ()->mutableOf (); tree ti = build_typeinfo (e->loc, tm); - result = build_libcall (libcall, Type::tvoid, 4, + /* Generate: _d_arraysetassign (t1.ptr, &t2, t1.length, ti); */ + result = build_libcall (LIBCALL_ARRAYSETASSIGN, Type::tvoid, 4, d_array_ptr (t1), build_address (t2), d_array_length (t1), ti); @@ -1011,14 +1014,11 @@ public: this->result_ = compound_expr (result, t1); } - else if ((postblit || destructor) && e->op != TOKblit) + else if ((postblit || destructor) + && e->op != EXP::blit && e->op != EXP::construct) { - /* Generate: _d_arrayassign(ti, from, to) - or: _d_arrayctor(ti, from, to) */ - libcall_fn libcall = (e->op == TOKconstruct) - ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN; - - this->result_ = build_libcall (libcall, e->type, 3, + /* Generate: _d_arrayassign(ti, from, to); */ + this->result_ = build_libcall (LIBCALL_ARRAYASSIGN, e->type, 3, build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1)); @@ -1039,8 +1039,8 @@ public: /* Look for reference initializations. */ if (e->memset == MemorySet::referenceInit) { - gcc_assert (e->op == TOKconstruct || e->op == TOKblit); - gcc_assert (e->e1->op == TOKvar); + gcc_assert (e->op == EXP::construct || e->op == EXP::blit); + gcc_assert (e->e1->op == EXP::variable); Declaration *decl = e->e1->isVarExp ()->var; if (decl->storage_class & (STCout | STCref)) @@ -1060,7 +1060,7 @@ public: /* Other types of assignments that may require post construction. */ Type *tb1 = e->e1->type->toBasetype (); - tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR; + tree_code modifycode = (e->op == EXP::construct) ? INIT_EXPR : MODIFY_EXPR; /* Look for struct assignment. */ if (tb1->ty == TY::Tstruct) @@ -1071,10 +1071,10 @@ public: StructDeclaration *sd = tb1->isTypeStruct ()->sym; /* Look for struct = 0. */ - if (e->e2->op == TOKint64) + if (e->e2->op == EXP::int64) { /* Use memset to fill struct. */ - gcc_assert (e->op == TOKblit); + gcc_assert (e->op == EXP::blit); tree result = build_memset_call (t1); /* Maybe set-up hidden pointer to outer scope context. */ @@ -1095,8 +1095,8 @@ public: tree init = NULL_TREE; /* Fill any alignment holes in the struct using memset. */ - if ((e->op == TOKconstruct - || (e->e2->op == TOKstructliteral && e->op == TOKblit)) + if ((e->op == EXP::construct + || (e->e2->op == EXP::structLiteral && e->op == EXP::blit)) && (sd->isUnionDeclaration () || !identity_compare_p (sd))) { t1 = stabilize_reference (t1); @@ -1120,10 +1120,10 @@ public: if (tb1->ty == TY::Tsarray) { /* Look for array = 0. */ - if (e->e2->op == TOKint64) + if (e->e2->op == EXP::int64) { /* Use memset to fill the array. */ - gcc_assert (e->op == TOKblit); + gcc_assert (e->op == EXP::blit); this->result_ = build_memset_call (build_expr (e->e1)); return; } @@ -1132,17 +1132,17 @@ public: gcc_assert (e->e2->type->toBasetype ()->ty == TY::Tsarray); /* Determine if we need to run postblit. */ - bool postblit = needs_postblit (etype); - bool destructor = needs_dtor (etype); - bool lvalue = lvalue_p (e->e2); + const bool postblit = needs_postblit (etype); + const bool destructor = needs_dtor (etype); + const bool lvalue = lvalue_p (e->e2); /* Optimize static array assignment with array literal. Even if the elements in rhs are all rvalues and don't have to call postblits, this assignment should call dtors on old assigned elements. */ if ((!postblit && !destructor) - || (e->op == TOKconstruct && e->e2->op == TOKarrayliteral) - || (e->op == TOKconstruct && !lvalue && postblit) - || (e->op == TOKblit || e->e1->type->size () == 0)) + || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral) + || (e->op == EXP::construct && !lvalue && postblit) + || (e->op == EXP::blit || e->e1->type->size () == 0)) { tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (build_expr (e->e2), @@ -1152,32 +1152,22 @@ public: return; } + /* All other kinds of lvalue or rvalue static array assignment. + Array construction has already been handled by the front-end. */ + gcc_assert (e->op != EXP::construct); + + /* Generate: _d_arrayassign_l() + or: _d_arrayassign_r() */ + libcall_fn libcall = (lvalue) + ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; + tree elembuf = build_local_temp (build_ctype (etype)); Type *arrtype = (e->type->ty == TY::Tsarray) ? etype->arrayOf () : e->type; - tree result; - - if (e->op == TOKconstruct) - { - /* Generate: _d_arrayctor(ti, from, to) */ - result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3, - build_typeinfo (e->loc, etype), - d_array_convert (e->e2), - d_array_convert (e->e1)); - } - else - { - /* Generate: _d_arrayassign_l() - or: _d_arrayassign_r() */ - libcall_fn libcall = (lvalue) - ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; - tree elembuf = build_local_temp (build_ctype (etype)); - - result = build_libcall (libcall, arrtype, 4, - build_typeinfo (e->loc, etype), - d_array_convert (e->e2), - d_array_convert (e->e1), - build_address (elembuf)); - } + tree result = build_libcall (libcall, arrtype, 4, + build_typeinfo (e->loc, etype), + d_array_convert (e->e2), + d_array_convert (e->e1), + build_address (elembuf)); /* Cast the libcall result back to a static array. */ if (e->type->ty == TY::Tsarray) @@ -1202,12 +1192,12 @@ public: { tree result; - if (e->op == TOKplusplus) + if (e->op == EXP::plusPlus) { result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); } - else if (e->op == TOKminusminus) + else if (e->op == EXP::minusMinus) { result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type), build_expr (e->e1), build_expr (e->e2)); @@ -1441,7 +1431,7 @@ public: the destructor is called for the object instance. */ libcall_fn libcall; - if (e->e1->op == TOKvar) + if (e->e1->op == EXP::variable) { VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration (); if (v && v->onstack) @@ -1586,10 +1576,10 @@ public: size_t offset; tree result; - if (e->e1->op == TOKadd) + if (e->e1->op == EXP::add) { AddExp *ae = e->e1->isAddExp (); - if (ae->e1->op == TOKaddress + if (ae->e1->op == EXP::address && ae->e2->isConst () && ae->e2->type->isintegral ()) { Expression *ex = ae->e1->isAddrExp ()->e1; @@ -1598,7 +1588,7 @@ public: offset = ae->e2->toUInteger (); } } - else if (e->e1->op == TOKsymoff) + else if (e->e1->op == EXP::symbolOffset) { SymOffExp *se = e->e1->isSymOffExp (); if (!declaration_reference_p (se->var)) @@ -1650,7 +1640,7 @@ public: /* The frontend optimizer can convert const symbol into a struct literal. Taking the address of a struct literal is otherwise illegal. */ - if (e->e1->op == TOKstructliteral) + if (e->e1->op == EXP::structLiteral) { StructLiteralExp *sle = e->e1->isStructLiteralExp ()->origin; gcc_assert (sle != NULL); @@ -1689,21 +1679,21 @@ public: TypeFunction *tf = NULL; /* Calls to delegates can sometimes look like this. */ - if (e1b->op == TOKcomma) + if (e1b->op == EXP::comma) { e1b = e1b->isCommaExp ()->e2; - gcc_assert (e1b->op == TOKvar); + gcc_assert (e1b->op == EXP::variable); Declaration *var = e1b->isVarExp ()->var; gcc_assert (var->isFuncDeclaration () && !var->needThis ()); } - if (e1b->op == TOKdotvar && tb->ty != TY::Tdelegate) + if (e1b->op == EXP::dotVariable && tb->ty != TY::Tdelegate) { DotVarExp *dve = e1b->isDotVarExp (); /* Don't modify the static initializer for struct literals. */ - if (dve->e1->op == TOKstructliteral) + if (dve->e1->op == EXP::structLiteral) { StructLiteralExp *sle = dve->e1->isStructLiteralExp (); sle->useStaticInit = false; @@ -1775,7 +1765,7 @@ public: { /* This could be a delegate expression (TY == Tdelegate), but not actually a delegate variable. */ - if (e1b->op == TOKdotvar) + if (e1b->op == EXP::dotVariable) { /* This gets the true function type, getting the function type from e1->type can sometimes be incorrect, such as when calling @@ -1795,7 +1785,7 @@ public: object = delegate_object (callee); callee = delegate_method (callee); } - else if (e1b->op == TOKvar) + else if (e1b->op == EXP::variable) { FuncDeclaration *fd = e1b->isVarExp ()->var->isFuncDeclaration (); gcc_assert (fd != NULL); @@ -1877,7 +1867,7 @@ public: if (e->func->isNested () && !e->func->isThis ()) { - if (e->e1->op == TOKnull) + if (e->e1->op == EXP::null_) object = build_expr (e->e1); else object = get_frame_for_symbol (e->func); @@ -1908,7 +1898,7 @@ public: /* Get pointer to function out of the virtual table. */ if (e->func->isVirtual () && !e->func->isFinalFunc () - && e->e1->op != TOKsuper && e->e1->op != TOKdottype) + && e->e1->op != EXP::super_ && e->e1->op != EXP::dotType) { tree fntype = build_pointer_type (TREE_TYPE (fndecl)); object = d_save_expr (object); @@ -2105,9 +2095,9 @@ 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 == TY::Tpointer) + if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer) { - e->fd->tok = TOKfunction; + e->fd->tok = TOK::function_; e->fd->vthis = NULL; } @@ -2196,9 +2186,9 @@ public: FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration (); if (fld != NULL) { - if (fld->tok == TOKreserved) + if (fld->tok == TOK::reserved) { - fld->tok = TOKfunction; + fld->tok = TOK::function_; fld->vthis = NULL; } @@ -2210,7 +2200,7 @@ public: { /* Want the initializer, not the expression. */ VarDeclaration *var = e->var->isVarDeclaration (); - SymbolDeclaration *sd = e->var->isSymbolDeclaration (); + SymbolDeclaration *sdecl = e->var->isSymbolDeclaration (); tree init = NULL_TREE; if (var && (var->isConst () || var->isImmutable ()) @@ -2226,8 +2216,15 @@ public: var->inuse--; } } - else if (sd && sd->dsym) - init = layout_struct_initializer (sd->dsym); + else if (sdecl && sdecl->dsym) + { + if (StructDeclaration *sd = sdecl->dsym->isStructDeclaration ()) + init = layout_struct_initializer (sd); + else if (ClassDeclaration *cd = sdecl->dsym->isClassDeclaration ()) + init = layout_class_initializer (cd); + else + gcc_unreachable (); + } else error_at (make_location_t (e->loc), "non-constant expression %qs", e->toChars ()); @@ -2242,6 +2239,26 @@ public: tree result = get_decl_tree (e->var); TREE_USED (result) = 1; + /* The variable expression generated for `__traits(initSymbol)'. */ + if (SymbolDeclaration *sd = e->var->isSymbolDeclaration ()) + { + if (e->type->isTypeDArray ()) + { + /* Generate a slice for non-zero initialized aggregates, + otherwise create an empty array. */ + gcc_assert (e->type == Type::tvoid->arrayOf ()->constOf ()); + + tree type = build_ctype (e->type); + tree length = size_int (sd->dsym->structsize); + tree ptr = (sd->dsym->isStructDeclaration () + && sd->dsym->type->isZeroInit (e->loc)) + ? null_pointer_node : build_address (result); + + this->result_ = d_array_value (type, length, ptr); + return; + } + } + /* For variables that are references - currently only out/inout arguments; objects don't count - evaluating the variable means we want what it refers to. */ @@ -2954,7 +2971,7 @@ public: tree type = build_ctype (e->type); /* First handle array literal expressions. */ - if (e->e1->op == TOKarrayliteral) + if (e->e1->op == EXP::arrayLiteral) { ArrayLiteralExp *ale = e->e1->isArrayLiteralExp (); vec <constructor_elt, va_gc> *elms = NULL; diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc index b14b0ca..dec2bd4 100644 --- a/gcc/d/intrinsics.cc +++ b/gcc/d/intrinsics.cc @@ -431,7 +431,7 @@ expand_intrinsic_rotate (intrinsic_code intrinsic, tree callexp) gcc_assert (ti && ti->tiargs && ti->tiargs->length == 2); Expression *e = isExpression ((*ti->tiargs)[0]); - gcc_assert (e && e->op == TOKint64); + gcc_assert (e && e->op == EXP::int64); count = build_expr (e, true); } diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index d0a5e2f..893bc23 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -380,10 +380,6 @@ 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. @@ -412,6 +408,10 @@ frevert=dtorfields D RejectNegative Don't destruct fields of partially constructed objects. +frevert=intpromote +D RejectNegative +Use C-style integral promotion for unary '+', '-' and '~'. + frevert=markdown D RejectNegative Disable Markdown replacements in Ddoc. diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index fdff6db..3961a1d 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -140,13 +140,6 @@ DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID), DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR), P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) -/* Used for constructing a new array from an existing array. The `set' variant - is for when the constructor value is a single element. */ -DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID), - P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) -DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR), - P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) - /* Used for concatenating two or more arrays together. Then `n' variant is for when there is more than two arrays to handle. */ DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE), diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index 55d63f8..17b63ba 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -969,8 +969,7 @@ public: StructLiteralExp *sle = NULL; bool using_rvo_p = false; - if (DotVarExp *dve = (s->exp->op == TOKcall - && s->exp->isCallExp ()->e1->op == TOKdotvar + if (DotVarExp *dve = (s->exp->isCallExp () ? s->exp->isCallExp ()->e1->isDotVarExp () : NULL)) { diff --git a/gcc/d/types.cc b/gcc/d/types.cc index b39b92e..1d551e5 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -338,7 +338,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) RootObject *ro = (*td->objects)[j]; gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION); Expression *e = (Expression *) ro; - gcc_assert (e->op == TOKdsymbol); + gcc_assert (e->op == EXP::dSymbol); DsymbolExp *se = e->isDsymbolExp (); tmembers.push (se->s); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 035a2c8..d4c35e5 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2519,7 +2519,6 @@ The following attributes are supported on most targets. @table @code @c Keep this table alphabetized by attribute name. Treat _ as space. -@item access @itemx access (@var{access-mode}, @var{ref-index}) @itemx access (@var{access-mode}, @var{ref-index}, @var{size-index}) @@ -2593,7 +2592,9 @@ __attribute__ ((access (write_only, 1, 2), access (read_write, 3))) int fgets (c The access mode @code{none} specifies that the pointer to which it applies is not used to access the referenced object at all. Unless the pointer is null the pointed-to object must exist and have at least the size as denoted -by the @var{size-index} argument. The object need not be initialized. +by the @var{size-index} argument. When the optional @var{size-index} +argument is omitted for an argument of @code{void*} type the actual pointer +agument is ignored. The referenced object need not be initialized. The mode is intended to be used as a means to help validate the expected object size, for example in functions that call @code{__builtin_object_size}. @xref{Object Size Checking}. diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi index ca2c840..5a84d9a 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -483,7 +483,7 @@ void gt_pch_nx (my_struct *p) void gt_pch_nx (my_struct *p, gt_pointer_operator op, void *cookie) @{ /* For every field 'fld', call the given pointer operator. */ - op (&(tp->fld), cookie); + op (&(tp->fld), NULL, cookie); @} @end smallexample @@ -536,7 +536,7 @@ void gt_pch_nx (TP<T *> *tp, gt_pointer_operator op, void *cookie) @{ /* For every field 'fld' of 'tp' with type 'T *', call the given pointer operator. */ - op (&(tp->fld), cookie); + op (&(tp->fld), NULL, cookie); @} template<typename T> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0b68449..ef8e4ce 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -13568,6 +13568,14 @@ The maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop. Larger values can exponentially increase compilation time. +@item max-inline-functions-called-once-loop-depth +Maximal loop depth of a call considered by inline heuristics that tries to +inline all functions called once. + +@item max-inline-functions-called-once-insns +Maximal estimated size of functions produced while inlining functions called +once. + @item max-inline-insns-single Several parameters control the tree inliner used in GCC@. This number sets the maximum number of instructions (counted in GCC's internal representation) in a diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index c16ff2c..1e70b9d 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,18 @@ +2021-12-11 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103606 + * resolve.c (resolve_fl_procedure): Do not access CLASS components + before class container has been built. + +2021-12-10 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103418 + * check.c (variable_check): Replace previous check of procedure + dummy arguments with INTENT(IN) attribute when passed to intrinsic + procedures by gfc_check_vardef_context. + * expr.c (gfc_check_vardef_context): Correct check of INTENT(IN) + dummy arguments for the case of sub-components of a CLASS pointer. + 2021-12-08 Harald Anlauf <anlauf@gmx.de> PR fortran/103609 diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index ee3a51e..3934336 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -1011,33 +1011,13 @@ variable_check (gfc_expr *e, int n, bool allow_proc) if (e->expr_type == EXPR_VARIABLE && e->symtree->n.sym->attr.intent == INTENT_IN && (gfc_current_intrinsic_arg[n]->intent == INTENT_OUT - || gfc_current_intrinsic_arg[n]->intent == INTENT_INOUT)) + || gfc_current_intrinsic_arg[n]->intent == INTENT_INOUT) + && !gfc_check_vardef_context (e, false, true, false, NULL)) { - gfc_ref *ref; - bool pointer = e->symtree->n.sym->ts.type == BT_CLASS - && CLASS_DATA (e->symtree->n.sym) - ? CLASS_DATA (e->symtree->n.sym)->attr.class_pointer - : e->symtree->n.sym->attr.pointer; - - for (ref = e->ref; ref; ref = ref->next) - { - if (pointer && ref->type == REF_COMPONENT) - break; - if (ref->type == REF_COMPONENT - && ((ref->u.c.component->ts.type == BT_CLASS - && CLASS_DATA (ref->u.c.component)->attr.class_pointer) - || (ref->u.c.component->ts.type != BT_CLASS - && ref->u.c.component->attr.pointer))) - break; - } - - if (!ref) - { - gfc_error ("%qs argument of %qs intrinsic at %L cannot be " - "INTENT(IN)", gfc_current_intrinsic_arg[n]->name, - gfc_current_intrinsic, &e->where); - return false; - } + gfc_error ("%qs argument of %qs intrinsic at %L cannot be INTENT(IN)", + gfc_current_intrinsic_arg[n]->name, + gfc_current_intrinsic, &e->where); + return false; } if (e->expr_type == EXPR_VARIABLE diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index 8708932..b874607 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -6254,10 +6254,13 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj, { if (ptr_component && ref->type == REF_COMPONENT) check_intentin = false; - if (ref->type == REF_COMPONENT && ref->u.c.component->attr.pointer) + if (ref->type == REF_COMPONENT) { - ptr_component = true; - if (!pointer) + gfc_component *comp = ref->u.c.component; + ptr_component = (comp->ts.type == BT_CLASS && comp->attr.class_ok) + ? CLASS_DATA (comp)->attr.class_pointer + : comp->attr.pointer; + if (ptr_component && !pointer) check_intentin = false; } if (ref->type == REF_INQUIRY diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 0ed3197..bff1b35 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -13294,7 +13294,8 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag) /* An elemental function is required to return a scalar 12.7.1 */ if (sym->attr.elemental && sym->attr.function - && (sym->as || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->as))) + && (sym->as || (sym->ts.type == BT_CLASS && sym->attr.class_ok + && CLASS_DATA (sym)->as))) { gfc_error ("ELEMENTAL function %qs at %L must have a scalar " "result", sym->name, &sym->declared_at); diff --git a/gcc/gengtype.c b/gcc/gengtype.c index b9daaa4..db218a7 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -2491,6 +2491,7 @@ struct walk_type_data int loopcounter; bool in_ptr_field; bool have_this_obj; + bool in_nested_ptr; }; @@ -2807,6 +2808,7 @@ walk_type (type_p t, struct walk_type_data *d) if (nested_ptr_d) { const char *oldprevval2 = d->prev_val[2]; + bool old_in_nested_ptr = d->in_nested_ptr; if (!union_or_struct_p (nested_ptr_d->type)) { @@ -2817,6 +2819,7 @@ walk_type (type_p t, struct walk_type_data *d) } d->prev_val[2] = d->val; + d->in_nested_ptr = true; oprintf (d->of, "%*s{\n", d->indent, ""); d->indent += 2; d->val = xasprintf ("x%d", d->counter++); @@ -2846,6 +2849,7 @@ walk_type (type_p t, struct walk_type_data *d) oprintf (d->of, "%*s}\n", d->indent, ""); d->val = d->prev_val[2]; d->prev_val[2] = oldprevval2; + d->in_nested_ptr = old_in_nested_ptr; } else d->process_field (t->u.p, d); @@ -3828,12 +3832,17 @@ write_types_local_user_process_field (type_p f, const struct walk_type_data *d) case TYPE_UNION: case TYPE_LANG_STRUCT: case TYPE_STRING: - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + if (d->in_nested_ptr) + oprintf (d->of, "%*s op (&(%s), &(%s), cookie);\n", + d->indent, "", d->val, d->prev_val[2]); + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); break; case TYPE_USER_STRUCT: if (d->in_ptr_field) - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); else oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", d->indent, "", d->val); @@ -3911,14 +3920,20 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d) case TYPE_STRING: oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", d->prev_val[3]); - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + if (d->in_nested_ptr) + oprintf (d->of, "%*s op (&(%s), &(%s), cookie);\n", + d->indent, "", d->val, d->prev_val[2]); + else + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); break; case TYPE_USER_STRUCT: oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", d->prev_val[3]); if (d->in_ptr_field) - oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + oprintf (d->of, "%*s op (&(%s), NULL, cookie);\n", + d->indent, "", d->val); else oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", d->indent, "", d->val); diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 7c998e9..4fe9ff1 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -40,7 +40,7 @@ static ggc_statistics *ggc_stats; struct traversal_state; static int compare_ptr_data (const void *, const void *); -static void relocate_ptrs (void *, void *); +static void relocate_ptrs (void *, void *, void *); static void write_pch_globals (const struct ggc_root_tab * const *tab, struct traversal_state *state); @@ -247,6 +247,7 @@ saving_hasher::equal (const ptr_data *p1, const void *p2) static hash_table<saving_hasher> *saving_htab; static vec<void *> callback_vec; +static vec<void *> reloc_addrs_vec; /* Register an object in the hash table. */ @@ -363,10 +364,10 @@ compare_ptr_data (const void *p1_p, const void *p2_p) /* Callbacks for note_ptr_fn. */ static void -relocate_ptrs (void *ptr_p, void *state_p) +relocate_ptrs (void *ptr_p, void *real_ptr_p, void *state_p) { void **ptr = (void **)ptr_p; - struct traversal_state *state ATTRIBUTE_UNUSED + struct traversal_state *state = (struct traversal_state *)state_p; struct ptr_data *result; @@ -377,6 +378,19 @@ relocate_ptrs (void *ptr_p, void *state_p) saving_htab->find_with_hash (*ptr, POINTER_HASH (*ptr)); gcc_assert (result); *ptr = result->new_addr; + if (ptr_p == real_ptr_p) + return; + if (real_ptr_p == NULL) + real_ptr_p = ptr_p; + gcc_assert (real_ptr_p >= state->ptrs[state->ptrs_i]->obj + && ((char *) real_ptr_p + sizeof (void *) + <= ((char *) state->ptrs[state->ptrs_i]->obj + + state->ptrs[state->ptrs_i]->size))); + void *addr + = (void *) ((char *) state->ptrs[state->ptrs_i]->new_addr + + ((char *) real_ptr_p + - (char *) state->ptrs[state->ptrs_i]->obj)); + reloc_addrs_vec.safe_push (addr); } /* Write out, after relocation, the pointers in TAB. */ @@ -411,6 +425,61 @@ write_pch_globals (const struct ggc_root_tab * const *tab, } } +/* Callback for qsort. */ + +static int +compare_ptr (const void *p1_p, const void *p2_p) +{ + void *p1 = *(void *const *)p1_p; + void *p2 = *(void *const *)p2_p; + return (((uintptr_t)p1 > (uintptr_t)p2) + - ((uintptr_t)p1 < (uintptr_t)p2)); +} + +/* Decode one uleb128 from P, return first byte after it, store + decoded value into *VAL. */ + +static unsigned char * +read_uleb128 (unsigned char *p, size_t *val) +{ + unsigned int shift = 0; + unsigned char byte; + size_t result; + + result = 0; + do + { + byte = *p++; + result |= ((size_t) byte & 0x7f) << shift; + shift += 7; + } + while (byte & 0x80); + + *val = result; + return p; +} + +/* Store VAL as uleb128 at P, return length in bytes. */ + +static size_t +write_uleb128 (unsigned char *p, size_t val) +{ + size_t len = 0; + do + { + unsigned char byte = (val & 0x7f); + val >>= 7; + if (val != 0) + /* More bytes to follow. */ + byte |= 0x80; + + *p++ = byte; + ++len; + } + while (val != 0); + return len; +} + /* Hold the information we need to mmap the file back in. */ struct mmap_info @@ -511,6 +580,7 @@ gt_pch_save (FILE *f) /* Actually write out the objects. */ for (i = 0; i < state.count; i++) { + state.ptrs_i = i; if (this_object_size < state.ptrs[i]->size) { this_object_size = state.ptrs[i]->size; @@ -591,7 +661,42 @@ gt_pch_save (FILE *f) vbits.release (); #endif + reloc_addrs_vec.qsort (compare_ptr); + + size_t reloc_addrs_size = 0; + void *last_addr = NULL; + unsigned char uleb128_buf[sizeof (size_t) * 2]; + for (void *addr : reloc_addrs_vec) + { + gcc_assert ((uintptr_t) addr >= (uintptr_t) mmi.preferred_base + && ((uintptr_t) addr + sizeof (void *) + < (uintptr_t) mmi.preferred_base + mmi.size)); + if (addr == last_addr) + continue; + if (last_addr == NULL) + last_addr = mmi.preferred_base; + size_t diff = (uintptr_t) addr - (uintptr_t) last_addr; + reloc_addrs_size += write_uleb128 (uleb128_buf, diff); + last_addr = addr; + } + if (fwrite (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1) + fatal_error (input_location, "cannot write PCH file: %m"); + last_addr = NULL; + for (void *addr : reloc_addrs_vec) + { + if (addr == last_addr) + continue; + if (last_addr == NULL) + last_addr = mmi.preferred_base; + size_t diff = (uintptr_t) addr - (uintptr_t) last_addr; + reloc_addrs_size = write_uleb128 (uleb128_buf, diff); + if (fwrite (uleb128_buf, 1, reloc_addrs_size, f) != reloc_addrs_size) + fatal_error (input_location, "cannot write PCH file: %m"); + last_addr = addr; + } + ggc_pch_finish (state.d, state.f); + gt_pch_fixup_stringpool (); unsigned num_callbacks = callback_vec.length (); @@ -608,6 +713,7 @@ gt_pch_save (FILE *f) delete saving_htab; saving_htab = NULL; callback_vec.release (); + reloc_addrs_vec.release (); } /* Read the state of the compiler back in from F. */ @@ -660,6 +766,7 @@ gt_pch_restore (FILE *f) if (fread (&mmi, sizeof (mmi), 1, f) != 1) fatal_error (input_location, "cannot read PCH file: %m"); + void *orig_preferred_base = mmi.preferred_base; result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size, fileno (f), mmi.offset); @@ -667,7 +774,7 @@ gt_pch_restore (FILE *f) address needed. */ if (result < 0) { - sorry_at (input_location, "PCH relocation is not yet supported"); + sorry_at (input_location, "PCH allocation failure"); /* There is no point in continuing from here, we will only end up with a crashed (most likely hanging) compiler. */ exit (-1); @@ -685,9 +792,75 @@ gt_pch_restore (FILE *f) else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) fatal_error (input_location, "cannot read PCH file: %m"); - ggc_pch_read (f, mmi.preferred_base); + size_t reloc_addrs_size; + if (fread (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1) + fatal_error (input_location, "cannot read PCH file: %m"); - gt_pch_restore_stringpool (); + if (orig_preferred_base != mmi.preferred_base) + { + uintptr_t bias + = (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base; + + /* Adjust all the global pointers by bias. */ + line_table = new_line_table; + for (rt = gt_ggc_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) + { + char *addr = (char *)rti->base + rti->stride * i; + char *p; + memcpy (&p, addr, sizeof (void *)); + if ((uintptr_t) p >= (uintptr_t) orig_preferred_base + && (uintptr_t) p < (uintptr_t) orig_preferred_base + mmi.size) + { + p = (char *) ((uintptr_t) p + bias); + memcpy (addr, &p, sizeof (void *)); + } + } + new_line_table = line_table; + line_table = save_line_table; + + /* And adjust all the pointers in the image by bias too. */ + char *addr = (char *) mmi.preferred_base; + unsigned char uleb128_buf[4096], *uleb128_ptr = uleb128_buf; + while (reloc_addrs_size != 0) + { + size_t this_size + = MIN (reloc_addrs_size, + (size_t) (4096 - (uleb128_ptr - uleb128_buf))); + if (fread (uleb128_ptr, 1, this_size, f) != this_size) + fatal_error (input_location, "cannot read PCH file: %m"); + unsigned char *uleb128_end = uleb128_ptr + this_size; + if (this_size != reloc_addrs_size) + uleb128_end -= 2 * sizeof (size_t); + uleb128_ptr = uleb128_buf; + while (uleb128_ptr < uleb128_end) + { + size_t diff; + uleb128_ptr = read_uleb128 (uleb128_ptr, &diff); + addr = (char *) ((uintptr_t) addr + diff); + + char *p; + memcpy (&p, addr, sizeof (void *)); + gcc_assert ((uintptr_t) p >= (uintptr_t) orig_preferred_base + && ((uintptr_t) p + < (uintptr_t) orig_preferred_base + mmi.size)); + p = (char *) ((uintptr_t) p + bias); + memcpy (addr, &p, sizeof (void *)); + } + reloc_addrs_size -= this_size; + if (reloc_addrs_size == 0) + break; + this_size = uleb128_end + 2 * sizeof (size_t) - uleb128_ptr; + memcpy (uleb128_buf, uleb128_ptr, this_size); + uleb128_ptr = uleb128_buf + this_size; + } + } + else if (fseek (f, (mmi.offset + mmi.size + sizeof (reloc_addrs_size) + + reloc_addrs_size), SEEK_SET) != 0) + fatal_error (input_location, "cannot read PCH file: %m"); + + ggc_pch_read (f, mmi.preferred_base); void (*pch_save) (FILE *); unsigned num_callbacks; @@ -696,23 +869,28 @@ gt_pch_restore (FILE *f) fatal_error (input_location, "cannot read PCH file: %m"); if (pch_save != >_pch_save) { - uintptr_t bias = (uintptr_t) >_pch_save - (uintptr_t) pch_save; + uintptr_t binbias = (uintptr_t) >_pch_save - (uintptr_t) pch_save; void **ptrs = XNEWVEC (void *, num_callbacks); unsigned i; + uintptr_t bias + = (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base; if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks) fatal_error (input_location, "cannot read PCH file: %m"); for (i = 0; i < num_callbacks; ++i) { - memcpy (&pch_save, ptrs[i], sizeof (pch_save)); - pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias); - memcpy (ptrs[i], &pch_save, sizeof (pch_save)); + void *ptr = (void *) ((uintptr_t) ptrs[i] + bias); + memcpy (&pch_save, ptr, sizeof (pch_save)); + pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + binbias); + memcpy (ptr, &pch_save, sizeof (pch_save)); } XDELETE (ptrs); } else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0) fatal_error (input_location, "cannot read PCH file: %m"); + gt_pch_restore_stringpool (); + /* Barring corruption of the PCH file, the restored line table should be complete and usable. */ line_table = new_line_table; @@ -736,7 +914,7 @@ default_gt_pch_get_address (size_t size ATTRIBUTE_UNUSED, of the PCH file would be required. */ int -default_gt_pch_use_address (void *base, size_t size, int fd ATTRIBUTE_UNUSED, +default_gt_pch_use_address (void *&base, size_t size, int fd ATTRIBUTE_UNUSED, size_t offset ATTRIBUTE_UNUSED) { void *addr = xmalloc (size); @@ -782,7 +960,7 @@ mmap_gt_pch_get_address (size_t size, int fd) mapped with something. */ int -mmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset) +mmap_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset) { void *addr; diff --git a/gcc/ggc-tests.c b/gcc/ggc-tests.c index e83f701..cd8621a 100644 --- a/gcc/ggc-tests.c +++ b/gcc/ggc-tests.c @@ -415,7 +415,7 @@ gt_pch_nx (user_struct *p) static void gt_pch_nx (user_struct *p, gt_pointer_operator op, void *cookie) { - op (&(p->m_ptr), cookie); + op (&(p->m_ptr), NULL, cookie); } /* Verify that GTY((user)) works. */ diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 48bf8aa..1d095a6 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -1337,10 +1337,10 @@ check_access (GimpleOrTree exp, tree dstwrite, if (!dstsize) dstsize = maxobjsize; - /* Set RANGE to that of DSTWRITE if non-null, bounded by PAD->DST.BNDRNG + /* Set RANGE to that of DSTWRITE if non-null, bounded by PAD->DST_BNDRNG if valid. */ gimple *stmt = pad ? pad->stmt : nullptr; - get_size_range (rvals, dstwrite, stmt, range, pad ? pad->dst.bndrng : NULL); + get_size_range (rvals, dstwrite, stmt, range, pad ? pad->dst_bndrng : NULL); tree func = get_callee_fndecl (exp); /* Read vs write access by built-ins can be determined from the const @@ -1432,9 +1432,9 @@ check_access (GimpleOrTree exp, tree dstwrite, of an object. */ if (maxread) { - /* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if + /* Set RANGE to that of MAXREAD, bounded by PAD->SRC_BNDRNG if PAD is nonnull and BNDRNG is valid. */ - get_size_range (rvals, maxread, stmt, range, pad ? pad->src.bndrng : NULL); + get_size_range (rvals, maxread, stmt, range, pad ? pad->src_bndrng : NULL); location_t loc = get_location (exp); tree size = dstsize; @@ -1479,12 +1479,12 @@ check_access (GimpleOrTree exp, tree dstwrite, && (pad->src.offrng[1] < 0 || pad->src.offrng[0] <= pad->src.offrng[1])) { - /* Set RANGE to that of MAXREAD, bounded by PAD->SRC.BNDRNG if + /* Set RANGE to that of MAXREAD, bounded by PAD->SRC_BNDRNG if PAD is nonnull and BNDRNG is valid. */ - get_size_range (rvals, maxread, stmt, range, pad ? pad->src.bndrng : NULL); + get_size_range (rvals, maxread, stmt, range, pad ? pad->src_bndrng : NULL); /* Set OVERREAD for reads starting just past the end of an object. */ - overread = pad->src.sizrng[1] - pad->src.offrng[0] < pad->src.bndrng[0]; - range[0] = wide_int_to_tree (sizetype, pad->src.bndrng[0]); + overread = pad->src.sizrng[1] - pad->src.offrng[0] < pad->src_bndrng[0]; + range[0] = wide_int_to_tree (sizetype, pad->src_bndrng[0]); slen = size_zero_node; } @@ -2592,7 +2592,7 @@ pass_waccess::check_strncmp (gcall *stmt) /* Determine the range of the bound first and bail if it fails; it's cheaper than computing the size of the objects. */ tree bndrng[2] = { NULL_TREE, NULL_TREE }; - get_size_range (m_ptr_qry.rvals, bound, stmt, bndrng, adata1.src.bndrng); + get_size_range (m_ptr_qry.rvals, bound, stmt, bndrng, adata1.src_bndrng); if (!bndrng[0] || integer_zerop (bndrng[0])) return; @@ -2998,6 +2998,10 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, tree fndecl, tree fntype, if (access.second.minsize && access.second.minsize != HOST_WIDE_INT_M1U) access_nelts = build_int_cstu (sizetype, access.second.minsize); + else if (VOID_TYPE_P (argtype) && access.second.mode == access_none) + /* Treat access mode none on a void* argument as expecting + as little as zero bytes. */ + access_nelts = size_zero_node; else access_nelts = size_one_node; } diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index d1df9ca..ca2d4c2 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -777,7 +777,7 @@ builtin_access::builtin_access (range_query *query, gimple *call, if (!POINTER_TYPE_P (TREE_TYPE (addr))) addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr); - if (tree dstsize = compute_objsize (addr, ostype)) + if (tree dstsize = compute_objsize (addr, call, ostype)) dst.basesize = wi::to_offset (dstsize); else if (POINTER_TYPE_P (TREE_TYPE (addr))) dst.basesize = HOST_WIDE_INT_MIN; @@ -791,7 +791,7 @@ builtin_access::builtin_access (range_query *query, gimple *call, if (!POINTER_TYPE_P (TREE_TYPE (addr))) addr = build1 (ADDR_EXPR, (TREE_TYPE (addr)), addr); - if (tree srcsize = compute_objsize (addr, ostype)) + if (tree srcsize = compute_objsize (addr, call, ostype)) src.basesize = wi::to_offset (srcsize); else if (POINTER_TYPE_P (TREE_TYPE (addr))) src.basesize = HOST_WIDE_INT_MIN; diff --git a/gcc/hash-map.h b/gcc/hash-map.h index c4fe26c..e495b62 100644 --- a/gcc/hash-map.h +++ b/gcc/hash-map.h @@ -111,7 +111,7 @@ class GTY((user)) hash_map static void pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie) { - op (&x, cookie); + op (&x, NULL, cookie); } /* The overloads below should match those in ggc.h. */ @@ -336,7 +336,7 @@ template<typename K, typename V, typename H> static inline void gt_pch_nx (hash_map<K, V, H> *h, gt_pointer_operator op, void *cookie) { - op (&h->m_table.m_entries, cookie); + op (&h->m_table.m_entries, NULL, cookie); } enum hm_alloc { hm_heap = false, hm_ggc = true }; diff --git a/gcc/hash-set.h b/gcc/hash-set.h index 85c31ef..60b3fcb 100644 --- a/gcc/hash-set.h +++ b/gcc/hash-set.h @@ -206,7 +206,7 @@ template<typename K, typename H> static inline void gt_pch_nx (hash_set<K, false, H> *h, gt_pointer_operator op, void *cookie) { - op (&h->m_table.m_entries, cookie); + op (&h->m_table.m_entries, NULL, cookie); } #endif diff --git a/gcc/hash-table.h b/gcc/hash-table.h index ff415c7..00b31d8 100644 --- a/gcc/hash-table.h +++ b/gcc/hash-table.h @@ -1206,7 +1206,7 @@ template<typename D> static inline void gt_pch_nx (hash_table<D> *h, gt_pointer_operator op, void *cookie) { - op (&h->m_entries, cookie); + op (&h->m_entries, NULL, cookie); } template<typename H> diff --git a/gcc/hash-traits.h b/gcc/hash-traits.h index 57c81bf..6f0373e 100644 --- a/gcc/hash-traits.h +++ b/gcc/hash-traits.h @@ -254,7 +254,7 @@ struct ggc_remove static void pch_nx (T &p, gt_pointer_operator op, void *cookie) { - op (&p, cookie); + op (&p, NULL, cookie); } }; diff --git a/gcc/hosthooks-def.h b/gcc/hosthooks-def.h index a87b6d3..8f50932 100644 --- a/gcc/hosthooks-def.h +++ b/gcc/hosthooks-def.h @@ -35,10 +35,10 @@ along with GCC; see the file COPYING3. If not see default_gt_pch_alloc_granularity extern void* default_gt_pch_get_address (size_t, int); -extern int default_gt_pch_use_address (void *, size_t, int, size_t); +extern int default_gt_pch_use_address (void *&, size_t, int, size_t); extern size_t default_gt_pch_alloc_granularity (void); extern void* mmap_gt_pch_get_address (size_t, int); -extern int mmap_gt_pch_use_address (void *, size_t, int, size_t); +extern int mmap_gt_pch_use_address (void *&, size_t, int, size_t); /* The structure is defined in hosthooks.h. */ #define HOST_HOOKS_INITIALIZER { \ diff --git a/gcc/hosthooks.h b/gcc/hosthooks.h index 42ed3dc..8241a53 100644 --- a/gcc/hosthooks.h +++ b/gcc/hosthooks.h @@ -30,10 +30,12 @@ struct host_hooks void * (*gt_pch_get_address) (size_t size, int fd); /* ADDR is an address returned by gt_pch_get_address. Attempt to allocate - SIZE bytes at the same address and load it with the data from FD at - OFFSET. Return -1 if we couldn't allocate memory at ADDR, return 0 - if the memory is allocated but the data not loaded, return 1 if done. */ - int (*gt_pch_use_address) (void *addr, size_t size, int fd, size_t offset); + SIZE bytes at the same address (preferrably) or some other address + and load it with the data from FD at OFFSET. Return -1 if we couldn't + allocate memory, otherwise update ADDR to the actual address where it got + allocated, return 0 if the memory is allocated but the data not loaded, + return 1 if done. */ + int (*gt_pch_use_address) (void *&addr, size_t size, int fd, size_t offset); /* Return the alignment required for allocating virtual memory. Usually this is the same as pagesize. */ diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 012b326..54cd085 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -1091,20 +1091,30 @@ static bool check_callers (struct cgraph_node *node, void *has_hot_call) { struct cgraph_edge *e; - for (e = node->callers; e; e = e->next_caller) - { - if (!opt_for_fn (e->caller->decl, flag_inline_functions_called_once) - || !opt_for_fn (e->caller->decl, optimize)) - return true; - if (!can_inline_edge_p (e, true)) - return true; - if (e->recursive_p ()) - return true; - if (!can_inline_edge_by_limits_p (e, true)) - return true; - if (!(*(bool *)has_hot_call) && e->maybe_hot_p ()) - *(bool *)has_hot_call = true; - } + for (e = node->callers; e; e = e->next_caller) + { + if (!opt_for_fn (e->caller->decl, flag_inline_functions_called_once) + || !opt_for_fn (e->caller->decl, optimize)) + return true; + if (!can_inline_edge_p (e, true)) + return true; + if (e->recursive_p ()) + return true; + if (!can_inline_edge_by_limits_p (e, true)) + return true; + /* Inlining large functions to large loop depth is often harmful because + of register pressure it implies. */ + if ((int)ipa_call_summaries->get (e)->loop_depth + > param_inline_functions_called_once_loop_depth) + return true; + /* Do not produce gigantic functions. */ + if (estimate_size_after_inlining (e->caller->inlined_to ? + e->caller->inlined_to : e->caller, e) + > param_inline_functions_called_once_insns) + return true; + if (!(*(bool *)has_hot_call) && e->maybe_hot_p ()) + *(bool *)has_hot_call = true; + } return false; } @@ -1327,9 +1337,12 @@ edge_badness (struct cgraph_edge *edge, bool dump) " %i (compensated)\n", badness.to_double (), freq.to_double (), - edge->count.ipa ().initialized_p () ? edge->count.ipa ().to_gcov_type () : -1, - caller->count.ipa ().initialized_p () ? caller->count.ipa ().to_gcov_type () : -1, - inlining_speedup (edge, freq, unspec_edge_time, edge_time).to_double (), + edge->count.ipa ().initialized_p () + ? edge->count.ipa ().to_gcov_type () : -1, + caller->count.ipa ().initialized_p () + ? caller->count.ipa ().to_gcov_type () : -1, + inlining_speedup (edge, freq, unspec_edge_time, + edge_time).to_double (), estimate_growth (callee), callee_info->growth, overall_growth); } diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h index 35190c2..4ad556f 100644 --- a/gcc/ipa-modref-tree.h +++ b/gcc/ipa-modref-tree.h @@ -87,7 +87,8 @@ struct GTY(()) modref_access_node { return parm_offset_known && parm_index != MODREF_UNKNOWN_PARM && parm_index != MODREF_RETSLOT_PARM && known_size_p (size) - && known_eq (max_size, size); + && known_eq (max_size, size) + && known_gt (size, 0); } /* Dump range to debug OUT. */ void dump (FILE *out); diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 9e537b0..2c89c63 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -754,7 +754,7 @@ get_modref_function_summary (cgraph_node *func) we don't want to return anything, even if we have summary for the target function. */ enum availability avail; - func = func->function_or_virtual_thunk_symbol + func = func->ultimate_alias_target (&avail, current_function_decl ? cgraph_node::get (current_function_decl) : NULL); if (avail <= AVAIL_INTERPOSABLE) @@ -1750,6 +1750,19 @@ modref_access_analysis::analyze () for (si = gsi_start_nondebug_after_labels_bb (bb); !gsi_end_p (si); gsi_next_nondebug (&si)) { + /* NULL memory accesses terminates BB. These accesses are known + to trip undefined behaviour. gimple-ssa-isolate-paths turns them + to volatile accesses and adds builtin_trap call which would + confuse us otherwise. */ + if (infer_nonnull_range_by_dereference (gsi_stmt (si), + null_pointer_node)) + { + if (dump_file) + fprintf (dump_file, " - NULL memory access; terminating BB\n"); + if (flag_non_call_exceptions) + set_side_effects (); + break; + } analyze_stmt (gsi_stmt (si), always_executed); /* Avoid doing useles work. */ @@ -4065,7 +4078,7 @@ ignore_edge (struct cgraph_edge *e) if (!e->inline_failed) return false; enum availability avail; - cgraph_node *callee = e->callee->function_or_virtual_thunk_symbol + cgraph_node *callee = e->callee->ultimate_alias_target (&avail, e->caller); return (avail <= AVAIL_INTERPOSABLE @@ -4088,7 +4101,7 @@ compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map) class ipa_call_summary *es = ipa_call_summaries->get (callee_edge); cgraph_node *callee - = callee_edge->callee->function_or_virtual_thunk_symbol + = callee_edge->callee->ultimate_alias_target (NULL, callee_edge->caller); caller_parms_info @@ -4578,7 +4591,7 @@ modref_propagate_in_scc (cgraph_node *component_node) /* Get the callee and its summary. */ enum availability avail; - callee = callee_edge->callee->function_or_virtual_thunk_symbol + callee = callee_edge->callee->ultimate_alias_target (&avail, cur); /* It is not necessary to re-process calls outside of the @@ -5021,7 +5034,7 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) /* Get the callee and its summary. */ enum availability avail; - callee = callee_edge->callee->function_or_virtual_thunk_symbol + callee = callee_edge->callee->ultimate_alias_target (&avail, cur); /* It is not necessary to re-process calls outside of the diff --git a/gcc/ipa-profile.c b/gcc/ipa-profile.c index ce32b538..02f42d9 100644 --- a/gcc/ipa-profile.c +++ b/gcc/ipa-profile.c @@ -854,18 +854,6 @@ ipa_profile (void) node_map_initialized = true; ncommon++; - if (in_lto_p) - { - if (dump_file) - { - fprintf (dump_file, - "Updating hotness threshold in LTO mode.\n"); - fprintf (dump_file, "Updated min count: %" PRId64 "\n", - (int64_t) threshold / spec_count); - } - set_hot_bb_threshold (threshold / spec_count); - } - unsigned speculative_id = 0; profile_count orig = e->count; for (unsigned i = 0; i < spec_count; i++) diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index fea8b08..25503f3 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -1097,6 +1097,28 @@ analyze_function (struct cgraph_node *fn, bool ipa) !gsi_end_p (gsi); gsi_next (&gsi)) { + /* NULL memory accesses terminates BB. These accesses are known + to trip undefined behaviour. gimple-ssa-isolate-paths turns them + to volatile accesses and adds builtin_trap call which would + confuse us otherwise. */ + if (infer_nonnull_range_by_dereference (gsi_stmt (gsi), + null_pointer_node)) + { + if (dump_file) + fprintf (dump_file, " NULL memory access; terminating BB%s\n", + flag_non_call_exceptions ? "; looping" : ""); + if (flag_non_call_exceptions) + { + l->looping = true; + if (stmt_can_throw_external (cfun, gsi_stmt (gsi))) + { + if (dump_file) + fprintf (dump_file, " can throw externally\n"); + l->can_throw = true; + } + } + break; + } check_stmt (&gsi, l, ipa); if (l->pure_const_state == IPA_NEITHER && l->looping diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 2a36b53..349b795 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,37 @@ +2021-12-12 Antoni Boucher <bouanto@zoho.com> + + PR target/95415 + * docs/topics/compatibility.rst (LIBGCCJIT_ABI_17): New ABI + tag. + * docs/topics/expressions.rst: Add document for the function + gcc_jit_lvalue_set_tls_model. + * jit-playback.h: New function (set_tls_model). + * jit-recording.c: New function (set_tls_model), new + variables (tls_models and tls_model_enum_strings) and support + for setting the tls model. + * jit-recording.h: New function (set_tls_model) and new + field m_tls_model. + * libgccjit.c: New function (gcc_jit_lvalue_set_tls_model). + * libgccjit.h: New function (gcc_jit_lvalue_set_tls_model) + and new enum (gcc_jit_tls_model). + * libgccjit.map (LIBGCCJIT_ABI_17): New ABI tag. + +2021-12-11 Antoni Boucher <bouanto@zoho.com> + + PR target/96066 + PR target/96067 + * jit-builtins.c: Implement missing types for builtins. + * jit-recording.c:: Allow sending a volatile const void * as + argument. + * jit-recording.h: New functions (is_volatile, is_const) and + allow comparing qualified types. + +2021-12-10 David Malcolm <dmalcolm@redhat.com> + + PR jit/103562 + * jit-playback.c (gcc::jit::playback::context::new_function): Set + DECL_CONTEXT of the result_decl. + 2021-11-27 Petter Tomner <tomner@kth.se> * libgccjit.c: %ld -> %zu diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 52ee3f8..2ad6e42 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -284,3 +284,12 @@ entrypoints: * :func:`gcc_jit_struct_get_field` * :func:`gcc_jit_struct_get_field_count` + +.. _LIBGCCJIT_ABI_17: + +``LIBGCCJIT_ABI_17`` +----------------------- +``LIBGCCJIT_ABI_17`` covers the addition of an API entrypoint to set the +thread-local storage model of a variable: + + * :func:`gcc_jit_lvalue_set_tls_model` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 396259e..386b80d 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -539,6 +539,43 @@ where the rvalue is computed by reading from the storage area. in C. +.. function:: void\ + gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue *lvalue,\ + enum gcc_jit_tls_model model) + + Make a variable a thread-local variable. + + The "model" parameter determines the thread-local storage model of the "lvalue": + + .. type:: enum gcc_jit_tls_model + + .. c:macro:: GCC_JIT_TLS_MODEL_NONE + + Don't set the TLS model. + + .. c:macro:: GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC + + .. c:macro:: GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC + + .. c:macro:: GCC_JIT_TLS_MODEL_INITIAL_EXEC + + .. c:macro:: GCC_JIT_TLS_MODEL_LOCAL_EXEC + + This is analogous to: + + .. code-block:: c + + _Thread_local int foo __attribute__ ((tls_model("MODEL"))); + + in C. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_17`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model + Global variables **************** diff --git a/gcc/jit/jit-builtins.c b/gcc/jit/jit-builtins.c index 1ea96f4..c279dd8 100644 --- a/gcc/jit/jit-builtins.c +++ b/gcc/jit/jit-builtins.c @@ -541,11 +541,11 @@ builtins_manager::make_primitive_type (enum jit_builtin_type type_id) // case BT_DFLOAT128: // case BT_VALIST_REF: // case BT_VALIST_ARG: - // case BT_I1: - // case BT_I2: - // case BT_I4: - // case BT_I8: - // case BT_I16: + case BT_I1: return m_ctxt->get_int_type (1, true); + case BT_I2: return m_ctxt->get_int_type (2, true); + case BT_I4: return m_ctxt->get_int_type (4, true); + case BT_I8: return m_ctxt->get_int_type (8, true); + case BT_I16: return m_ctxt->get_int_type (16, true); // case BT_PTR_CONST_STRING: } } diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index b412eae..783a037 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -473,6 +473,7 @@ new_function (location *loc, DECL_ARTIFICIAL (resdecl) = 1; DECL_IGNORED_P (resdecl) = 1; DECL_RESULT (fndecl) = resdecl; + DECL_CONTEXT (resdecl) = fndecl; if (builtin_id) { diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index f670c9e..c9839c2 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -675,6 +675,12 @@ public: rvalue * get_address (location *loc); + void + set_tls_model (enum tls_model tls_model) + { + set_decl_tls_model (as_tree (), tls_model); + } + private: bool mark_addressable (location *loc); }; diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 117ff70..5ba35bd 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -2598,8 +2598,13 @@ recording::memento_of_get_pointer::accepts_writes_from (type *rtype) return false; /* It's OK to assign to a (const T *) from a (T *). */ - return m_other_type->unqualified () - ->accepts_writes_from (rtype_points_to); + if (m_other_type->unqualified ()->accepts_writes_from (rtype_points_to)) + { + return true; + } + + /* It's OK to assign to a (volatile const T *) from a (volatile const T *). */ + return m_other_type->is_same_type_as (rtype_points_to); } /* Implementation of pure virtual hook recording::memento::replay_into @@ -3713,6 +3718,12 @@ recording::lvalue::get_address (recording::location *loc) return result; } +void +recording::lvalue::set_tls_model (enum gcc_jit_tls_model model) +{ + m_tls_model = model; +} + /* The implementation of class gcc::jit::recording::param. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -4539,6 +4550,16 @@ recording::block::dump_edges_to_dot (pretty_printer *pp) # pragma GCC diagnostic pop #endif +namespace recording { +static const enum tls_model tls_models[] = { + TLS_MODEL_NONE, /* GCC_JIT_TLS_MODEL_NONE */ + TLS_MODEL_GLOBAL_DYNAMIC, /* GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC */ + TLS_MODEL_LOCAL_DYNAMIC, /* GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC */ + TLS_MODEL_INITIAL_EXEC, /* GCC_JIT_TLS_MODEL_INITIAL_EXEC */ + TLS_MODEL_LOCAL_EXEC, /* GCC_JIT_TLS_MODEL_LOCAL_EXEC */ +}; +} /* namespace recording */ + /* The implementation of class gcc::jit::recording::global. */ /* Implementation of pure virtual hook recording::memento::replay_into @@ -4547,8 +4568,7 @@ recording::block::dump_edges_to_dot (pretty_printer *pp) void recording::global::replay_into (replayer *r) { - set_playback_obj ( - m_initializer + playback::lvalue *global = m_initializer ? r->new_global_initialized (playback_location (r, m_loc), m_kind, m_type->playback_type (), @@ -4560,7 +4580,11 @@ recording::global::replay_into (replayer *r) : r->new_global (playback_location (r, m_loc), m_kind, m_type->playback_type (), - playback_string (m_name))); + playback_string (m_name)); + if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) + global->set_tls_model (recording::tls_models[m_tls_model]); + + set_playback_obj (global); } /* Override the default implementation of @@ -4658,6 +4682,14 @@ recording::global::write_initializer_reproducer (const char *id, reproducer &r) /* Implementation of recording::memento::write_reproducer for globals. */ +static const char * const tls_model_enum_strings[] = { + "GCC_JIT_TLS_MODEL_NONE", + "GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC", + "GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC", + "GCC_JIT_TLS_MODEL_INITIAL_EXEC", + "GCC_JIT_TLS_MODEL_LOCAL_EXEC", +}; + void recording::global::write_reproducer (reproducer &r) { @@ -4675,6 +4707,12 @@ recording::global::write_reproducer (reproducer &r) r.get_identifier_as_type (get_type ()), m_name->get_debug_string ()); + if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) + r.write (" gcc_jit_lvalue_set_tls_model (%s, /* gcc_jit_lvalue *lvalue */\n" + " %s); /* enum gcc_jit_tls_model model */\n", + id, + tls_model_enum_strings[m_tls_model]); + if (m_initializer) switch (m_type->dereference ()->get_size ()) { diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 4a994fe..72fa30c 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -545,6 +545,8 @@ public: virtual bool is_float () const = 0; virtual bool is_bool () const = 0; virtual type *is_pointer () = 0; + virtual type *is_volatile () { return NULL; } + virtual type *is_const () { return NULL; } virtual type *is_array () = 0; virtual struct_ *is_struct () { return NULL; } virtual bool is_void () const { return false; } @@ -687,6 +689,15 @@ public: /* Strip off the "const", giving the underlying type. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } + virtual bool is_same_type_as (type *other) + { + if (!other->is_const ()) + return false; + return m_other_type->is_same_type_as (other->is_const ()); + } + + virtual type *is_const () { return m_other_type; } + void replay_into (replayer *) FINAL OVERRIDE; private: @@ -701,9 +712,18 @@ public: memento_of_get_volatile (type *other_type) : decorated_type (other_type) {} + virtual bool is_same_type_as (type *other) + { + if (!other->is_volatile ()) + return false; + return m_other_type->is_same_type_as (other->is_volatile ()); + } + /* Strip off the "volatile", giving the underlying type. */ type *unqualified () FINAL OVERRIDE { return m_other_type; } + virtual type *is_volatile () { return m_other_type; } + void replay_into (replayer *) FINAL OVERRIDE; private: @@ -1112,7 +1132,8 @@ public: lvalue (context *ctxt, location *loc, type *type_) - : rvalue (ctxt, loc, type_) + : rvalue (ctxt, loc, type_), + m_tls_model (GCC_JIT_TLS_MODEL_NONE) {} playback::lvalue * @@ -1134,6 +1155,10 @@ public: const char *access_as_rvalue (reproducer &r) OVERRIDE; virtual const char *access_as_lvalue (reproducer &r); virtual bool is_global () const { return false; } + void set_tls_model (enum gcc_jit_tls_model model); + +protected: + enum gcc_jit_tls_model m_tls_model; }; class param : public lvalue diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 5d051e4..7ccb76a 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -2220,6 +2220,24 @@ gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue, /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::lvalue::set_tls_model method in jit-recording.c. */ + +void +gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue *lvalue, + enum gcc_jit_tls_model model) +{ + RETURN_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue"); + JIT_LOG_FUNC (lvalue->get_context ()->get_logger ()); + RETURN_IF_FAIL_PRINTF1 (lvalue->is_global (), lvalue->get_context (), NULL, + "lvalue \"%s\" not a global", + lvalue->get_debug_string ()); + + lvalue->set_tls_model (model); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::function::new_local method in jit-recording.c. */ gcc_jit_lvalue * diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index a1c9436..5aa2e40 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -739,6 +739,16 @@ enum gcc_jit_function_kind GCC_JIT_FUNCTION_ALWAYS_INLINE }; +/* Thread local storage model. */ +enum gcc_jit_tls_model +{ + GCC_JIT_TLS_MODEL_NONE, + GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC, + GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC, + GCC_JIT_TLS_MODEL_INITIAL_EXEC, + GCC_JIT_TLS_MODEL_LOCAL_EXEC, +}; + /* Create a function. */ extern gcc_jit_function * gcc_jit_context_new_function (gcc_jit_context *ctxt, @@ -1089,6 +1099,17 @@ extern gcc_jit_rvalue * gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue, gcc_jit_location *loc); +#define LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model + +/* Set the thread-local storage model of a global variable + + This API entrypoint was added in LIBGCCJIT_ABI_17; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model */ +extern void +gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue *lvalue, + enum gcc_jit_tls_model model); + extern gcc_jit_lvalue * gcc_jit_function_new_local (gcc_jit_function *func, gcc_jit_location *loc, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 64e7909..98d693f 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -226,3 +226,8 @@ LIBGCCJIT_ABI_16 { gcc_jit_type_is_struct; gcc_jit_struct_get_field_count; } LIBGCCJIT_ABI_15; + +LIBGCCJIT_ABI_17 { + global: + gcc_jit_lvalue_set_tls_model; +} LIBGCCJIT_ABI_16; diff --git a/gcc/machmode.h b/gcc/machmode.h index 1583513..2e5bafd 100644 --- a/gcc/machmode.h +++ b/gcc/machmode.h @@ -1199,7 +1199,7 @@ gt_pch_nx (pod_mode<T> *) template<typename T> void -gt_pch_nx (pod_mode<T> *, void (*) (void *, void *), void *) +gt_pch_nx (pod_mode<T> *, void (*) (void *, void *, void *), void *) { } diff --git a/gcc/params.opt b/gcc/params.opt index e725c99..80ec654 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -545,6 +545,14 @@ The maximum expansion factor when copying basic blocks. Common Joined UInteger Var(param_max_hoist_depth) Init(30) Param Optimization Maximum depth of search in the dominator tree for expressions to hoist. +-param=max-inline-functions-called-once-loop-depth= +Common Joined UInteger Var(param_inline_functions_called_once_loop_depth) Init(6) Optimization Param +Maximum loop depth of a call which is considered for inlining functions called once. + +-param=max-inline-functions-called-once-insns= +Common Joined UInteger Var(param_inline_functions_called_once_insns) Init(4000) Optimization Param +Maximum combinaed size of caller and callee wich is inlined if callee is called once. + -param=max-inline-insns-auto= Common Joined UInteger Var(param_max_inline_insns_auto) Init(15) Optimization Param The maximum number of instructions when automatically inlining. diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index 2ead027..4bedf7f 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -43,7 +43,7 @@ #include "tree-ssanames.h" #include "target.h" -static bool compute_objsize_r (tree, gimple *, int, access_ref *, +static bool compute_objsize_r (tree, gimple *, bool, int, access_ref *, ssa_name_limit_t &, pointer_query *); /* Wrapper around the wide_int overload of get_range that accepts @@ -199,7 +199,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end, of the source object. */ access_ref aref; tree src = gimple_call_arg (stmt, 1); - if (compute_objsize (src, stmt, 1, &aref, qry) + if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry) && aref.sizrng[1] < offrng[1]) offrng[1] = aref.sizrng[1]; } @@ -233,7 +233,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end, { access_ref aref; tree src = gimple_call_arg (stmt, 1); - if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry)) + if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry)) offrng[1] = aref.sizrng[1] - 1; else offrng[1] = HOST_WIDE_INT_M1U; @@ -258,7 +258,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end, of the source object. */ access_ref aref; tree src = gimple_call_arg (stmt, 1); - if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry) + if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry) && aref.sizrng[1] < offrng[1]) offrng[1] = aref.sizrng[1]; } @@ -596,15 +596,9 @@ gimple_parm_array_size (tree ptr, wide_int rng[2], return var; } -/* Given a statement STMT, set the bounds of the reference to at most - as many bytes as BOUND or unknown when null, and at least one when - the MINACCESS is true unless BOUND is a constant zero. STMT is - used for context to get accurate range info. */ +/* Initialize the object. */ -access_ref::access_ref (range_query *qry /* = nullptr */, - tree bound /* = NULL_TREE */, - gimple *stmt /* = nullptr */, - bool minaccess /* = false */) +access_ref::access_ref () : ref (), eval ([](tree x){ return x; }), deref (), trail1special (true), base0 (true), parmarray () { @@ -613,21 +607,6 @@ access_ref::access_ref (range_query *qry /* = nullptr */, offmax[0] = offmax[1] = 0; /* Invalidate. */ sizrng[0] = sizrng[1] = -1; - - /* Set the default bounds of the access and adjust below. */ - bndrng[0] = minaccess ? 1 : 0; - bndrng[1] = HOST_WIDE_INT_M1U; - - /* When BOUND is nonnull and a range can be extracted from it, - set the bounds of the access to reflect both it and MINACCESS. - BNDRNG[0] is the size of the minimum access. */ - tree rng[2]; - if (bound && get_size_range (qry, bound, stmt, rng, SR_ALLOW_ZERO)) - { - bndrng[0] = wi::to_offset (rng[0]); - bndrng[1] = wi::to_offset (rng[1]); - bndrng[0] = bndrng[0] > 0 && minaccess ? 1 : 0; - } } /* Return the PHI node REF refers to or null if it doesn't. */ @@ -645,6 +624,102 @@ access_ref::phi () const return as_a <gphi *> (def_stmt); } +/* Determine the size and offset for ARG, append it to ALL_REFS, and + merge the result with *THIS. Ignore ARG if SKIP_NULL is set and + ARG refers to the null pointer. Return true on success and false + on failure. */ + +bool +access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt, + int ostype, bool skip_null, + ssa_name_limit_t &snlim, pointer_query &qry) +{ + access_ref aref; + if (!compute_objsize_r (arg, stmt, false, ostype, &aref, snlim, &qry) + || aref.sizrng[0] < 0) + /* This may be a PHI with all null pointer arguments. */ + return false; + + if (all_refs) + { + access_ref dummy_ref; + aref.get_ref (all_refs, &dummy_ref, ostype, &snlim, &qry); + } + + if (TREE_CODE (arg) == SSA_NAME) + qry.put_ref (arg, aref, ostype); + + if (all_refs) + all_refs->safe_push (aref); + + aref.deref += deref; + + bool merged_parmarray = aref.parmarray; + + const bool nullp = skip_null && integer_zerop (arg); + const offset_int maxobjsize = wi::to_offset (max_object_size ()); + offset_int minsize = sizrng[0]; + + if (sizrng[0] < 0) + { + /* If *THIS doesn't contain a meaningful result yet set it to AREF + unless the argument is null and it's okay to ignore it. */ + if (!nullp) + *this = aref; + + /* Set if the current argument refers to one or more objects of + known size (or range of sizes), as opposed to referring to + one or more unknown object(s). */ + const bool arg_known_size = (aref.sizrng[0] != 0 + || aref.sizrng[1] != maxobjsize); + if (arg_known_size) + sizrng[0] = aref.sizrng[0]; + + return true; + } + + /* Disregard null pointers in PHIs with two or more arguments. + TODO: Handle this better! */ + if (nullp) + return true; + + const bool known_size = (sizrng[0] != 0 || sizrng[1] != maxobjsize); + + if (known_size && aref.sizrng[0] < minsize) + minsize = aref.sizrng[0]; + + /* Extend the size and offset of *THIS to account for AREF. The result + can be cached but results in false negatives. */ + + offset_int orng[2]; + if (sizrng[1] < aref.sizrng[1]) + { + orng[0] = offrng[0]; + orng[1] = offrng[1]; + *this = aref; + } + else + { + orng[0] = aref.offrng[0]; + orng[1] = aref.offrng[1]; + } + + if (orng[0] < offrng[0]) + offrng[0] = orng[0]; + if (offrng[1] < orng[1]) + offrng[1] = orng[1]; + + /* Reset the PHI's BASE0 flag if any of the nonnull arguments + refers to an object at an unknown offset. */ + if (!aref.base0) + base0 = false; + + sizrng[0] = minsize; + parmarray = merged_parmarray; + + return true; +} + /* Determine and return the largest object to which *THIS refers. If *THIS refers to a PHI and PREF is nonnull, fill *PREF with the details of the object determined by compute_objsize(ARG, OSTYPE) for each PHI @@ -657,9 +732,8 @@ access_ref::get_ref (vec<access_ref> *all_refs, ssa_name_limit_t *psnlim /* = NULL */, pointer_query *qry /* = NULL */) const { - gphi *phi_stmt = this->phi (); - if (!phi_stmt) - return ref; + if (!ref || TREE_CODE (ref) != SSA_NAME) + return NULL; /* FIXME: Calling get_ref() with a null PSNLIM is dangerous and might cause unbounded recursion. */ @@ -667,13 +741,49 @@ access_ref::get_ref (vec<access_ref> *all_refs, if (!psnlim) psnlim = &snlim_buf; - if (!psnlim->visit_phi (ref)) - return NULL_TREE; - pointer_query empty_qry; if (!qry) qry = &empty_qry; + if (gimple *def_stmt = SSA_NAME_DEF_STMT (ref)) + { + if (is_gimple_assign (def_stmt)) + { + tree_code code = gimple_assign_rhs_code (def_stmt); + if (code != MIN_EXPR && code != MAX_EXPR) + return NULL_TREE; + + access_ref aref; + tree arg1 = gimple_assign_rhs1 (def_stmt); + if (!aref.merge_ref (all_refs, arg1, def_stmt, ostype, false, + *psnlim, *qry)) + return NULL_TREE; + + tree arg2 = gimple_assign_rhs2 (def_stmt); + if (!aref.merge_ref (all_refs, arg2, def_stmt, ostype, false, + *psnlim, *qry)) + return NULL_TREE; + + if (pref && pref != this) + { + tree ref = pref->ref; + *pref = aref; + pref->ref = ref; + } + + return aref.ref; + } + } + else + return NULL_TREE; + + gphi *phi_stmt = this->phi (); + if (!phi_stmt) + return ref; + + if (!psnlim->visit_phi (ref)) + return NULL_TREE; + /* The conservative result of the PHI reflecting the offset and size of the largest PHI argument, regardless of whether or not they all refer to the same object. */ @@ -691,91 +801,17 @@ access_ref::get_ref (vec<access_ref> *all_refs, phi_ref = *pref; } - /* Set if any argument is a function array (or VLA) parameter not - declared [static]. */ - bool parmarray = false; - /* The size of the smallest object referenced by the PHI arguments. */ - offset_int minsize = 0; - const offset_int maxobjsize = wi::to_offset (max_object_size ()); - const unsigned nargs = gimple_phi_num_args (phi_stmt); for (unsigned i = 0; i < nargs; ++i) { access_ref phi_arg_ref; + bool skip_null = i || i + 1 < nargs; tree arg = gimple_phi_arg_def (phi_stmt, i); - if (!compute_objsize_r (arg, phi_stmt, ostype, &phi_arg_ref, *psnlim, - qry) - || phi_arg_ref.sizrng[0] < 0) - /* A PHI with all null pointer arguments. */ + if (!phi_ref.merge_ref (all_refs, arg, phi_stmt, ostype, skip_null, + *psnlim, *qry)) return NULL_TREE; - - if (TREE_CODE (arg) == SSA_NAME) - qry->put_ref (arg, phi_arg_ref); - - if (all_refs) - all_refs->safe_push (phi_arg_ref); - - parmarray |= phi_arg_ref.parmarray; - - const bool nullp = integer_zerop (arg) && (i || i + 1 < nargs); - - if (phi_ref.sizrng[0] < 0) - { - /* If PHI_REF doesn't contain a meaningful result yet set it - to the result for the first argument. */ - if (!nullp) - phi_ref = phi_arg_ref; - - /* Set if the current argument refers to one or more objects of - known size (or range of sizes), as opposed to referring to - one or more unknown object(s). */ - const bool arg_known_size = (phi_arg_ref.sizrng[0] != 0 - || phi_arg_ref.sizrng[1] != maxobjsize); - if (arg_known_size) - minsize = phi_arg_ref.sizrng[0]; - - continue; - } - - const bool phi_known_size = (phi_ref.sizrng[0] != 0 - || phi_ref.sizrng[1] != maxobjsize); - - if (phi_known_size && phi_arg_ref.sizrng[0] < minsize) - minsize = phi_arg_ref.sizrng[0]; - - /* Disregard null pointers in PHIs with two or more arguments. - TODO: Handle this better! */ - if (nullp) - continue; - - /* Determine the amount of remaining space in the argument. */ - offset_int argrem[2]; - argrem[1] = phi_arg_ref.size_remaining (argrem); - - /* Determine the amount of remaining space computed so far and - if the remaining space in the argument is more use it instead. */ - offset_int phirem[2]; - phirem[1] = phi_ref.size_remaining (phirem); - - /* Reset the PHI's BASE0 flag if any of the nonnull arguments - refers to an object at an unknown offset. */ - if (!phi_arg_ref.base0) - phi_ref.base0 = false; - - if (phirem[1] < argrem[1] - || (phirem[1] == argrem[1] - && phi_ref.sizrng[1] < phi_arg_ref.sizrng[1])) - /* Use the argument with the most space remaining as the result, - or the larger one if the space is equal. */ - phi_ref = phi_arg_ref; } - /* Replace the lower bound of the largest argument with the size - of the smallest argument, and set PARMARRAY if any argument - was one. */ - phi_ref.sizrng[0] = minsize; - phi_ref.parmarray = parmarray; - if (phi_ref.sizrng[0] < 0) { /* Fail if none of the PHI's arguments resulted in updating PHI_REF @@ -787,7 +823,14 @@ access_ref::get_ref (vec<access_ref> *all_refs, /* Avoid changing *THIS. */ if (pref && pref != this) - *pref = phi_ref; + { + /* Keep the SSA_NAME of the PHI unchanged so that all PHI arguments + can be referred to later if necessary. This is useful even if + they all refer to the same object. */ + tree ref = pref->ref; + *pref = phi_ref; + pref->ref = ref; + } psnlim->leave_phi (ref); @@ -959,42 +1002,45 @@ void access_ref::add_offset (const offset_int &min, const offset_int &max) WRITE is set for a write access and clear for a read access. */ void -access_ref::inform_access (access_mode mode) const +access_ref::inform_access (access_mode mode, int ostype /* = 1 */) const { const access_ref &aref = *this; if (!aref.ref) return; - if (aref.phi ()) + if (phi ()) { /* Set MAXREF to refer to the largest object and fill ALL_REFS with data for all objects referenced by the PHI arguments. */ access_ref maxref; auto_vec<access_ref> all_refs; - if (!get_ref (&all_refs, &maxref)) + if (!get_ref (&all_refs, &maxref, ostype)) return; - /* Except for MAXREF, the rest of the arguments' offsets need not - reflect one added to the PHI itself. Determine the latter from - MAXREF on which the result is based. */ - const offset_int orng[] = + if (all_refs.length ()) { - offrng[0] - maxref.offrng[0], - wi::smax (offrng[1] - maxref.offrng[1], offrng[0]), - }; + /* Except for MAXREF, the rest of the arguments' offsets need not + reflect one added to the PHI itself. Determine the latter from + MAXREF on which the result is based. */ + const offset_int orng[] = + { + offrng[0] - maxref.offrng[0], + wi::smax (offrng[1] - maxref.offrng[1], offrng[0]), + }; - /* Add the final PHI's offset to that of each of the arguments - and recurse to issue an inform message for it. */ - for (unsigned i = 0; i != all_refs.length (); ++i) - { - /* Skip any PHIs; those could lead to infinite recursion. */ - if (all_refs[i].phi ()) - continue; + /* Add the final PHI's offset to that of each of the arguments + and recurse to issue an inform message for it. */ + for (unsigned i = 0; i != all_refs.length (); ++i) + { + /* Skip any PHIs; those could lead to infinite recursion. */ + if (all_refs[i].phi ()) + continue; - all_refs[i].add_offset (orng[0], orng[1]); - all_refs[i].inform_access (mode); + all_refs[i].add_offset (orng[0], orng[1]); + all_refs[i].inform_access (mode, ostype); + } + return; } - return; } /* Convert offset range and avoid including a zero range since it @@ -1199,6 +1245,111 @@ access_ref::inform_access (access_mode mode) const sizestr, allocfn); } +/* Dump *THIS to FILE. */ + +void +access_ref::dump (FILE *file) const +{ + for (int i = deref; i < 0; ++i) + fputc ('&', file); + + for (int i = 0; i < deref; ++i) + fputc ('*', file); + + if (gphi *phi_stmt = phi ()) + { + fputs ("PHI <", file); + unsigned nargs = gimple_phi_num_args (phi_stmt); + for (unsigned i = 0; i != nargs; ++i) + { + tree arg = gimple_phi_arg_def (phi_stmt, i); + print_generic_expr (file, arg); + if (i + 1 < nargs) + fputs (", ", file); + } + fputc ('>', file); + } + else + print_generic_expr (file, ref); + + if (offrng[0] != offrng[1]) + fprintf (file, " + [%lli, %lli]", + (long long) offrng[0].to_shwi (), + (long long) offrng[1].to_shwi ()); + else if (offrng[0] != 0) + fprintf (file, " %c %lli", + offrng[0] < 0 ? '-' : '+', + (long long) offrng[0].to_shwi ()); + + if (base0) + fputs (" (base0)", file); + + fputs ("; size: ", file); + if (sizrng[0] != sizrng[1]) + { + offset_int maxsize = wi::to_offset (max_object_size ()); + if (sizrng[0] == 0 && sizrng[1] >= maxsize) + fputs ("unknown", file); + else + fprintf (file, "[%llu, %llu]", + (unsigned long long) sizrng[0].to_uhwi (), + (unsigned long long) sizrng[1].to_uhwi ()); + } + else if (sizrng[0] != 0) + fprintf (file, "%llu", + (unsigned long long) sizrng[0].to_uhwi ()); + + fputc ('\n', file); +} + +/* Set the access to at most MAXWRITE and MAXREAD bytes, and at least 1 + when MINWRITE or MINREAD, respectively, is set. */ +access_data::access_data (range_query *query, gimple *stmt, access_mode mode, + tree maxwrite /* = NULL_TREE */, + bool minwrite /* = false */, + tree maxread /* = NULL_TREE */, + bool minread /* = false */) + : stmt (stmt), call (), dst (), src (), mode (mode), ostype () +{ + set_bound (dst_bndrng, maxwrite, minwrite, query, stmt); + set_bound (src_bndrng, maxread, minread, query, stmt); +} + +/* Set the access to at most MAXWRITE and MAXREAD bytes, and at least 1 + when MINWRITE or MINREAD, respectively, is set. */ +access_data::access_data (range_query *query, tree expr, access_mode mode, + tree maxwrite /* = NULL_TREE */, + bool minwrite /* = false */, + tree maxread /* = NULL_TREE */, + bool minread /* = false */) + : stmt (), call (expr), dst (), src (), mode (mode), ostype () +{ + set_bound (dst_bndrng, maxwrite, minwrite, query, stmt); + set_bound (src_bndrng, maxread, minread, query, stmt); +} + +/* Set BNDRNG to the range of BOUND for the statement STMT. */ + +void +access_data::set_bound (offset_int bndrng[2], tree bound, bool minaccess, + range_query *query, gimple *stmt) +{ + /* Set the default bounds of the access and adjust below. */ + bndrng[0] = minaccess ? 1 : 0; + bndrng[1] = HOST_WIDE_INT_M1U; + + /* When BOUND is nonnull and a range can be extracted from it, + set the bounds of the access to reflect both it and MINACCESS. + BNDRNG[0] is the size of the minimum access. */ + tree rng[2]; + if (bound && get_size_range (query, bound, stmt, rng, SR_ALLOW_ZERO)) + { + bndrng[0] = wi::to_offset (rng[0]); + bndrng[1] = wi::to_offset (rng[1]); + bndrng[0] = bndrng[0] > 0 && minaccess ? 1 : 0; + } +} + /* Set a bit for the PHI in VISITED and return true if it wasn't already set. */ @@ -1320,7 +1471,8 @@ pointer_query::get_ref (tree ptr, int ostype /* = 1 */) const there or compute it and insert it into the cache if it's nonnonull. */ bool -pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref, int ostype /* = 1 */) +pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref, + int ostype /* = 1 */) { const unsigned version = TREE_CODE (ptr) == SSA_NAME ? SSA_NAME_VERSION (ptr) : 0; @@ -1408,6 +1560,9 @@ pointer_query::flush_cache () void pointer_query::dump (FILE *dump_file, bool contents /* = false */) { + if (!var_cache) + return; + unsigned nused = 0, nrefs = 0; unsigned nidxs = var_cache->indices.length (); for (unsigned i = 0; i != nidxs; ++i) @@ -1468,35 +1623,40 @@ pointer_query::dump (FILE *dump_file, bool contents /* = false */) else fprintf (dump_file, " _%u = ", ver); - if (gphi *phi = aref.phi ()) - { - fputs ("PHI <", dump_file); - unsigned nargs = gimple_phi_num_args (phi); - for (unsigned i = 0; i != nargs; ++i) - { - tree arg = gimple_phi_arg_def (phi, i); - print_generic_expr (dump_file, arg); - if (i + 1 < nargs) - fputs (", ", dump_file); - } - fputc ('>', dump_file); - } - else - print_generic_expr (dump_file, aref.ref); - - if (aref.offrng[0] != aref.offrng[1]) - fprintf (dump_file, " + [%lli, %lli]", - (long long) aref.offrng[0].to_shwi (), - (long long) aref.offrng[1].to_shwi ()); - else if (aref.offrng[0] != 0) - fprintf (dump_file, " %c %lli", - aref.offrng[0] < 0 ? '-' : '+', - (long long) aref.offrng[0].to_shwi ()); - - fputc ('\n', dump_file); + aref.dump (dump_file); } fputc ('\n', dump_file); + + { + fputs ("\npointer_query cache contents (again):\n", dump_file); + + tree var; + unsigned i; + FOR_EACH_SSA_NAME (i, var, cfun) + { + if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE) + continue; + + for (unsigned ost = 0; ost != 2; ++ost) + { + if (const access_ref *cache_ref = get_ref (var, ost)) + { + unsigned ver = SSA_NAME_VERSION (var); + fprintf (dump_file, " %u.%u: ", ver, ost); + if (tree name = ssa_name (ver)) + { + print_generic_expr (dump_file, name); + fputs (" = ", dump_file); + } + else + fprintf (dump_file, " _%u = ", ver); + + cache_ref->dump (dump_file); + } + } + } + } } /* A helper of compute_objsize_r() to determine the size from an assignment @@ -1520,7 +1680,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref, for the expression. */ access_ref aref[2] = { *pref, *pref }; tree arg1 = gimple_assign_rhs1 (stmt); - if (!compute_objsize_r (arg1, stmt, ostype, &aref[0], snlim, qry)) + if (!compute_objsize_r (arg1, stmt, false, ostype, &aref[0], snlim, qry)) { aref[0].base0 = false; aref[0].offrng[0] = aref[0].offrng[1] = 0; @@ -1529,7 +1689,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref, } tree arg2 = gimple_assign_rhs2 (stmt); - if (!compute_objsize_r (arg2, stmt, ostype, &aref[1], snlim, qry)) + if (!compute_objsize_r (arg2, stmt, false, ostype, &aref[1], snlim, qry)) { aref[1].base0 = false; aref[1].offrng[0] = aref[1].offrng[1] = 0; @@ -1592,6 +1752,46 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref, return true; } +/* A helper of compute_objsize_r() to determine the size of a DECL. + Return true on success and (possibly in the future) false on failure. */ + +static bool +handle_decl (tree decl, bool addr, access_ref *pref) +{ + tree decl_type = TREE_TYPE (decl); + + pref->ref = decl; + + /* Reset the offset in case it was set by a prior call and not + cleared by the caller. The offset is only adjusted after + the identity of the object has been determined. */ + pref->offrng[0] = pref->offrng[1] = 0; + + if (!addr && POINTER_TYPE_P (decl_type)) + { + /* Set the maximum size if the reference is to the pointer + itself (as opposed to what it points to), and clear + BASE0 since the offset isn't necessarily zero-based. */ + pref->set_max_size_range (); + pref->base0 = false; + return true; + } + + /* Valid offsets into the object are nonnegative. */ + pref->base0 = true; + + if (tree size = decl_init_size (decl, false)) + if (TREE_CODE (size) == INTEGER_CST) + { + pref->sizrng[0] = wi::to_offset (size); + pref->sizrng[1] = pref->sizrng[0]; + return true; + } + + pref->set_max_size_range (); + return true; +} + /* A helper of compute_objsize_r() to determine the size from ARRAY_REF AREF. ADDR is true if PTR is the operand of ADDR_EXPR. Return true on success and false on failure. */ @@ -1603,8 +1803,6 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype, { gcc_assert (TREE_CODE (aref) == ARRAY_REF); - ++pref->deref; - tree arefop = TREE_OPERAND (aref, 0); tree reftype = TREE_TYPE (arefop); if (!addr && TREE_CODE (TREE_TYPE (reftype)) == POINTER_TYPE) @@ -1612,13 +1810,13 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype, of known bound. */ return false; - if (!compute_objsize_r (arefop, stmt, ostype, pref, snlim, qry)) + if (!compute_objsize_r (arefop, stmt, addr, ostype, pref, snlim, qry)) return false; offset_int orng[2]; tree off = pref->eval (TREE_OPERAND (aref, 1)); range_query *const rvals = qry ? qry->rvals : NULL; - if (!get_offset_range (off, NULL, orng, rvals)) + if (!get_offset_range (off, stmt, orng, rvals)) { /* Set ORNG to the maximum offset representable in ptrdiff_t. */ orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); @@ -1673,6 +1871,96 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype, return true; } +/* Given a COMPONENT_REF CREF, set *PREF size to the size of the referenced + member. */ + +static void +set_component_ref_size (tree cref, access_ref *pref) +{ + const tree base = TREE_OPERAND (cref, 0); + const tree base_type = TREE_TYPE (base); + + /* SAM is set for array members that might need special treatment. */ + special_array_member sam; + tree size = component_ref_size (cref, &sam); + if (sam == special_array_member::int_0) + pref->sizrng[0] = pref->sizrng[1] = 0; + else if (!pref->trail1special && sam == special_array_member::trail_1) + pref->sizrng[0] = pref->sizrng[1] = 1; + else if (size && TREE_CODE (size) == INTEGER_CST) + pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size); + else + { + /* When the size of the member is unknown it's either a flexible + array member or a trailing special array member (either zero + length or one-element). Set the size to the maximum minus + the constant size of the base object's type. */ + pref->sizrng[0] = 0; + pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); + if (tree base_size = TYPE_SIZE_UNIT (base_type)) + if (TREE_CODE (base_size) == INTEGER_CST) + pref->sizrng[1] -= wi::to_offset (base_size); + } +} + +/* A helper of compute_objsize_r() to determine the size from COMPONENT_REF + CREF. Return true on success and false on failure. */ + +static bool +handle_component_ref (tree cref, gimple *stmt, bool addr, int ostype, + access_ref *pref, ssa_name_limit_t &snlim, + pointer_query *qry) +{ + gcc_assert (TREE_CODE (cref) == COMPONENT_REF); + + const tree base = TREE_OPERAND (cref, 0); + const tree base_type = TREE_TYPE (base); + if (TREE_CODE (base_type) == UNION_TYPE) + /* In accesses through union types consider the entire unions + rather than just their members. */ + ostype = 0; + + tree field = TREE_OPERAND (cref, 1); + + if (ostype == 0) + { + /* In OSTYPE zero (for raw memory functions like memcpy), use + the maximum size instead if the identity of the enclosing + object cannot be determined. */ + if (!compute_objsize_r (base, stmt, addr, ostype, pref, snlim, qry)) + return false; + + /* Otherwise, use the size of the enclosing object and add + the offset of the member to the offset computed so far. */ + tree offset = byte_position (field); + if (TREE_CODE (offset) == INTEGER_CST) + pref->add_offset (wi::to_offset (offset)); + else + pref->add_max_offset (); + + if (!pref->ref) + /* PREF->REF may have been already set to an SSA_NAME earlier + to provide better context for diagnostics. In that case, + leave it unchanged. */ + pref->ref = base; + + return true; + } + + pref->ref = field; + + if (!addr && POINTER_TYPE_P (TREE_TYPE (field))) + { + /* Set maximum size if the reference is to the pointer member + itself (as opposed to what it points to). */ + pref->set_max_size_range (); + return true; + } + + set_component_ref_size (cref, pref); + return true; +} + /* A helper of compute_objsize_r() to determine the size from MEM_REF MREF. Return true on success and false on failure. */ @@ -1682,10 +1970,9 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref, { gcc_assert (TREE_CODE (mref) == MEM_REF); - ++pref->deref; - - if (VECTOR_TYPE_P (TREE_TYPE (mref))) - { + tree mreftype = TYPE_MAIN_VARIANT (TREE_TYPE (mref)); + if (VECTOR_TYPE_P (mreftype)) + { /* Hack: Handle MEM_REFs of vector types as those to complete objects; those may be synthesized from multiple assignments to consecutive data members (see PR 93200 and 96963). @@ -1699,13 +1986,15 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref, } tree mrefop = TREE_OPERAND (mref, 0); - if (!compute_objsize_r (mrefop, stmt, ostype, pref, snlim, qry)) + if (!compute_objsize_r (mrefop, stmt, false, ostype, pref, snlim, qry)) return false; + ++pref->deref; + offset_int orng[2]; tree off = pref->eval (TREE_OPERAND (mref, 1)); range_query *const rvals = qry ? qry->rvals : NULL; - if (!get_offset_range (off, NULL, orng, rvals)) + if (!get_offset_range (off, stmt, orng, rvals)) { /* Set ORNG to the maximum offset representable in ptrdiff_t. */ orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); @@ -1716,168 +2005,283 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref, return true; } -/* Helper to compute the size of the object referenced by the PTR - expression which must have pointer type, using Object Size type - OSTYPE (only the least significant 2 bits are used). - On success, sets PREF->REF to the DECL of the referenced object - if it's unique, otherwise to null, PREF->OFFRNG to the range of - offsets into it, and PREF->SIZRNG to the range of sizes of - the object(s). - SNLIM is used to avoid visiting the same PHI operand multiple - times, and, when nonnull, RVALS to determine range information. - Returns true on success, false when a meaningful size (or range) - cannot be determined. - - The function is intended for diagnostics and should not be used - to influence code generation or optimization. */ +/* A helper of compute_objsize_r() to determine the size from SSA_NAME + PTR. Return true on success and false on failure. */ static bool -compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref, - ssa_name_limit_t &snlim, pointer_query *qry) +handle_ssa_name (tree ptr, bool addr, int ostype, + access_ref *pref, ssa_name_limit_t &snlim, + pointer_query *qry) { - STRIP_NOPS (ptr); + if (!snlim.next ()) + return false; - const bool addr = TREE_CODE (ptr) == ADDR_EXPR; - if (addr) + /* Only process an SSA_NAME if the recursion limit has not yet + been reached. */ + if (qry) { - --pref->deref; - ptr = TREE_OPERAND (ptr, 0); + if (++qry->depth > qry->max_depth) + qry->max_depth = qry->depth; + if (const access_ref *cache_ref = qry->get_ref (ptr, ostype)) + { + /* Add the number of DEREFerences accummulated so far. */ + const int deref = pref->deref; + *pref = *cache_ref; + pref->deref += deref; + return true; + } } - if (DECL_P (ptr)) + gimple *stmt = SSA_NAME_DEF_STMT (ptr); + if (is_gimple_call (stmt)) { - pref->ref = ptr; - - /* Reset the offset in case it was set by a prior call and not - cleared by the caller. The offset is only adjusted after - the identity of the object has been determined. */ - pref->offrng[0] = pref->offrng[1] = 0; + /* If STMT is a call to an allocation function get the size + from its argument(s). If successful, also set *PREF->REF + to PTR for the caller to include in diagnostics. */ + wide_int wr[2]; + range_query *const rvals = qry ? qry->rvals : NULL; + if (gimple_call_alloc_size (stmt, wr, rvals)) + { + pref->ref = ptr; + pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED); + pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED); + /* Constrain both bounds to a valid size. */ + offset_int maxsize = wi::to_offset (max_object_size ()); + if (pref->sizrng[0] > maxsize) + pref->sizrng[0] = maxsize; + if (pref->sizrng[1] > maxsize) + pref->sizrng[1] = maxsize; + } + else + { + /* For functions known to return one of their pointer arguments + try to determine what the returned pointer points to, and on + success add OFFRNG which was set to the offset added by + the function (e.g., memchr) to the overall offset. */ + bool past_end; + offset_int offrng[2]; + if (tree ret = gimple_call_return_array (stmt, offrng, &past_end, + snlim, qry)) + { + if (!compute_objsize_r (ret, stmt, addr, ostype, pref, snlim, qry)) + return false; + + /* Cap OFFRNG[1] to at most the remaining size of + the object. */ + offset_int remrng[2]; + remrng[1] = pref->size_remaining (remrng); + if (remrng[1] != 0 && !past_end) + /* Decrement the size for functions that never return + a past-the-end pointer. */ + remrng[1] -= 1; + + if (remrng[1] < offrng[1]) + offrng[1] = remrng[1]; + pref->add_offset (offrng[0], offrng[1]); + } + else + { + /* For other calls that might return arbitrary pointers + including into the middle of objects set the size + range to maximum, clear PREF->BASE0, and also set + PREF->REF to include in diagnostics. */ + pref->set_max_size_range (); + pref->base0 = false; + pref->ref = ptr; + } + } + qry->put_ref (ptr, *pref, ostype); + return true; + } - if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr))) + if (gimple_nop_p (stmt)) + { + /* For a function argument try to determine the byte size + of the array from the current function declaratation + (e.g., attribute access or related). */ + wide_int wr[2]; + bool static_array = false; + if (tree ref = gimple_parm_array_size (ptr, wr, &static_array)) { - /* Set the maximum size if the reference is to the pointer - itself (as opposed to what it points to), and clear - BASE0 since the offset isn't necessarily zero-based. */ - pref->set_max_size_range (); - pref->base0 = false; + pref->parmarray = !static_array; + pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED); + pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED); + pref->ref = ref; + qry->put_ref (ptr, *pref, ostype); return true; } - /* Valid offsets into the object are nonnegative. */ - pref->base0 = true; - - if (tree size = decl_init_size (ptr, false)) - if (TREE_CODE (size) == INTEGER_CST) - { - pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size); - return true; - } - pref->set_max_size_range (); + pref->base0 = false; + pref->ref = ptr; + qry->put_ref (ptr, *pref, ostype); return true; } - const tree_code code = TREE_CODE (ptr); - range_query *const rvals = qry ? qry->rvals : NULL; - - if (code == BIT_FIELD_REF) + if (gimple_code (stmt) == GIMPLE_PHI) { - tree ref = TREE_OPERAND (ptr, 0); - if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry)) + /* Pass PTR to get_ref() via PREF. If all PHI arguments refer + to the same object the function will replace it with it. */ + pref->ref = ptr; + access_ref phi_ref = *pref; + if (!pref->get_ref (NULL, &phi_ref, ostype, &snlim, qry)) return false; + *pref = phi_ref; + qry->put_ref (ptr, *pref, ostype); + return true; + } - offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2))); - pref->add_offset (off / BITS_PER_UNIT); + if (!is_gimple_assign (stmt)) + { + /* Clear BASE0 since the assigned pointer might point into + the middle of the object, set the maximum size range and, + if the SSA_NAME refers to a function argumnent, set + PREF->REF to it. */ + pref->base0 = false; + pref->set_max_size_range (); + pref->ref = ptr; return true; } - if (code == COMPONENT_REF) + tree_code code = gimple_assign_rhs_code (stmt); + + if (code == MAX_EXPR || code == MIN_EXPR) { - tree ref = TREE_OPERAND (ptr, 0); - if (TREE_CODE (TREE_TYPE (ref)) == UNION_TYPE) - /* In accesses through union types consider the entire unions - rather than just their members. */ - ostype = 0; - tree field = TREE_OPERAND (ptr, 1); + if (!handle_min_max_size (ptr, ostype, pref, snlim, qry)) + return false; - if (ostype == 0) - { - /* In OSTYPE zero (for raw memory functions like memcpy), use - the maximum size instead if the identity of the enclosing - object cannot be determined. */ - if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry)) - return false; - - /* Otherwise, use the size of the enclosing object and add - the offset of the member to the offset computed so far. */ - tree offset = byte_position (field); - if (TREE_CODE (offset) == INTEGER_CST) - pref->add_offset (wi::to_offset (offset)); - else - pref->add_max_offset (); + qry->put_ref (ptr, *pref, ostype); + return true; + } - if (!pref->ref) - /* REF may have been already set to an SSA_NAME earlier - to provide better context for diagnostics. In that case, - leave it unchanged. */ - pref->ref = ref; - return true; - } + tree rhs = gimple_assign_rhs1 (stmt); - pref->ref = field; + if (code == ASSERT_EXPR) + { + rhs = TREE_OPERAND (rhs, 0); + return compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry); + } - if (!addr && POINTER_TYPE_P (TREE_TYPE (field))) - { - /* Set maximum size if the reference is to the pointer member - itself (as opposed to what it points to). */ - pref->set_max_size_range (); - return true; - } + if (code == POINTER_PLUS_EXPR + && TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE) + { + /* Compute the size of the object first. */ + if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry)) + return false; - /* SAM is set for array members that might need special treatment. */ - special_array_member sam; - tree size = component_ref_size (ptr, &sam); - if (sam == special_array_member::int_0) - pref->sizrng[0] = pref->sizrng[1] = 0; - else if (!pref->trail1special && sam == special_array_member::trail_1) - pref->sizrng[0] = pref->sizrng[1] = 1; - else if (size && TREE_CODE (size) == INTEGER_CST) - pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size); + offset_int orng[2]; + tree off = gimple_assign_rhs2 (stmt); + range_query *const rvals = qry ? qry->rvals : NULL; + if (get_offset_range (off, stmt, orng, rvals)) + pref->add_offset (orng[0], orng[1]); else - { - /* When the size of the member is unknown it's either a flexible - array member or a trailing special array member (either zero - length or one-element). Set the size to the maximum minus - the constant size of the type. */ - pref->sizrng[0] = 0; - pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); - if (tree recsize = TYPE_SIZE_UNIT (TREE_TYPE (ref))) - if (TREE_CODE (recsize) == INTEGER_CST) - pref->sizrng[1] -= wi::to_offset (recsize); - } + pref->add_max_offset (); + + qry->put_ref (ptr, *pref, ostype); return true; } - if (code == ARRAY_REF) - return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry); - - if (code == MEM_REF) - return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry); + if (code == ADDR_EXPR || code == SSA_NAME) + { + if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry)) + return false; + qry->put_ref (ptr, *pref, ostype); + return true; + } - if (code == TARGET_MEM_REF) + if (ostype > 1 && POINTER_TYPE_P (TREE_TYPE (rhs))) { - tree ref = TREE_OPERAND (ptr, 0); - if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry)) + /* When determining the qualifiers follow the pointer but + avoid caching the result. As the pointer is added to + and/or dereferenced the computed size and offset need + not be meaningful for other queries involving the same + pointer. */ + if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry)) return false; - /* TODO: Handle remaining operands. Until then, add maximum offset. */ - pref->ref = ptr; - pref->add_max_offset (); - return true; + rhs = pref->ref; } - if (code == INTEGER_CST) + /* (This could also be an assignment from a nonlocal pointer.) Save + PTR to mention in diagnostics but otherwise treat it as a pointer + to an unknown object. */ + pref->ref = rhs; + pref->base0 = false; + pref->set_max_size_range (); + return true; +} + +/* Helper to compute the size of the object referenced by the PTR + expression which must have pointer type, using Object Size type + OSTYPE (only the least significant 2 bits are used). + On success, sets PREF->REF to the DECL of the referenced object + if it's unique, otherwise to null, PREF->OFFRNG to the range of + offsets into it, and PREF->SIZRNG to the range of sizes of + the object(s). + ADDR is true for an enclosing ADDR_EXPR. + SNLIM is used to avoid visiting the same PHI operand multiple + times, and, when nonnull, RVALS to determine range information. + Returns true on success, false when a meaningful size (or range) + cannot be determined. + + The function is intended for diagnostics and should not be used + to influence code generation or optimization. */ + +static bool +compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype, + access_ref *pref, ssa_name_limit_t &snlim, + pointer_query *qry) +{ + STRIP_NOPS (ptr); + + if (DECL_P (ptr)) + return handle_decl (ptr, addr, pref); + + switch (TREE_CODE (ptr)) { + case ADDR_EXPR: + { + tree ref = TREE_OPERAND (ptr, 0); + if (!compute_objsize_r (ref, stmt, true, ostype, pref, snlim, qry)) + return false; + + --pref->deref; + return true; + } + + case BIT_FIELD_REF: + { + tree ref = TREE_OPERAND (ptr, 0); + if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry)) + return false; + + offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2))); + pref->add_offset (off / BITS_PER_UNIT); + return true; + } + + case ARRAY_REF: + return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry); + + case COMPONENT_REF: + return handle_component_ref (ptr, stmt, addr, ostype, pref, snlim, qry); + + case MEM_REF: + return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry); + + case TARGET_MEM_REF: + { + tree ref = TREE_OPERAND (ptr, 0); + if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry)) + return false; + + /* TODO: Handle remaining operands. Until then, add maximum offset. */ + pref->ref = ptr; + pref->add_max_offset (); + return true; + } + + case INTEGER_CST: /* Pointer constants other than null are most likely the result of erroneous null pointer addition/subtraction. Unless zero is a valid address set size to zero. For null pointers, set @@ -1898,21 +2302,17 @@ compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref, pref->sizrng[0] = pref->sizrng[1] = 0; pref->ref = ptr; - return true; - } - if (code == STRING_CST) - { + case STRING_CST: pref->sizrng[0] = pref->sizrng[1] = TREE_STRING_LENGTH (ptr); pref->ref = ptr; return true; - } - if (code == POINTER_PLUS_EXPR) + case POINTER_PLUS_EXPR: { tree ref = TREE_OPERAND (ptr, 0); - if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry)) + if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry)) return false; /* Clear DEREF since the offset is being applied to the target @@ -1921,206 +2321,22 @@ compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref, offset_int orng[2]; tree off = pref->eval (TREE_OPERAND (ptr, 1)); - if (get_offset_range (off, NULL, orng, rvals)) + if (get_offset_range (off, stmt, orng, qry->rvals)) pref->add_offset (orng[0], orng[1]); else pref->add_max_offset (); return true; } - if (code == VIEW_CONVERT_EXPR) - { + case VIEW_CONVERT_EXPR: ptr = TREE_OPERAND (ptr, 0); - return compute_objsize_r (ptr, stmt, ostype, pref, snlim, qry); - } - - if (code == SSA_NAME) - { - if (!snlim.next ()) - return false; - - /* Only process an SSA_NAME if the recursion limit has not yet - been reached. */ - if (qry) - { - if (++qry->depth) - qry->max_depth = qry->depth; - if (const access_ref *cache_ref = qry->get_ref (ptr)) - { - /* If the pointer is in the cache set *PREF to what it refers - to and return success. - FIXME: BNDRNG is determined by each access and so it doesn't - belong in access_ref. Until the design is changed, keep it - unchanged here. */ - const offset_int bndrng[2] = { pref->bndrng[0], pref->bndrng[1] }; - *pref = *cache_ref; - pref->bndrng[0] = bndrng[0]; - pref->bndrng[1] = bndrng[1]; - return true; - } - } - - stmt = SSA_NAME_DEF_STMT (ptr); - if (is_gimple_call (stmt)) - { - /* If STMT is a call to an allocation function get the size - from its argument(s). If successful, also set *PREF->REF - to PTR for the caller to include in diagnostics. */ - wide_int wr[2]; - if (gimple_call_alloc_size (stmt, wr, rvals)) - { - pref->ref = ptr; - pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED); - pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED); - /* Constrain both bounds to a valid size. */ - offset_int maxsize = wi::to_offset (max_object_size ()); - if (pref->sizrng[0] > maxsize) - pref->sizrng[0] = maxsize; - if (pref->sizrng[1] > maxsize) - pref->sizrng[1] = maxsize; - } - else - { - /* For functions known to return one of their pointer arguments - try to determine what the returned pointer points to, and on - success add OFFRNG which was set to the offset added by - the function (e.g., memchr) to the overall offset. */ - bool past_end; - offset_int offrng[2]; - if (tree ret = gimple_call_return_array (stmt, offrng, - &past_end, snlim, qry)) - { - if (!compute_objsize_r (ret, stmt, ostype, pref, snlim, qry)) - return false; - - /* Cap OFFRNG[1] to at most the remaining size of - the object. */ - offset_int remrng[2]; - remrng[1] = pref->size_remaining (remrng); - if (remrng[1] != 0 && !past_end) - /* Decrement the size for functions that never return - a past-the-end pointer. */ - remrng[1] -= 1; - - if (remrng[1] < offrng[1]) - offrng[1] = remrng[1]; - pref->add_offset (offrng[0], offrng[1]); - } - else - { - /* For other calls that might return arbitrary pointers - including into the middle of objects set the size - range to maximum, clear PREF->BASE0, and also set - PREF->REF to include in diagnostics. */ - pref->set_max_size_range (); - pref->base0 = false; - pref->ref = ptr; - } - } - qry->put_ref (ptr, *pref); - return true; - } - - if (gimple_nop_p (stmt)) - { - /* For a function argument try to determine the byte size - of the array from the current function declaratation - (e.g., attribute access or related). */ - wide_int wr[2]; - bool static_array = false; - if (tree ref = gimple_parm_array_size (ptr, wr, &static_array)) - { - pref->parmarray = !static_array; - pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED); - pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED); - pref->ref = ref; - qry->put_ref (ptr, *pref); - return true; - } + return compute_objsize_r (ptr, stmt, addr, ostype, pref, snlim, qry); - pref->set_max_size_range (); - pref->base0 = false; - pref->ref = ptr; - qry->put_ref (ptr, *pref); - return true; - } - - if (gimple_code (stmt) == GIMPLE_PHI) - { - pref->ref = ptr; - access_ref phi_ref = *pref; - if (!pref->get_ref (NULL, &phi_ref, ostype, &snlim, qry)) - return false; - *pref = phi_ref; - pref->ref = ptr; - qry->put_ref (ptr, *pref); - return true; - } + case SSA_NAME: + return handle_ssa_name (ptr, addr, ostype, pref, snlim, qry); - if (!is_gimple_assign (stmt)) - { - /* Clear BASE0 since the assigned pointer might point into - the middle of the object, set the maximum size range and, - if the SSA_NAME refers to a function argumnent, set - PREF->REF to it. */ - pref->base0 = false; - pref->set_max_size_range (); - pref->ref = ptr; - return true; - } - - tree_code code = gimple_assign_rhs_code (stmt); - - if (code == MAX_EXPR || code == MIN_EXPR) - { - if (!handle_min_max_size (ptr, ostype, pref, snlim, qry)) - return false; - - qry->put_ref (ptr, *pref); - return true; - } - - tree rhs = gimple_assign_rhs1 (stmt); - - if (code == ASSERT_EXPR) - { - rhs = TREE_OPERAND (rhs, 0); - return compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry); - } - - if (code == POINTER_PLUS_EXPR - && TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE) - { - /* Compute the size of the object first. */ - if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry)) - return false; - - offset_int orng[2]; - tree off = gimple_assign_rhs2 (stmt); - if (get_offset_range (off, stmt, orng, rvals)) - pref->add_offset (orng[0], orng[1]); - else - pref->add_max_offset (); - - qry->put_ref (ptr, *pref); - return true; - } - - if (code == ADDR_EXPR || code == SSA_NAME) - { - if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry)) - return false; - qry->put_ref (ptr, *pref); - return true; - } - - /* (This could also be an assignment from a nonlocal pointer.) Save - PTR to mention in diagnostics but otherwise treat it as a pointer - to an unknown object. */ - pref->ref = rhs; - pref->base0 = false; - pref->set_max_size_range (); - return true; + default: + break; } /* Assume all other expressions point into an unknown object @@ -2151,7 +2367,7 @@ compute_objsize (tree ptr, gimple *stmt, int ostype, access_ref *pref, pref->sizrng[0] = pref->sizrng[1] = -1; ssa_name_limit_t snlim; - if (!compute_objsize_r (ptr, stmt, ostype, pref, snlim, ptr_qry)) + if (!compute_objsize_r (ptr, stmt, false, ostype, pref, snlim, ptr_qry)) return NULL_TREE; offset_int maxsize = pref->size_remaining (); @@ -2176,13 +2392,13 @@ compute_objsize (tree ptr, gimple *stmt, int ostype, access_ref *pref, once callers transition to one of the two above. */ tree -compute_objsize (tree ptr, int ostype, tree *pdecl /* = NULL */, +compute_objsize (tree ptr, gimple *stmt, int ostype, tree *pdecl /* = NULL */, tree *poff /* = NULL */, range_query *rvals /* = NULL */) { /* Set the initial offsets to zero and size to negative to indicate none has been computed yet. */ access_ref ref; - tree size = compute_objsize (ptr, nullptr, ostype, &ref, rvals); + tree size = compute_objsize (ptr, stmt, ostype, &ref, rvals); if (!size || !ref.base0) return NULL_TREE; diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index fbea331..25101b7 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -61,12 +61,15 @@ class pointer_query; struct access_ref { /* Set the bounds of the reference. */ - access_ref (range_query *query = nullptr, tree = NULL_TREE, - gimple * = nullptr, bool = false); + access_ref (); /* Return the PHI node REF refers to or null if it doesn't. */ gphi *phi () const; + /* Merge the result for a pointer with *THIS. */ + bool merge_ref (vec<access_ref> *all_refs, tree, gimple *, int, bool, + ssa_name_limit_t &, pointer_query &); + /* Return the object to which REF refers. */ tree get_ref (vec<access_ref> *, access_ref * = nullptr, int = 1, ssa_name_limit_t * = nullptr, pointer_query * = nullptr) const; @@ -119,7 +122,10 @@ struct access_ref /* Issue an informational message describing the target of an access with the given mode. */ - void inform_access (access_mode) const; + void inform_access (access_mode, int = 1) const; + + /* Dump *THIS to a file. */ + void dump (FILE *) const; /* Reference to the accessed object(s). */ tree ref; @@ -129,11 +135,6 @@ struct access_ref offset_int sizrng[2]; /* The minimum and maximum offset computed. */ offset_int offmax[2]; - /* Range of the bound of the access: denotes that the access - is at least BNDRNG[0] bytes but no more than BNDRNG[1]. - For string functions the size of the actual access is - further constrained by the length of the string. */ - offset_int bndrng[2]; /* Used to fold integer expressions when called from front ends. */ tree (*eval)(tree); @@ -206,23 +207,18 @@ struct access_data { /* Set the access to at most MAXWRITE and MAXREAD bytes, and at least 1 when MINWRITE or MINREAD, respectively, is set. */ - access_data (range_query *query, gimple *stmt, access_mode mode, - tree maxwrite = NULL_TREE, bool minwrite = false, - tree maxread = NULL_TREE, bool minread = false) - : stmt (stmt), call (), - dst (query, maxwrite, stmt, minwrite), - src (query, maxread, stmt, minread), - mode (mode) { } + access_data (range_query *, gimple *, access_mode, + tree = NULL_TREE, bool = false, + tree = NULL_TREE, bool = false); /* Set the access to at most MAXWRITE and MAXREAD bytes, and at least 1 when MINWRITE or MINREAD, respectively, is set. */ - access_data (range_query *query, tree expr, access_mode mode, - tree maxwrite = NULL_TREE, bool minwrite = false, - tree maxread = NULL_TREE, bool minread = false) - : stmt (), call (expr), - dst (query, maxwrite, nullptr, minwrite), - src (query, maxread, nullptr, minread), - mode (mode) { } + access_data (range_query *, tree, access_mode, + tree = NULL_TREE, bool = false, + tree = NULL_TREE, bool = false); + + /* Constructor helper. */ + static void set_bound (offset_int[2], tree, bool, range_query *, gimple *); /* Access statement. */ gimple *stmt; @@ -230,9 +226,19 @@ struct access_data tree call; /* Destination and source of the access. */ access_ref dst, src; + + /* Range of the bound of the access: denotes that the access is at + least XXX_BNDRNG[0] bytes but no more than XXX_BNDRNG[1]. For + string functions the size of the actual access is further + constrained by the length of the string. */ + offset_int dst_bndrng[2]; + offset_int src_bndrng[2]; + /* Read-only for functions like memcmp or strlen, write-only for memset, read-write for memcpy or strcat. */ access_mode mode; + /* The object size type. */ + int ostype; }; enum size_range_flags @@ -263,8 +269,13 @@ inline tree compute_objsize (tree ptr, int ostype, access_ref *pref) } /* Legacy/transitional API. Should not be used in new code. */ -extern tree compute_objsize (tree, int, tree * = nullptr, tree * = nullptr, - range_query * = nullptr); +extern tree compute_objsize (tree, gimple *, int, tree * = nullptr, + tree * = nullptr, range_query * = nullptr); +inline tree compute_objsize (tree ptr, int ostype, tree *pdecl = nullptr, + tree *poff = nullptr, range_query *rvals = nullptr) +{ + return compute_objsize (ptr, nullptr, ostype, pdecl, poff, rvals); +} /* Return the field at the constant offset. */ extern tree field_at_offset (tree, tree, HOST_WIDE_INT, diff --git a/gcc/poly-int.h b/gcc/poly-int.h index 94e7b70..60a38c3 100644 --- a/gcc/poly-int.h +++ b/gcc/poly-int.h @@ -2717,7 +2717,7 @@ gt_pch_nx (poly_int_pod<N, C> *) template<unsigned int N, typename C> void -gt_pch_nx (poly_int_pod<N, C> *, void (*) (void *, void *), void *) +gt_pch_nx (poly_int_pod<N, C> *, void (*) (void *, void *, void *), void *) { } diff --git a/gcc/stringpool.c b/gcc/stringpool.c index 2f21466..cf7f87d 100644 --- a/gcc/stringpool.c +++ b/gcc/stringpool.c @@ -225,7 +225,7 @@ gt_pch_nx (unsigned char& x ATTRIBUTE_UNUSED) void gt_pch_nx (unsigned char *x, gt_pointer_operator op, void *cookie) { - op (x, cookie); + op (x, NULL, cookie); } /* Handle saving and restoring the string pool for PCH. */ diff --git a/gcc/symtab.c b/gcc/symtab.c index 94b4e47..05e8239 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -2257,7 +2257,7 @@ symtab_node::equal_address_to (symtab_node *s2, bool memory_accessed) if (rs1->alias || rs2->alias) return -1; - /* If we have a non-interposale definition of at least one of the symbols + /* If we have a non-interposable definition of at least one of the symbols and the other symbol is different, we know other unit cannot interpose it to the first symbol; all aliases of the definition needs to be present in the current unit. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e02c0c8..2da36cf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,104 @@ +2021-12-12 Antoni Boucher <bouanto@zoho.com> + + PR target/95415 + * jit.dg/all-non-failing-tests.h: Add test-tls.c. + * jit.dg/test-tls.c: New test. + +2021-12-11 Antoni Boucher <bouanto@zoho.com> + + PR target/96066 + PR target/96067 + * jit.dg/all-non-failing-tests.h: Add test-builtin-types.c. + * jit.dg/test-builtin-types.c + * jit.dg/test-error-bad-assignment.c + * jit.dg/test-fuzzer.c: Add fuzzing for type qualifiers. + +2021-12-11 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103606 + * gfortran.dg/pr103606.f90: New test. + +2021-12-11 Jason Merrill <jason@redhat.com> + + PR c++/103534 + * g++.dg/warn/Wstringop-overflow-8.C: New test. + +2021-12-10 David Malcolm <dmalcolm@redhat.com> + + PR jit/103562 + * jit.dg/all-non-failing-tests.h: Add comment about... + * jit.dg/test-pr103562.c: New test. + +2021-12-10 Marek Polacek <polacek@redhat.com> + + * g++.dg/cpp23/auto-fncast10.C: New test. + +2021-12-10 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103418 + * gfortran.dg/move_alloc_8.f90: Adjust error messages. + * gfortran.dg/pointer_intent_9.f90: New test. + +2021-12-10 Roger Sayle <roger@nextmovesoftware.com> + + PR ipa/103601 + * gcc.dg/ipa/pr103601.c: New test case. + +2021-12-10 Joel Hutton <joel.hutton@arm.com> + + * gcc.target/aarch64/pr103523.c: New test. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + PR tree-optimization/103215 + * gcc.dg/Wstringop-overflow-58.c: Adjust and xfail expected warnings. + * gcc.dg/Wstringop-overflow-59.c: Same. + * gcc.dg/warn-strnlen-no-nul.c: Same. + * gcc.dg/Warray-bounds-91.c: New test. + * gcc.dg/Warray-bounds-92.c: New test. + * gcc.dg/Wstringop-overflow-85.c: New test. + * gcc.dg/Wstringop-overflow-87.c: New test. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + PR middle-end/101751 + * gcc.dg/Wstringop-overflow-86.c: New test. + +2021-12-09 Martin Sebor <msebor@redhat.com> + + PR middle-end/103143 + * gcc.dg/Wstringop-overflow-83.c: New test. + +2021-12-09 Marek Polacek <polacek@redhat.com> + + PR c++/103401 + * g++.dg/cpp1y/lambda-generic-85713-2.C: Add dg-error. + * g++.dg/cpp1y/pr60054.C: Adjust dg-error. + * g++.dg/cpp1y/pr60332.C: Likewise. + * g++.dg/cpp2a/concepts-pr84979-2.C: Likewise. + * g++.dg/cpp2a/concepts-pr84979-3.C: Likewise. + * g++.dg/cpp2a/concepts-pr84979.C: Likewise. + * g++.dg/cpp23/auto-fncast7.C: New test. + * g++.dg/cpp23/auto-fncast8.C: New test. + * g++.dg/cpp23/auto-fncast9.C: New test. + +2021-12-09 Alexandre Oliva <oliva@adacore.com> + + PR target/103097 + * gcc.target/i386/pr103097.c: New. + +2021-12-09 Alexandre Oliva <oliva@adacore.com> + + PR target/103302 + * gcc.target/riscv/pr103302.c: New. + +2021-12-09 Alexandre Oliva <oliva@adacore.com> + + PR tree-optimization/103024 + PR middle-end/103530 + * g++.dg/pr103024.C: New. + * g++.dg/pr103530.C: New. + 2021-12-08 Harald Anlauf <anlauf@gmx.de> PR fortran/103609 diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C index 8fb8dfd..dbc9e8c 100644 --- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C +++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-85713-2.C @@ -2,6 +2,6 @@ // { dg-do compile { target c++14 } } auto l4 = [](auto v, auto (&array (int)) [5]) -> int { return v + array[0]; }; -auto l5 = [](auto v, auto (&array (auto)) [5]) -> int { return v + array[0]; }; +auto l5 = [](auto v, auto (&array (auto)) [5]) -> int { return v + array[0]; }; // { dg-error ".auto. parameter not permitted in this context" } auto l6 = [](auto v, auto (&array (int int)) [5]) -> int { return v + array[0]; }; // { dg-error "two or more data types" } auto l7 = [](auto v, auto (&array (int auto)) [5]) -> int { return v + array[0]; }; // { dg-error "two or more data types" } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60054.C b/gcc/testsuite/g++.dg/cpp1y/pr60054.C index f51120f..0d4925a 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr60054.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr60054.C @@ -6,6 +6,6 @@ template<typename T> decltype(T{}) fooB(T); void bar() { - fooA((auto*)0); // { dg-error "invalid use" } - fooB((auto*)0); // { dg-error "invalid use" } + fooA((auto*)0); // { dg-error "expected" } + fooB((auto*)0); // { dg-error "expected" } } diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60332.C b/gcc/testsuite/g++.dg/cpp1y/pr60332.C index e75ab85..f3a7980 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr60332.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr60332.C @@ -3,4 +3,5 @@ void foo(); -auto f = (auto(*)())(&foo); // { dg-error "invalid" } +auto f = (auto(*)())(&foo); // { dg-error "expected" } +// { dg-error "only available" "" { target c++20_down } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C new file mode 100644 index 0000000..29c779b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast10.C @@ -0,0 +1,18 @@ +// { dg-do compile { target c++23 } } + +struct S { + int i1 : auto(12); + int i2 : auto{12}; + static constexpr auto x = auto(12); + static constexpr auto y = auto{12}; +}; + +struct R { + int i; +}; + +static constexpr R r1 = { auto(23) }; +static constexpr R r2 = { auto{23} }; +enum E { X = auto(12), Y = auto{1u} }; +static_assert (auto(true)); +static_assert (auto{true}); diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast7.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast7.C new file mode 100644 index 0000000..763164f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast7.C @@ -0,0 +1,9 @@ +// PR c++/103401 +// { dg-do compile { target c++23 } } + +void f(decltype(auto(0))) { } + +int main() +{ + f<int,int>(0); // { dg-error "no matching function" } +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast8.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast8.C new file mode 100644 index 0000000..9fb7b9c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast8.C @@ -0,0 +1,42 @@ +// PR c++/103401 +// { dg-do compile { target c++23 } } + +void f1 (decltype(auto(0))); +void f2 (decltype(auto{0})); +void f3 (int = auto(42)); +void f4 (int = auto{42}); +void f5 (decltype(auto(0)) = auto(42)); +void f6 (auto (x)); +void f7 (int[auto(10)]); +void f8 (int[auto{10}]); +void f9 (auto[auto{10}]); +void f10 (auto); +void f11 (int x, decltype(x) y); +void f12 (int[sizeof(auto{10})]); +void f13 (int[sizeof(auto(10))]); +void f14 (int[__extension__ alignof(auto{10})]); +void f15 (int[__extension__ alignof(auto(10))]); + +void +g () +{ + int a[2]; + f1 (1); + f2 (1); + f3 (); + f3 (1); + f4 (); + f4 (1); + f5 (); + f5 (1); + f6 ('a'); + f7 (&a[0]); + f8 (&a[0]); + f9 (&a[0]); + f10 (1); + f11 (1, 2); + f12 (&a[0]); + f13 (&a[0]); + f14 (&a[0]); + f15 (&a[0]); +} diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast9.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast9.C new file mode 100644 index 0000000..12a0dce --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast9.C @@ -0,0 +1,17 @@ +// PR c++/103401 +// { dg-do compile { target c++23 } } + +void f1(decltype(new auto{0})); +void f2(decltype(new int{0})); + +void +g () +{ + int i; + void f3(decltype(new auto{0})); + void f4(decltype(new int{0})); + f1 (&i); + f2 (&i); + f3 (&i); + f4 (&i); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C index 025bbf3..75f8e40 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C @@ -4,9 +4,9 @@ template <typename T> void foo1(T& t) { typename T::template C<void> tcv = t; - typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } } - T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" } - (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted|unable" } + typename T::template C<auto> u = tcv; // { dg-error "" "" { target c++20 } } + T::template C<auto>::f (tcv, u); // { dg-error "" } + (typename T::template D<auto> (t)); // { dg-error "" } // { dg-warning "only available" "" { target c++17_down } .-1 } } @@ -23,9 +23,9 @@ struct T1 { template <typename T> void foo2(T& t) { typename T::template C<void> tcv = t; - typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } } - T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" } - T::template D<auto> (t); // { dg-error "invalid|not permitted" } + typename T::template C<auto> u = tcv; // { dg-error "" "" { target c++20 } } + T::template C<auto>::f (tcv, u); // { dg-error "" } + T::template D<auto> (t); // { dg-error "" } } struct T2 { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C index 80a3884..1c1a41c 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C @@ -8,9 +8,9 @@ template <typename T> void foo1(T& t) { typename T::template C<void> tcv = t; - typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } } - T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" } - (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted|no class" } + typename T::template C<auto> u = tcv; // { dg-error "" "" { target c++20 } } + T::template C<auto>::f (tcv, u); // { dg-error "" } + (typename T::template D<auto> (t)); // { dg-error "" } // { dg-warning "only available" "" { target c++17_down } .-1 } } @@ -27,9 +27,9 @@ struct T1 { template <typename T> void foo2(T& t) { typename T::template C<void> tcv = t; - typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } } - T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" } - T::template D<auto> (t); // { dg-error "yields a type|not permitted" } + typename T::template C<auto> u = tcv; // { dg-error "" "" { target c++20 } } + T::template C<auto>::f (tcv, u); // { dg-error "" } + T::template D<auto> (t); // { dg-error "" } } struct T2 { diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C index 81555eb..a836015 100644 --- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C @@ -5,5 +5,5 @@ template<typename> void foo() {} void bar() { - foo<auto>(); // { dg-error "not permitted|invalid|no matching function" } + foo<auto>(); // { dg-error "" } } diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-8.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-8.C new file mode 100644 index 0000000..d0ef5e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-8.C @@ -0,0 +1,10 @@ +// PR c++/103534 +// { dg-additional-options "-O -Wall" } + +#include <string> + +std::string foo(std::string x) +{ + // This used to get a bogus -Wstringop-overflow warning. + return std::string("1234567890123456") + x; +} diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-91.c b/gcc/testsuite/gcc.dg/Warray-bounds-91.c new file mode 100644 index 0000000..1c81091 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-91.c @@ -0,0 +1,145 @@ +/* PR middle-end/103215 - bogus -Warray-bounds with two pointers with + different offsets each + Test for accesses into the same array through pointers with different + offsets each. + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +#define NOIPA __attribute__ ((noipa)) + +#define A(p, off) ((p)[off] = __COUNTER__) + +extern int a4[4]; + + +NOIPA void p0_p1 (int i) +{ + int *p0 = a4 + 0; + int *p1 = a4 + 1; + int *q = i ? p0 : p1; + A (q, -2); // { dg-warning "-Warray-bounds" } + A (q, -1); A (q, 0); A (q, 1); A (q, 2); + /* Since q points to a4 and -1 is a valid subscript, +3 must be invalid. + But the warning for each subscript is independent of prior subscripts + into the same object. That should be improved. */ + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" } +} + +NOIPA void p1_p0 (int i) +{ + int *p1 = a4 + 1; + int *p0 = a4 + 0; + int *q = i ? p0 : p1; + A (q, -2); // { dg-warning "-Warray-bounds" } + A (q, -1); A (q, 0); A (q, 1); A (q, 2); + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void p1_p2 (int i) +{ + int *p1 = a4 + 1; + int *p2 = a4 + 2; + int *q = i ? p1 : p2; + A (q, -3); // { dg-warning "-Warray-bounds" } + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" } +} + +NOIPA void p2_p1 (int i) +{ + int *p2 = a4 + 2; + int *p1 = a4 + 1; + int *q = i ? p1 : p2; + A (q, -3); // { dg-warning "-Warray-bounds" } + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void p1_p3 (int i) +{ + int *p1 = a4 + 1; + int *p3 = a4 + 3; + int *q = i ? p1 : p3; + A (q, -4); // { dg-warning "-Warray-bounds" } + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" } +} + +NOIPA void p3_p1 (int i) +{ + int *p3 = a4 + 3; + int *p1 = a4 + 1; + int *q = i ? p1 : p3; + A (q, -4); // { dg-warning "-Warray-bounds" } + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void p1_p4 (int i) +{ + int *p1 = a4 + 1; + int *p4 = a4 + 4; + int *q = i ? p1 : p4; + A (q, -5); // { dg-warning "-Warray-bounds" } + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" } +} + +NOIPA void p4_p1 (int i) +{ + int *p4 = a4 + 4; + int *p1 = a4 + 1; + int *q = i ? p1 : p4; + A (q, -5); // { dg-warning "-Warray-bounds" } + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void p0_p1_p2 (int i) +{ + int *p0 = a4 + 0; + int *p1 = a4 + 1; + int *p2 = a4 + 2; + int *q = i < 0 ? p1 : 0 < i ? p2 : p0; + A (q, -3); // { dg-warning "-Warray-bounds" } + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void p0_p1_p2_p3_p4 (int i) +{ + int *p0 = a4 + 0; + int *p1 = a4 + 1; + int *p2 = a4 + 2; + int *p3 = a4 + 3; + int *p4 = a4 + 4; + int *q = i < -1 ? p1 : i < 0 ? p2 : 1 < i ? p4 : 0 < i ? p3 : p0; + A (q, -5); // { dg-warning "-Warray-bounds" } + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" } +} diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-92.c b/gcc/testsuite/gcc.dg/Warray-bounds-92.c new file mode 100644 index 0000000..8c8f5f7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-92.c @@ -0,0 +1,149 @@ +/* PR middle-end/103215 - bogus -Warray-bounds with two pointers with + different offsets each + Test for accesses into distinct arrays through pointers with different + offsets each. + + If/when -Warray-bounds is enhanced to issue "maybe" kinds of warnings + some of the accesses here will trigger those and will need updating. + + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +#define NOIPA __attribute__ ((noipa)) + +#define A(p, off) ((p)[off] = __COUNTER__) + +extern int a4[4], a8[8]; + + +NOIPA void a4_p1_a8_p3 (int i) +{ + int *a4_p1 = a4 + 1; + int *a8_p3 = a8 + 3; + int *q = i ? a4_p1 : a8_p3; + A (q, -4); // { dg-warning "-Warray-bounds" } + /* Because -3 is a valid offset into a8 but not a4, q must point + to the former and so subscripts between -3 and +4 refer to its + elements. */ + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + A (q, 1); A (q, 2); A (q, 3); A (q, 4); + A (q, 5); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + /* Both of the following are definitely out of bounds but the first isn't + diagnosed because the code conservatively merges the offsets into A4 + and A8. */ + A (q, 7); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void a4_p1_a8_p5 (int i) +{ + int *a4_p1 = a4 + 1; + int *a8_p5 = a8 + 5; + int *q = i ? a4_p1 : a8_p5; + A (q, -6); // { dg-warning "-Warray-bounds" } + /* Similarly to the above, because -5 is a valid offset into a8 but + not a4, q must point to the former and so subscripts between -5 + and +2 refer to its elements. */ + A (q, -5); A (q, -4); A (q, -3); A (q, -2); + A (q, -1); A (q, 0); A (q, 1); A (q, 2); + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void a4_p1_a8_p7 (int i) +{ + int *a4_p1 = a4 + 1; + int *a8_p7 = a8 + 7; + int *q = i ? a4_p1 : a8_p7; + A (q, -8); // { dg-warning "-Warray-bounds" } + A (q, -7); A (q, -6); A (q, -5); A (q, -4); + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + /* Since -7 is valid, q must point to a8 and the last valid subscript + must be 0. */ + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void mp_1_a4_p1_a8_p7 (int i, int j) +{ + int *a4_p1 = a4 + 1; + int *a8_p7 = a8 + 7; + int *p = i ? a4_p1 : a8_p7; + int *q = j ? p + 1 : p - 1; + + A (q, -9); // { dg-warning "-Warray-bounds" } + + /* q points either to a8 + [6, 8] or a4 + [0, 2]. */ + A (q, -8); A (q, -7); A (q, -6); A (q, -5); + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + + /* Since all the above are valid, q must point to a8 + 8. But as + mentioned above, the warning for each subscript is independent + of prior subscripts into the same object so the access below + aren't diagnosed. */ + A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 8); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void mp1_a4_p1_a8_p5 (int i, int j) +{ + int *a4_p1 = a4 + 1; + int *a8_p5 = a8 + 5; + int *p = i ? a4_p1 : a8_p5; + + int *q = j ? p + 1 : p - 1; + + // q is assumed to point to a8 + 6 + A (q, -7); // { dg-warning "-Warray-bounds" } + A (q, -6); A (q, -5); A (q, -4); A (q, -3); + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + /* Even though the above accesses rule it out, q is now assumed + to point to either a4 + [0, 2] or a8 + [4, 5]. */ + A (q, 2); + /* q is now assumed to point tp a4. Given that, only the first store + is valid. */ + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 5); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 6); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 8); // { dg-warning "-Warray-bounds" } +} + + +NOIPA void mp1_a4_p1_a8_p4 (int i, int j) +{ + int *a4_p1 = a4 + 1; + int *a8_p4 = a8 + 4; + int *p = i ? a4_p1 : a8_p4; + + int *q = j ? p + 1 : p - 1; + + // q is assumed to point to a8 + 5 + A (q, -6); // { dg-warning "-Warray-bounds" } + A (q, -5); + A (q, -4); + A (q, -3); + A (q, -2); + A (q, -1); + A (q, 0); + A (q, 1); + A (q, 2); + /* Even though the above accesses rule it out, q is now assumed + to point tp a4. Given that, only the first store is valid. */ + A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 5); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 6); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } } + A (q, 8); // { dg-warning "-Warray-bounds" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c index b81186c..e0a4078 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c @@ -182,8 +182,8 @@ void memset_decl_2_off (void) int i2 = SR (2, INT_MAX); { - char a5[5]; // { dg-warning "at offset [1, 5] into destination object 'a5' - char a7[7]; // { dg-warning "at offset [2, 7] into destination object 'a7' + char a5[5]; // { dg-message "at offset \\\[1, 5] into destination object 'a5'" "note" } + char a7[7]; // { dg-message "at offset \\\[2, 7] into destination object 'a7'" "note" } char *p5_p1 = a5 + i1; char *p7_p2 = a7 + i2; char *p5_7 = cond1 ? p5_p1 : p7_p2; @@ -193,7 +193,11 @@ void memset_decl_2_off (void) memset (p5_7, 0, 3); memset (p5_7, 0, 4); memset (p5_7, 0, 5); - memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " } + /* The warning code conservatively "merges" both the sizes and the offsets + into A5 and A7 and so only the second store below is diagnosed but not + the first. See PR 103215. The logic needs to be tightened up. */ + memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " "pr??????" { xfail *-*-* } } + memset (p5_7, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6 " } } int i3 = SR (3, INT_MAX); @@ -208,7 +212,8 @@ void memset_decl_2_off (void) // { dg-message "at offset \\\[4, 9] into destination object 'a9'" "note" { target *-*-* } .-1 } // { dg-message "at offset \\\[3, 9] into destination object 'a9'" "note" { target *-*-* } .-2 } // { dg-message "at offset \\\[2, 9] into destination object 'a9'" "note" { target *-*-* } .-3 } - // { dg-message ": destination object 'a9'" "note" { target *-*-* } .-4 } + // { dg-message "at offset \\\[1, 9] into destination object 'a9'" "note" { target *-*-* } .-4 } + // { dg-message ": destination object 'a9'" "pr??????" { xfail *-*-* } .-5 } char *p5_p2 = a5 + i2; // 3 bytes left char *p9_p3 = a9 + i3; // 6 bytes left char *p = @@ -220,7 +225,8 @@ void memset_decl_2_off (void) memset (q, 0, 3); memset (q, 0, 4); memset (q, 0, 5); - memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" } + memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" "pr??????" { xfail *-*-* } } + memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" } --q; // [3 - 6] bytes left memset (q, 0, 1); @@ -229,7 +235,8 @@ void memset_decl_2_off (void) memset (q, 0, 4); memset (q, 0, 5); memset (q, 0, 6); - memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" } + memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" "pr??????" { xfail *-*-* } } + memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" } --q; // [4 - 7] bytes left memset (q, 0, 1); @@ -239,7 +246,8 @@ void memset_decl_2_off (void) memset (q, 0, 5); memset (q, 0, 6); memset (q, 0, 7); - memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" } + memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" "pr??????" { xfail *-*-* } } + memset (q, 0, 9); // { dg-warning "memset' writing 9 bytes into a region of size 8" } int m1_x = SR (-1, INT_MAX); int m2_x = SR (-2, INT_MAX); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c index c45a92d..b6265e3 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c @@ -200,7 +200,11 @@ void memset_malloc_2_off (void) memset (p5_7, 0, 3); memset (p5_7, 0, 4); memset (p5_7, 0, 5); - memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " } + /* The warning code conservatively "merges" both the sizes and the offsets + into A5 and A7 and so only the second store below is diagnosed but not + the first. See PR 103215. The logic needs to be tightened up. */ + memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " "pr??????" { xfail *-*-* } } + memset (p5_7, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6 " } } int i3 = SR (3, INT_MAX); @@ -215,7 +219,8 @@ void memset_malloc_2_off (void) // { dg-message "at offset \\\[4, 9] into destination object 'a9'" "note" { target *-*-* } .-1 } // { dg-message "at offset \\\[3, 9] into destination object 'a9'" "note" { target *-*-* } .-2 } // { dg-message "at offset \\\[2, 9] into destination object 'a9'" "note" { target *-*-* } .-3 } - // { dg-message ": destination object 'a9'" "note" { target *-*-* } .-4 } + // { dg-message "at offset \\\[1, 9] into destination object 'a9'" "note" { target *-*-* } .-4 } + // { dg-message ": destination object 'a9'" "pr??????" { xfail *-*-* } .-5 } char *p5_p2 = a5 + i2; // 3 bytes left char *p9_p3 = a9 + i3; // 6 bytes left char *p = @@ -227,7 +232,8 @@ void memset_malloc_2_off (void) memset (q, 0, 3); memset (q, 0, 4); memset (q, 0, 5); - memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" } + memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" "pr??????" { xfail *-*-* } } + memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" } --q; // [3 - 6] bytes left memset (q, 0, 1); @@ -236,7 +242,8 @@ void memset_malloc_2_off (void) memset (q, 0, 4); memset (q, 0, 5); memset (q, 0, 6); - memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" } + memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" "pr??????" { xfail *-*-* } } + memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" } --q; // [4 - 7] bytes left memset (q, 0, 1); @@ -246,7 +253,8 @@ void memset_malloc_2_off (void) memset (q, 0, 5); memset (q, 0, 6); memset (q, 0, 7); - memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" } + memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" "pr??????" { xfail *-*-* } } + memset (q, 0, 9); // { dg-warning "memset' writing 9 bytes into a region of size 8" } int m1_x = SR (-1, INT_MAX); int m2_x = SR (-2, INT_MAX); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-83.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-83.c new file mode 100644 index 0000000..6928ee4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-83.c @@ -0,0 +1,19 @@ +/* PR middle-end/103143 - ICE due to infinite recursion in pointer-query.cc + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +void foo (size_t x) +{ + struct T { char buf[64]; char buf2[64]; } t; + char *p = &t.buf[8]; + char *r = t.buf2; + size_t i; + + for (i = 0; i < x; i++) + { + r = __builtin_mempcpy (r, p, i); + p = r + 1; + } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-85.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-85.c new file mode 100644 index 0000000..ac61e0a --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-85.c @@ -0,0 +1,153 @@ +/* PR middle-end/103215 - bogus -Wstringop-overflow with two pointers with + different offsets each + Test for accesses into distinct arrays through pointers with different + offsets each. + + If/when -Wstringop-overflow is enhanced to issue "maybe" kinds of + warnings some of the accesses here will trigger those and will need + updating. + + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +#define NOIPA __attribute__ ((noipa)) + +void sink (int[1]); +#define A(p, off) sink (p + off) + +extern int a4[4], a8[8]; + + + + +NOIPA void a4_p1_a8_p3 (int i) +{ + int *a4_p1 = a4 + 1; + int *a8_p3 = a8 + 3; + int *q = i ? a4_p1 : a8_p3; + A (q, -4); // { dg-warning "-Wstringop-overflow" } + /* Because -3 is a valid offset into a8 but not a4, q must point + to the former and so subscripts between -3 and +4 refer to its + elements. */ + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + A (q, 1); A (q, 2); A (q, 3); A (q, 4); + A (q, 5); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + /* Both of the following are definitely out of bounds but the first isn't + diagnosed because the code conservatively merges the offsets into A4 + and A8. */ + A (q, 7); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void a4_p1_a8_p5 (int i) +{ + int *a4_p1 = a4 + 1; + int *a8_p5 = a8 + 5; + int *q = i ? a4_p1 : a8_p5; + A (q, -6); // { dg-warning "-Wstringop-overflow" } + /* Similarly to the above, because -5 is a valid offset into a8 but + not a4, q must point to the former and so subscripts between -5 + and +2 refer to its elements. */ + A (q, -5); A (q, -4); A (q, -3); A (q, -2); + A (q, -1); A (q, 0); A (q, 1); A (q, 2); + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void a4_p1_a8_p7 (int i) +{ + int *a4_p1 = a4 + 1; + int *a8_p7 = a8 + 7; + int *q = i ? a4_p1 : a8_p7; + A (q, -8); // { dg-warning "-Wstringop-overflow" } + A (q, -7); A (q, -6); A (q, -5); A (q, -4); + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + /* Since -7 is valid, q must point to a8 and the last valid subscript + must be 0. */ + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void mp_1_a4_p1_a8_p7 (int i, int j) +{ + int *a4_p1 = a4 + 1; + int *a8_p7 = a8 + 7; + int *p = i ? a4_p1 : a8_p7; + int *q = j ? p + 1 : p - 1; + + A (q, -9); // { dg-warning "-Wstringop-overflow" } + + /* q points either to a8 + [6, 8] or a4 + [0, 2]. */ + A (q, -8); A (q, -7); A (q, -6); A (q, -5); + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + + /* Since all the above are valid, q must point to a8 + 8. But as + mentioned above, the warning for each subscript is independent + of prior subscripts into the same object so the access below + aren't diagnosed. */ + A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 8); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void mp1_a4_p1_a8_p5 (int i, int j) +{ + int *a4_p1 = a4 + 1; + int *a8_p5 = a8 + 5; + int *p = i ? a4_p1 : a8_p5; + + int *q = j ? p + 1 : p - 1; + + // q is assumed to point to a8 + 6 + A (q, -7); // { dg-warning "-Wstringop-overflow" } + A (q, -6); A (q, -5); A (q, -4); A (q, -3); + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + /* Even though the above accesses rule it out, q is now assumed + to point to either a4 + [0, 2] or a8 + [4, 5]. */ + A (q, 2); + /* q is now assumed to point tp a4. Given that, only the first store + is valid. */ + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 5); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 6); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 8); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void mp1_a4_p1_a8_p4 (int i, int j) +{ + int *a4_p1 = a4 + 1; + int *a8_p4 = a8 + 4; + int *p = i ? a4_p1 : a8_p4; + + int *q = j ? p + 1 : p - 1; + + // q is assumed to point to a8 + 5 + A (q, -6); // { dg-warning "-Wstringop-overflow" } + A (q, -5); + A (q, -4); + A (q, -3); + A (q, -2); + A (q, -1); + A (q, 0); + A (q, 1); + A (q, 2); + /* Even though the above accesses rule it out, q is now assumed + to point tp a4. Given that, only the first store is valid. */ + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 5); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 6); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 7); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 8); // { dg-warning "-Wstringop-overflow" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-86.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-86.c new file mode 100644 index 0000000..345abe4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-86.c @@ -0,0 +1,63 @@ +/* PR middle-end/101751 - attribute access none with void pointer expects + nonzero size + { dg-do compile } + { dg-options "-Wall" } */ + +__attribute__ ((access (none, 1))) void +fvp_m1 (const void*); + +void nowarn_m1 (void) +{ + /* Verify these don't trigger a warning for calls to a function + declared with attribute access none. */ + fvp_m1 ((void*)-1); // { dg-bogus "-Wstringop-" } + fvp_m1 ((void*)1); // { dg-bogus "-Wstringop-" } +} + + +__attribute__ ((access (none, 1))) void +fvp_none (void*); + +void nowarn_c_cp1 (void) +{ + char c; + fvp_none (&c); + fvp_none (&c + 1); // { dg-bogus "-Wstringop-" } +} + +void nowarn_f_fp1 (void) +{ + fvp_none ((char*)&nowarn_f_fp1); + fvp_none ((char*)&nowarn_f_fp1 + 1); +} + +void nowarn_sp1_sp_4 (void) +{ + fvp_none ("" + 1); // { dg-bogus "-Wstringop-" } + fvp_none ("123" + 4); // { dg-bogus "-Wstringop-" } +} + + +__attribute__ ((access (none, 1))) void +wfvp_none (void*); // { dg-message "in a call to function 'wfvp_none' declared with attribute 'access \\\(none, 1\\\)'" } + +void warn_cm1_p1 (void) +{ + char c; + /* With optimization both of the following are diagnosed by -Warray-bounds. + The second also without optimization by -Wstringop-overread. They + should both be diagnosed by the same warning even without optimization. */ + wfvp_none (&c - 1); // { dg-warning "" "pr??????" { xfail *-*-* } } + wfvp_none (&c + 2); // { dg-warning "" } +} + +void warn_fp2 (void) +{ + void *p = (char*)&warn_fp2 + sizeof warn_fp2; + fvp_none (p); // { dg-warning "" "pr??????" { xfail *-*-* } } +} + +void warn_sp2 (void) +{ + wfvp_none ("" + 2); // { dg-warning "" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-87.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-87.c new file mode 100644 index 0000000..bc12192 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-87.c @@ -0,0 +1,147 @@ +/* PR middle-end/103215 - bogus -Warray-bounds with two pointers with + different offsets each + Test for accesses by a user-defined function into the same array + through pointers with different offsets each. See Warray-bounds-91.c + for the corresponding test exercising -Warray-bounds for direct accesses. + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +#define NOIPA __attribute__ ((noipa)) + +void sink (int[1]); +#define A(p, off) sink (p + off) + +extern int a4[4]; + + +NOIPA void p0_p1 (int i) +{ + int *p0 = a4 + 0; + int *p1 = a4 + 1; + int *q = i ? p0 : p1; + A (q, -2); // { dg-warning "-Wstringop-overflow" } + A (q, -1); A (q, 0); A (q, 1); A (q, 2); + /* Since q points to a4 and -1 is a valid subscript, +3 must be invalid. + But the warning for each subscript is independent of prior subscripts + into the same object. That should be improved. */ + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" } +} + +NOIPA void p1_p0 (int i) +{ + int *p1 = a4 + 1; + int *p0 = a4 + 0; + int *q = i ? p0 : p1; + A (q, -2); // { dg-warning "-Wstringop-overflow" } + A (q, -1); A (q, 0); A (q, 1); A (q, 2); + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void p1_p2 (int i) +{ + int *p1 = a4 + 1; + int *p2 = a4 + 2; + int *q = i ? p1 : p2; + A (q, -3); // { dg-warning "-Wstringop-overflow" } + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" } +} + +NOIPA void p2_p1 (int i) +{ + int *p2 = a4 + 2; + int *p1 = a4 + 1; + int *q = i ? p1 : p2; + A (q, -3); // { dg-warning "-Wstringop-overflow" } + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void p1_p3 (int i) +{ + int *p1 = a4 + 1; + int *p3 = a4 + 3; + int *q = i ? p1 : p3; + A (q, -4); // { dg-warning "-Wstringop-overflow" } + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" } +} + +NOIPA void p3_p1 (int i) +{ + int *p3 = a4 + 3; + int *p1 = a4 + 1; + int *q = i ? p1 : p3; + A (q, -4); // { dg-warning "-Wstringop-overflow" } + A (q, -3); A (q, -2); A (q, -1); A (q, 0); + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void p1_p4 (int i) +{ + int *p1 = a4 + 1; + int *p4 = a4 + 4; + int *q = i ? p1 : p4; + A (q, -5); // { dg-warning "-Wstringop-overflow" } + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" } +} + +NOIPA void p4_p1 (int i) +{ + int *p4 = a4 + 4; + int *p1 = a4 + 1; + int *q = i ? p1 : p4; + A (q, -5); // { dg-warning "-Wstringop-overflow" } + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void p0_p1_p2 (int i) +{ + int *p0 = a4 + 0; + int *p1 = a4 + 1; + int *p2 = a4 + 2; + int *q = i < 0 ? p1 : 0 < i ? p2 : p0; + A (q, -3); // { dg-warning "-Wstringop-overflow" } + A (q, -2); A (q, -1); A (q, 0); A (q, 1); + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" } +} + + +NOIPA void p0_p1_p2_p3_p4 (int i) +{ + int *p0 = a4 + 0; + int *p1 = a4 + 1; + int *p2 = a4 + 2; + int *p3 = a4 + 3; + int *p4 = a4 + 4; + int *q = i < -1 ? p1 : i < 0 ? p2 : 1 < i ? p4 : 0 < i ? p3 : p0; + A (q, -5); // { dg-warning "-Wstringop-overflow" } + A (q, -4); A (q, -3); A (q, -2); A (q, -1); + A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } } + A (q, 4); // { dg-warning "-Wstringop-overflow" } +} diff --git a/gcc/testsuite/gcc.dg/ipa/pr103601.c b/gcc/testsuite/gcc.dg/ipa/pr103601.c new file mode 100644 index 0000000..7bdb5e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr103601.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fgnu89-inline" } */ + +typedef struct { } spinlock_t; +struct list_head { + struct list_head *next, *prev; +}; +struct __wait_queue_head { + spinlock_t lock; + struct list_head task_list; +}; +typedef struct __wait_queue_head wait_queue_head_t; +static inline void init_waitqueue_head(wait_queue_head_t *q) +{ + q->lock = (spinlock_t) { }; + do { (&q->task_list)->next = (&q->task_list); (&q->task_list)->prev = (&q->task_list); } while (0); +} +struct timer_list { + void (*function)(unsigned long); +}; +struct rpc_task { + struct timer_list tk_timer; + wait_queue_head_t tk_wait; +}; +static void +rpc_run_timer(struct rpc_task *task) +{ +} +inline void +rpc_init_task(struct rpc_task *task) +{ + task->tk_timer.function = (void (*)(unsigned long)) rpc_run_timer; + init_waitqueue_head(&task->tk_wait); +} + diff --git a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c index 846e930..70f6a43 100644 --- a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c +++ b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c @@ -143,17 +143,18 @@ T (v0 ? b[1] : "", bsz); T (v0 ? b[2] : "", bsz); T (v0 ? b[3] : "", bsz); -/* The warnings below are strictly correct but the strnlen calls are safe - because the reads are bounded by the length of the constant arguments. - It might make sense to relax the warning to avoid triggering for them. */ +/* Warning for the calls below would be strictly correct even though + the strnlen calls are safe because the reads are bounded by + the length of the constant arguments. Most of the calls are + not diagnosed anymore as a result of the fix for PR 103215. */ T (v0 ? "" : b[0], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? "" : b[1], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? "" : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? "" : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ +T (v0 ? "" : b[1], bsz + 1); +T (v0 ? "" : b[2], bsz + 1); +T (v0 ? "" : b[3], bsz + 1); T (v0 ? b[0] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[1] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[2] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[3] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ +T (v0 ? b[1] : "", bsz + 1); +T (v0 ? b[2] : "", bsz + 1); +T (v0 ? b[3] : "", bsz + 1); T (v0 ? "" : b[i0], bsz); T (v0 ? "" : b[i1], bsz); @@ -167,11 +168,11 @@ T (v0 ? b[i3] : "", bsz); T (v0 ? "" : b[i0], bsz + 1); T (v0 ? "" : b[i1], bsz + 1); T (v0 ? "" : b[i2], bsz + 1); -T (v0 ? "" : b[i3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr86937" } */ +T (v0 ? "" : b[i3], bsz + 1); T (v0 ? b[i0] : "", bsz + 1); T (v0 ? b[i1] : "", bsz + 1); T (v0 ? b[i2] : "", bsz + 1); -T (v0 ? b[i3] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr86937" } */ +T (v0 ? b[i3] : "", bsz + 1); T (v0 ? "1234" : b[3], bsz); T (v0 ? "1234" : b[i3], bsz); @@ -183,15 +184,17 @@ T (v0 ? b[0] : b[2], bsz); T (v0 ? b[2] : b[3], bsz); T (v0 ? b[3] : b[2], bsz); -T (v0 ? "1234" : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? "1234" : b[i3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[3] : "1234", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[i3] : "1234", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ - -T (v0 ? a : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[0] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[2] : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ -T (v0 ? b[3] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */ +T (v0 ? "1234" : b[3], bsz + 1); +T (v0 ? "1234" : b[i3], bsz + 1); +T (v0 ? b[3] : "1234", bsz + 1); +T (v0 ? b[i3] : "1234", bsz + 1); + +/* That the following are not diagnosed is a bug/limitation resulting from + the fix for PR 103215. */ +T (v0 ? a : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ +T (v0 ? b[0] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ +T (v0 ? b[2] : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ +T (v0 ? b[3] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ struct A { char a[5], b[5]; }; diff --git a/gcc/testsuite/gcc.target/aarch64/pr103523.c b/gcc/testsuite/gcc.target/aarch64/pr103523.c new file mode 100644 index 0000000..736e893 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr103523.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-march=armv8-a+sve -mtune=neoverse-v1 -Ofast" } */ + +void d(float *a, float b, int c) { + float e; + for (; c; c--, e += b) + a[c] = e; +} diff --git a/gcc/testsuite/gcc.target/nvptx/float16-1.c b/gcc/testsuite/gcc.target/nvptx/float16-1.c new file mode 100644 index 0000000..3a0324d --- /dev/null +++ b/gcc/testsuite/gcc.target/nvptx/float16-1.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -misa=sm_53 -mptx=6.3 -ffast-math" } */ + +_Float16 var; + +float load() +{ + return var; +} + +void store(float x) +{ + var = x; +} + +void move(_Float16 *dst, _Float16 *src) +{ + *dst = *src; +} + +double plus(double x, double y) +{ + _Float16 hx = x; + _Float16 hy = y; + _Float16 hz = hx + hy; + return hz; +} + +double minus(double x, double y) +{ + _Float16 hx = x; + _Float16 hy = y; + _Float16 hz = hx - hy; + return hz; +} + +double mult(double x, double y) +{ + _Float16 hx = x; + _Float16 hy = y; + _Float16 hz = hx * hy; + return hz; +} + +/* { dg-final { scan-assembler-times "ld.b16" 2 } } */ +/* { dg-final { scan-assembler-times "cvt.f32.f16" 1 } } */ +/* { dg-final { scan-assembler-times "cvt.rn.f16.f32" 1 } } */ +/* { dg-final { scan-assembler-times "st.b16" 2 } } */ +/* { dg-final { scan-assembler-times "add.f16" 1 } } */ +/* { dg-final { scan-assembler-times "sub.f16" 1 } } */ +/* { dg-final { scan-assembler-times "mul.f16" 1 } } */ +/* { dg-final { scan-assembler-times "cvt.rn.f16.f64" 6 } } */ +/* { dg-final { scan-assembler-times "cvt.f64.f16" 3 } } */ diff --git a/gcc/testsuite/gdc.test/compilable/covariant_override.d b/gcc/testsuite/gdc.test/compilable/covariant_override.d new file mode 100644 index 0000000..1afe0a2 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/covariant_override.d @@ -0,0 +1,34 @@ +// https://issues.dlang.org/show_bug.cgi?id=21538 +// REQUIRED_ARGS: -preview=dip1000 + +interface I +{ + void f(void delegate() @safe dg) @safe; +} + +class CI : I +{ + override void f(void delegate() @system dg) @safe { } +} + +abstract class A +{ + void f(void delegate() @safe dg) @safe; +} + +class CA : A +{ + override void f(void delegate() @system dg) @safe { } +} + +// https://issues.dlang.org/show_bug.cgi?id=20904 +auto blah(void delegate()) +{ +} + +void delegate()[string] r; +void main() +{ + void delegate() nothrow a; + r["v"] = a; +} diff --git a/gcc/testsuite/gdc.test/compilable/emptygenmain.d b/gcc/testsuite/gdc.test/compilable/emptygenmain.d new file mode 100644 index 0000000..be7bee8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/emptygenmain.d @@ -0,0 +1,3 @@ +// REQUIRED_ARGS: -main -c + +void foo() { } diff --git a/gcc/testsuite/gdc.test/compilable/noreturn1.d b/gcc/testsuite/gdc.test/compilable/noreturn1.d index b041e07..22734cf 100644 --- a/gcc/testsuite/gdc.test/compilable/noreturn1.d +++ b/gcc/testsuite/gdc.test/compilable/noreturn1.d @@ -111,3 +111,15 @@ void* useTls() void* a3 = &globalNoreturn; return a1 < a2 ? a2 : a3; } + +/***************************************************/ + +noreturn testfn(noreturn function() fn) +{ + fn(); +} + +noreturn testdg(noreturn delegate() dg) +{ + dg(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test17870.d b/gcc/testsuite/gdc.test/compilable/test17870.d new file mode 100644 index 0000000..2329b60 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17870.d @@ -0,0 +1,26 @@ +alias AliasSeq(T...) = T; + +class A +{ + int z = 3; +} + +class B : A +{ + int a = 1; +} + +class C : B +{ + int b = 2; + alias tup = AliasSeq!(b, a, z); +} + +void main() +{ + static const ins = new C; + static assert(&ins.tup[0] == &ins.b); + static assert(&ins.tup[1] == &ins.a); + static assert(&ins.tup[2] == &ins.z); + static assert(ins.tup == AliasSeq!(2,1,3)); +} diff --git a/gcc/testsuite/gdc.test/compilable/test19873.d b/gcc/testsuite/gdc.test/compilable/test19873.d new file mode 100644 index 0000000..7252edd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test19873.d @@ -0,0 +1,37 @@ +// PERMUTE_ARGS -preview=dip1000 +// https://issues.dlang.org/show_bug.cgi?id=19873 +int* ed(scope int* x) +{ + auto y = x; + return y; +} + +int* et(scope int* x) @trusted +{ + auto y = x; + return y; +} + +int* es(scope int* x) @system +{ + auto y = x; + return y; +} + +auto ad(scope int* x) +{ + auto y = x; + return y; +} + +auto at(scope int* x) @trusted +{ + auto y = x; + return y; +} + +auto as(scope int* x) @system +{ + auto y = x; + return y; +} diff --git a/gcc/testsuite/gdc.test/compilable/test21719.d b/gcc/testsuite/gdc.test/compilable/test21719.d new file mode 100644 index 0000000..9d444e1 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21719.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=21719 + +struct S +{ + auto f() + { + } // inferred to be @safe @nogc pure nothrow +} + +class C +{ + auto f() // should also infer the same attributes + { + } +} + +pure @nogc nothrow @safe void test(S s, C c) +{ + s.f; + c.f; +} diff --git a/gcc/testsuite/gdc.test/compilable/test22254.d b/gcc/testsuite/gdc.test/compilable/test22254.d new file mode 100644 index 0000000..94f6596a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22254.d @@ -0,0 +1,19 @@ +// https://issues.dlang.org/show_bug.cgi?id=22254 + +struct Template(T) { T t; } + +Template!Bar a; +Template!Bar b; + +immutable struct Bar { } + +static assert(is(typeof(a) == typeof(b))); +static assert(is(typeof(a) == Template!(immutable Bar))); + +Template!C c1; +Template!C c2; + +immutable class C { } + +static assert(is(typeof(c1) == typeof(c2))); +static assert(is(typeof(c1) == Template!(immutable C))); diff --git a/gcc/testsuite/gdc.test/compilable/test22510.d b/gcc/testsuite/gdc.test/compilable/test22510.d new file mode 100644 index 0000000..af5d0a4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22510.d @@ -0,0 +1,18 @@ +// https://issues.dlang.org/show_bug.cgi?id=22510 + +struct S +{ + int b; + + @disable this(this); + this (scope ref inout S) inout + { + this.b = b; + } +} + +void main() +{ + auto scoped_s = S(4); + auto heap_s = new S(42); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/covariant_override.d b/gcc/testsuite/gdc.test/fail_compilation/covariant_override.d new file mode 100644 index 0000000..7738770 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/covariant_override.d @@ -0,0 +1,35 @@ +/++ +https://issues.dlang.org/show_bug.cgi?id=21538 + +TEST_OUTPUT: +--- +fail_compilation/covariant_override.d(23): Error: function `@safe void covariant_override.CI.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.I.f(void delegate() @system dg)`? +fail_compilation/covariant_override.d(34): Error: function `@safe void covariant_override.CA.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.A.f(void delegate() @system dg)`? +fail_compilation/covariant_override.d(20): Error: class `covariant_override.CI` interface function `void f(void delegate() @system dg) @safe` is not implemented +--- +++/ + +static assert(!is(void delegate() @system : void delegate() @safe)); +static assert( is(void delegate() @safe : void delegate() @system)); + +interface I +{ + void f(void delegate() @system dg) @safe; +} + +class CI : I +{ + // this overrride should not be legal + override void f(void delegate() @safe dg) @safe { } +} + +abstract class A +{ + void f(void delegate() @system dg) @safe; +} + +class CA : A +{ + // this overrride should not be legal + override void f(void delegate() @safe dg) @safe { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d index de3673f..4b31a92 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d @@ -5,8 +5,8 @@ fail_compilation/fail10964.d(28): Error: function `fail10964.S.__postblit` is no 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(34): Error: function `core.internal.array.construction._d_arraysetctor!(S[], S)._d_arraysetctor` is not `nothrow` +fail_compilation/fail10964.d(35): Error: function `core.internal.array.construction._d_arrayctor!(S[], S)._d_arrayctor` 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 06e0687..d9f554a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d @@ -1,24 +1,26 @@ /* TEST_OUTPUT: --- -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(29): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(42): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(42): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(43): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(43): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(29): `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 +fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(47): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor` +fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` +fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here +fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor` --- */ @@ -49,12 +51,12 @@ void bar() pure @safe /* TEST_OUTPUT: --- -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(75): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit +fail_compilation/fail10968.d(76): 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 +fail_compilation/fail10968.d(80): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit +fail_compilation/fail10968.d(81): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16997.d b/gcc/testsuite/gdc.test/fail_compilation/fail16997.d index a8f3ae4..279d9da 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail16997.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16997.d @@ -1,25 +1,25 @@ /* -REQUIRED_ARGS: -de +REQUIRED_ARGS: -de -revert=intpromote 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)` +fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, remove '-revert=intpromote' switch or `~cast(int)(c)` +fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, remove '-revert=intpromote' switch or `-cast(int)(c)` +fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, remove '-revert=intpromote' switch or `+cast(int)(c)` +fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, remove '-revert=intpromote' switch or `~cast(int)(w)` +fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, remove '-revert=intpromote' switch or `-cast(int)(w)` +fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, remove '-revert=intpromote' switch or `+cast(int)(w)` +fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, remove '-revert=intpromote' switch or `~cast(int)(sb)` +fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, remove '-revert=intpromote' switch or `-cast(int)(sb)` +fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, remove '-revert=intpromote' switch or `+cast(int)(sb)` +fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, remove '-revert=intpromote' switch or `~cast(int)(ub)` +fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, remove '-revert=intpromote' switch or `-cast(int)(ub)` +fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, remove '-revert=intpromote' switch or `+cast(int)(ub)` +fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, remove '-revert=intpromote' switch or `~cast(int)(s)` +fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, remove '-revert=intpromote' switch or `-cast(int)(s)` +fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, remove '-revert=intpromote' switch or `+cast(int)(s)` +fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, remove '-revert=intpromote' switch or `~cast(int)(us)` +fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, remove '-revert=intpromote' switch or `-cast(int)(us)` +fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, remove '-revert=intpromote' switch or `+cast(int)(us)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail809.d b/gcc/testsuite/gdc.test/fail_compilation/fail809.d deleted file mode 100644 index b83639b..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail809.d +++ /dev/null @@ -1,12 +0,0 @@ -// 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/fob2.d b/gcc/testsuite/gdc.test/fail_compilation/fob2.d index dbe8ea2..175ade3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fob2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fob2.d @@ -120,7 +120,7 @@ fail_compilation/fob2.d(515): Error: variable `fob2.test52.p` has undefined stat } -@live void test52() +@live void test52() @safe { int x = 5; auto p = &x; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d new file mode 100644 index 0000000..c3e8a78 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test20023b.d @@ -0,0 +1,10 @@ +module imports.test20023b; + +auto threw()() @safe +{ + try + throw new Exception("Hello"); + catch (Exception e) + return e; + assert(0); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d index 58f0430..64db4c8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d @@ -14,14 +14,14 @@ fail_compilation/retscope.d(49): Error: address of struct temporary returned by -int* foo1(return scope int* p) { return p; } // ok +int* foo1(return scope int* p) @safe { return p; } // ok -int* foo2()(scope int* p) { return p; } // ok, 'return' is inferred +int* foo2()(scope int* p) @safe { return p; } // ok, 'return' is inferred alias foo2a = foo2!(); -int* foo3(scope int* p) { return p; } // error +int* foo3(scope int* p) @safe { return p; } // error -int* foo4(bool b) +int* foo4(bool b) @safe { int i; int j; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d index 173473a..1b3078f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d @@ -1,18 +1,52 @@ /* TEST_OUTPUT: +PERMUTE_ARGS -dip1000 --- -fail_compilation/test15191.d(17): Error: cannot take address of `ref return` of `foo()` in `@safe` function `bar` +fail_compilation/test15191.d(31): Error: returning `&identity(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(37): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(43): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive` +fail_compilation/test15191.d(43): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` --- */ - // https://issues.dlang.org/show_bug.cgi?id=15191 +// https://issues.dlang.org/show_bug.cgi?id=22519 -ref int foo(return ref int s)@safe +@safe: +ref int foo(return ref int s) { return s; } -int* bar(return ref int s) @safe +int* bar(return ref int s) { return &foo(s); } + +ref int identity(ref return int x) {return x;} +ref int* identityPtr(ref return int* x) {return x;} + +int* addrOfRefEscape() +{ + int x; + return &identity(x); +} + +int** addrOfRefSystem() @system +{ + int* x; + return &identityPtr(x); +} + +int** addrOfRefTransitive() +{ + int* x; + return &identityPtr(x); +} + +int gInt; +ref int getGlobalInt() {return gInt;} + +int* addrOfRefGlobal() +{ + return &getGlobalInt(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17977.d b/gcc/testsuite/gdc.test/fail_compilation/test17977.d new file mode 100644 index 0000000..ff6bc1c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17977.d @@ -0,0 +1,20 @@ +/* +https://issues.dlang.org/show_bug.cgi?id=15399 +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/test17977.d(19): Error: address of variable `__slList3` assigned to `elem` with longer lifetime +--- +*/ + +@safe: +struct List { + int* data; + ~this(); + int* front() return; +} + +void test() +{ + auto elem = List().front; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20023.d b/gcc/testsuite/gdc.test/fail_compilation/test20023.d new file mode 100644 index 0000000..909e699 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test20023.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -preview=dip1000 -preview=dip1008 -Ifail_compilation/extra-files +// https://issues.dlang.org/show_bug.cgi?id=20023 +/* +TEST_OUTPUT: +--- +fail_compilation/imports/test20023b.d(8): Error: scope variable `e` may not be returned +fail_compilation/test20023.d(15): Error: template instance `imports.test20023b.threw!()` error instantiating +--- +*/ +import imports.test20023b; + +@safe: +void main() +{ + threw!()(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d b/gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d new file mode 100644 index 0000000..94ff80a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/traits_initSymbol.d @@ -0,0 +1,63 @@ +/******************************************** +TEST_OUTPUT: +--- +fail_compilation/traits_initSymbol.d(105): Error: struct / class type expected as argument to __traits(initSymbol) instead of `int` +fail_compilation/traits_initSymbol.d(106): Error: struct / class type expected as argument to __traits(initSymbol) instead of `S[2]` +fail_compilation/traits_initSymbol.d(107): Error: struct / class type expected as argument to __traits(initSymbol) instead of `123` +--- +*/ +#line 100 + +struct S { int i = 4; } + +void test1() +{ + const void[] initInt = __traits(initSymbol, int); + const void[] initArray = __traits(initSymbol, S[2]); + const void[] initValue = __traits(initSymbol, 123); +} + +/******************************************** +TEST_OUTPUT: +--- +fail_compilation/traits_initSymbol.d(203): Error: cannot determine the address of the initializer symbol during CTFE +fail_compilation/traits_initSymbol.d(203): called from here: `(*function () pure nothrow @nogc @safe => S)()` +--- +*/ +#line 200 + +void test2() +{ + enum initLen = (() => __traits(initSymbol, S))(); +} + +/******************************************** +TEST_OUTPUT: +--- +fail_compilation/traits_initSymbol.d(305): Error: struct / class type expected as argument to __traits(initSymbol) instead of `traits_initSymbol.Interface` +--- +*/ +#line 300 + +interface Interface {} + +void test3() +{ + const void[] initInterface = __traits(initSymbol, Interface); +} + +/******************************************** +TEST_OUTPUT: +--- +fail_compilation/traits_initSymbol.d(404): Error: expected 1 arguments for `initSymbol` but had 0 +fail_compilation/traits_initSymbol.d(405): Error: expected 1 arguments for `initSymbol` but had 2 +--- +*/ +#line 400 + + +void test4() +{ + const void[] tmp = __traits(initSymbol); + const void[] tmo = __traits(initSymbol, Interface, S); +} diff --git a/gcc/testsuite/gdc.test/runnable/b19294.d b/gcc/testsuite/gdc.test/runnable/b19294.d new file mode 100644 index 0000000..5700195 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/b19294.d @@ -0,0 +1,163 @@ +alias T = MyStruct!float; + +struct MyStruct(U) +{ + U x; + U y; + + this(U xx, U yy) + { + x = xx; + y = yy; + } + + MyStruct!U opBinary(string op)(MyStruct!U z) const + { + alias C = typeof(return); + auto w = C(this.x, this.y); + return w.opOpAssign!(op)(z); + } + + MyStruct!U opBinaryRight(string op)(MyStruct!U z) const + { + return opBinary!(op)(z); + } + + ref MyStruct opOpAssign(string op, U)(const MyStruct!U z) + { + mixin ("x "~op~"= z.x;"); + mixin ("y "~op~"= z.y;"); + return this; + } + + MyStruct!U opBinary(string op, R)(R z) const + if (is(R == int) || is(R == float)) + { + alias C = typeof(return); + auto w = C(this.x, this.y); + return w.opOpAssign!(op)(z); + } + + MyStruct!U opBinaryRight(string op, R)(R z) const + if (is(R == int) || is(R == float)) + { + return opBinary!(op)(z); + } + + ref MyStruct opOpAssign(string op, R)(const R z) + if (is(R == int) || is(R == float)) + { + mixin ("x "~op~"= z;"); + return this; + } +} + +void main() +{ + T c = MyStruct!float(1.0f, 1.0f); + T[] arr = [T(1,1), T(2,2), T(3,3), T(4,4), T(5,5), T(6,6)]; + T[] result = new T[arr.length]; + + // part 2 + + result[0] = c * c; + assert(result[0] == T(1, 1)); + + result[0] = arr[1] * arr[2]; + assert(result[0] == T(6, 6)); + + int[] intarr = [6, 5, 4, 3, 2, 1]; + + result[] = arr[] * arr[]; + assert(result[] == [T(1, 1), T(4, 4), T(9, 9), T(16, 16), T(25, 25), T(36, 36)]); + + result[] = arr[] * 3; + assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + result[] = 3 * arr[]; + assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + + result[] = arr[]; + result[1..3] = arr[1..3] * 2.0f; + assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(4, 4), T(5, 5), T(6, 6)]); + result[1..3] = 2.0f * arr[1..3]; + assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(4, 4), T(5, 5), T(6, 6)]); + + result[] = arr[]; + result[1..$] = arr[1..$] * 2.0f; + assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(8, 4), T(10, 5), T(12, 6)]); + result[1..$] = 2.0f * arr[1..$]; + assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(8, 4), T(10, 5), T(12, 6)]); + + result[] = intarr[] * arr[]; + assert(result[] == [T(6, 1), T(10, 2), T(12, 3), T(12, 4), T(10, 5), T(6, 6)]); + result[] = arr[] * intarr[]; + assert(result[] == [T(6, 1), T(10, 2), T(12, 3), T(12, 4), T(10, 5), T(6, 6)]); + + result[] = intarr[] * T(2,3); + assert(result[] == [T(12, 3), T(10, 3), T(8, 3), T(6, 3), T(4, 3), T(2, 3)]); + result[] = T(2,3) * intarr[]; + assert(result[] == [T(12, 3), T(10, 3), T(8, 3), T(6, 3), T(4, 3), T(2, 3)]); + + result[] = intarr[] * c; + assert(result[] == [T(6, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]); + result[] = c * intarr[]; + assert(result[] == [T(6, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]); + + result[] = arr[]; + result[1..3] = intarr[1..3] * c; + assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(4, 4), T(5, 5), T(6, 6)]); + result[1..3] = c * intarr[1..3]; + assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(4, 4), T(5, 5), T(6, 6)]); + + result[1..$] = intarr[1..$] * c; + assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]); + result[1..$] = c * intarr[1..$]; + assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]); + + result[] = arr[]; + result[1..3] = intarr[1..3] * arr[1..3]; + assert(result[] == [T(1, 1), T(10, 2), T(12, 3), T(4, 4), T(5, 5), T(6, 6)]); + result[1..3] = arr[1..3] * intarr[1..3]; + assert(result[] == [T(1, 1), T(10, 2), T(12, 3), T(4, 4), T(5, 5), T(6, 6)]); + + result[] = [1,2,3,4,5,6] * c; + assert(result[] == [T(1, 1), T(2, 1), T(3, 1), T(4, 1), T(5, 1), T(6, 1)]); + result[] = c * [1,2,3,4,5,6]; + assert(result[] == [T(1, 1), T(2, 1), T(3, 1), T(4, 1), T(5, 1), T(6, 1)]); + + result[] = arr[] * [1,2,3,4,5,6]; + assert(result[] == [T(1, 1), T(4, 2), T(9, 3), T(16, 4), T(25, 5), T(36, 6)]); + result[] = [1,2,3,4,5,6] * arr[]; + assert(result[] == [T(1, 1), T(4, 2), T(9, 3), T(16, 4), T(25, 5), T(36, 6)]); + + result[] = [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c] * [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c]; + assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]); + + result[] = [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c] * [1,2,3,4,5,6]; + assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]); + result[] = [1,2,3,4,5,6] * [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c]; + assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]); + + result[] = arr[] * c; + assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]); + result[] = c * arr[]; + assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]); + + result[] = c * 3.0f * arr[]; + assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + result[] = 3.0f * c * arr[]; + assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + + result[] = arr[] * 3.0f * c; + assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + // result[] = arr[] * c * 3.0f; //not ok + // assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + + result[] = 3.0f * arr[] * c; + assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + // result[] = c * arr[] * 3.0f; //not ok + // assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]); + + result[] = c * arr[] * c; + assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]); +} diff --git a/gcc/testsuite/gdc.test/runnable/mars1.d b/gcc/testsuite/gdc.test/runnable/mars1.d index 4f38f4d..30aa950 100644 --- a/gcc/testsuite/gdc.test/runnable/mars1.d +++ b/gcc/testsuite/gdc.test/runnable/mars1.d @@ -1,5 +1,5 @@ /* -REQUIRED_ARGS: -mcpu=native -preview=intpromote +REQUIRED_ARGS: -mcpu=native PERMUTE_ARGS: -O -inline -release */ diff --git a/gcc/testsuite/gdc.test/runnable/test15862.d b/gcc/testsuite/gdc.test/runnable/test15862.d new file mode 100644 index 0000000..87e2560 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test15862.d @@ -0,0 +1,39 @@ +// https://issues.dlang.org/show_bug.cgi?id=15862 + +/* +PERMUTE_ARGS: +REQUIRED_ARGS: -O -release +*/ + + +int* p() pure nothrow {return new int;} +int[] a() pure nothrow {return [0];} +Object o() pure nothrow {return new Object;} + +auto pa() pure nothrow {return new int;} + +void main() +{ + { + int* p1 = p(); + int* p2 = p(); + + if (p1 is p2) assert(0); + + int[] a1 = a(); + int[] a2 = a(); + + if (a1 is a2) assert(0); + + Object o1 = o(); + Object o2 = o(); + + if (o1 is o2) assert(0); + } + { + auto p1 = pa(); + auto p2 = pa(); + + if (p1 is p2) assert(0); + } +} diff --git a/gcc/testsuite/gdc.test/runnable/test21367.d b/gcc/testsuite/gdc.test/runnable/test21367.d new file mode 100644 index 0000000..96e8d6c --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test21367.d @@ -0,0 +1,47 @@ +// https://issues.dlang.org/show_bug.cgi?id=21367 + +string result = ""; + +struct RCArray(T) +{ + T* data; + this(this) + { + result ~= "A"; + } + ~this() + { + result ~= "B"; + } +} + +struct Variant(T...) +{ + union + { + T payload; + } + this(this) + { + result ~= "C"; + } + + ~this() + { + result ~= "D"; + } +} + +alias Ft = Variant!(RCArray!double, RCArray!int); + +void fun(Ft a) {} +void main() +{ + Ft a; + Ft b = a; +} + +static ~this() +{ + assert(result == "CDD"); +} diff --git a/gcc/testsuite/gdc.test/runnable/test22227.d b/gcc/testsuite/gdc.test/runnable/test22227.d new file mode 100644 index 0000000..7ef53c3 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test22227.d @@ -0,0 +1,16 @@ +// REQUIRED_ARGS: -debug -O -release +// https://issues.dlang.org/show_bug.cgi?id=22277 + +bool secret = false; + +void free(immutable void* x) pure nothrow +{ + debug secret = true; +} + +void main() +{ + free(null); + if (!secret) + assert(0); +} diff --git a/gcc/testsuite/gdc.test/runnable/testOpApply.d b/gcc/testsuite/gdc.test/runnable/testOpApply.d index 7b884e5..285365e 100644 --- a/gcc/testsuite/gdc.test/runnable/testOpApply.d +++ b/gcc/testsuite/gdc.test/runnable/testOpApply.d @@ -1,4 +1,4 @@ -/* PERMUTE_ARGS: +/* PERMUTE_ARGS: -preview=dip1000 */ // https://issues.dlang.org/show_bug.cgi?id=15624 @@ -140,3 +140,32 @@ void testInverseAttributes() } safe(); } + +// https://issues.dlang.org/show_bug.cgi?id=20907 +Lockstep!() lockstep() +{ + return Lockstep!()(); +} + +struct Lockstep() +{ + int opApply(int delegate(int) callback) @system + { + return 0; + } + + int opApply(int delegate(int) pure nothrow @nogc @safe callback) pure nothrow @nogc @safe + { + return 0; + } +} + +void foo0() +{ + foreach (x; lockstep()) {} +} + +void foo1() +{ + foreach (x; lockstep()) {} +} diff --git a/gcc/testsuite/gdc.test/runnable/testcgelem.d b/gcc/testsuite/gdc.test/runnable/testcgelem.d index b5c7f7d..617e3fb 100644 --- a/gcc/testsuite/gdc.test/runnable/testcgelem.d +++ b/gcc/testsuite/gdc.test/runnable/testcgelem.d @@ -1,5 +1,5 @@ /* -REQUIRED_ARGS: -mcpu=native -preview=intpromote +REQUIRED_ARGS: -mcpu=native PERMUTE_ARGS: -O -inline -release */ diff --git a/gcc/testsuite/gdc.test/runnable/testconst.d b/gcc/testsuite/gdc.test/runnable/testconst.d index 5c0e75d..764bb1b 100644 --- a/gcc/testsuite/gdc.test/runnable/testconst.d +++ b/gcc/testsuite/gdc.test/runnable/testconst.d @@ -2860,9 +2860,11 @@ static assert(is(S7038b == shared)); immutable struct S7038c{ int x; } static assert(is(S7038c == immutable)); -static assert(!is(C7038 == const)); +// https://issues.dlang.org/show_bug.cgi?id=22515 +// Classes fixed for consistency with structs +static assert(is(C7038 == const)); const class C7038{ int x; } -static assert(!is(C7038 == const)); +static assert(is(C7038 == const)); void test7038() { @@ -2871,7 +2873,7 @@ void test7038() static assert(is(typeof(s.x) == const int)); C7038 c; - static assert(!is(typeof(c) == const)); + static assert(is(typeof(c) == const)); static assert(is(typeof(c.x) == const int)); } diff --git a/gcc/testsuite/gdc.test/runnable/traits_initSymbol.d b/gcc/testsuite/gdc.test/runnable/traits_initSymbol.d new file mode 100644 index 0000000..0385d98 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/traits_initSymbol.d @@ -0,0 +1,119 @@ +struct Zero +{ + int x; +} + +void testZero() +{ + auto zeroInit = __traits(initSymbol, Zero); + static assert(is(typeof(zeroInit) == const(void[]))); + + assert(zeroInit.ptr is null); + assert(zeroInit.length == Zero.sizeof); +} + +struct NonZero +{ + long x = 1; +} + +void testNonZero() +{ + auto nonZeroInit = __traits(initSymbol, NonZero); + static assert(is(typeof(nonZeroInit) == const(void[]))); + + assert(nonZeroInit.ptr); + assert(nonZeroInit.length == NonZero.sizeof); + assert(cast(const(long[])) nonZeroInit == [1L]); +} + +class C +{ + short x = 123; +} + +void testClass() +{ + auto cInit = __traits(initSymbol, C); + static assert(is(typeof(cInit) == const(void[]))); + + assert(cInit.ptr); + assert(cInit.length == __traits(classInstanceSize, C)); + + scope c = new C; + assert((cast(void*) c)[0 .. cInit.length] == cInit); +} + +struct AlignedStruct +{ + short s = 5; + // 2 byte padding + align(4) char c = 'c'; + // 3 byte padding + int i = 4; + // reduced alignment + align(1) long l = 0xDEADBEEF; +} + +void testAlignedStruct() +{ + auto init = __traits(initSymbol, AlignedStruct); + + assert(init.ptr); + assert(init.length == AlignedStruct.sizeof); + + version (GNU) + AlignedStruct exp = AlignedStruct(); + else + AlignedStruct exp; + assert(init == (cast(void*) &exp)[0 .. AlignedStruct.sizeof]); + +} + +class AlignedClass : C +{ + short s = 5; + // 2 byte padding + align(4) char c = 'c'; + // 3 byte padding + int i = 4; + // reduced alignment + align(1) long l = 0xDEADBEEF; +} + +void testAlignedClass() +{ + auto init = __traits(initSymbol, AlignedClass); + + assert(init.ptr); + assert(init.length == __traits(classInstanceSize, AlignedClass)); + + scope ac = new AlignedClass(); + assert(init == (cast(void*) ac)[0 .. init.length]); +} + +extern (C++) class ExternCppClass +{ + int i = 4; +} + +void testExternCppClass() +{ + auto init = __traits(initSymbol, ExternCppClass); + + assert(init.ptr); + assert(init.length == __traits(classInstanceSize, ExternCppClass)); + + scope ac = new ExternCppClass(); + assert(init == (cast(void*) ac)[0 .. init.length]); +} + +void main() +{ + testZero(); + testNonZero(); + testClass(); + testAlignedStruct(); + testAlignedClass(); + testExternCppClass(); +} diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index 20cc225..4fe6b00 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -4903,7 +4903,7 @@ static assert(is(typeof(S5933d.x) == FuncType5933)); class C5933a { auto x() { return 0; } } -static assert(is(typeof(&(new C5933b()).x) == int delegate())); +static assert(is(typeof(&(new C5933b()).x) == int delegate() pure nothrow @nogc @safe)); class C5933b { auto x() { return 0; } } //static assert(is(typeof((new C5933b()).x) == FuncType5933)); @@ -7923,8 +7923,9 @@ void test17349() { static struct S { - int bar(void delegate(ref int*)) { return 1; } - int bar(void delegate(ref const int*)) const { return 2; } + // Specify attribute inferred for dg1/dg2 + int bar(void delegate(ref int*) pure nothrow @nogc @safe) { return 1; } + int bar(void delegate(ref const int*) pure nothrow @nogc @safe) const { return 2; } } void dg1(ref int*) { } diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp new file mode 100644 index 0000000..f3a9a85 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp7925.cpp @@ -0,0 +1,103 @@ +#include <stdarg.h> +#include <assert.h> + +class C1 +{ +public: + virtual ~C1(); + + int i; + + int f0(); + int f1(int a); + int f2(int a, int b); + virtual int f3(int a, int b); + int f4(int a, ...); +}; + +C1::~C1() +{ +} + +int C1::f0() +{ + return i; +} + +int C1::f1(int a) +{ + return i + a; +} + +int C1::f2(int a, int b) +{ + return i + a + b; +} + +int C1::f3(int a, int b) +{ + return i + a + b; +} + +int C1::f4(int a, ...) +{ + int r = i + a; + int last = a; + + va_list argp; + va_start(argp, a); + while (last) + { + last = va_arg(argp, int); + r += last; + } + va_end(argp); + return r; +} + +C1 *createC1() +{ + return new C1(); +} + +class C2 +{ +public: + virtual ~C2(); + + int i; + + int f0(); + int f1(int a); + int f2(int a, int b); + virtual int f3(int a, int b); + int f4(int a, ...); +}; + +C2 *createC2(); + +void runCPPTests() +{ + C2 *c2 = createC2(); + c2->i = 100; + assert(c2->f0() == 100); + assert(c2->f1(1) == 101); + assert(c2->f2(20, 3) == 123); + assert(c2->f3(20, 3) == 123); + assert(c2->f4(20, 3, 0) == 123); + + int (C2::*fp0)() = &C2::f0; + int (C2::*fp1)(int) = &C2::f1; + int (C2::*fp2)(int, int) = &C2::f2; + int (C2::*fp3)(int, int) = &C2::f3; +#ifndef __DMC__ + int (C2::*fp4)(int, ...) = &C2::f4; +#endif + assert((c2->*(fp0))() == 100); + assert((c2->*(fp1))(1) == 101); + assert((c2->*(fp2))(20, 3) == 123); + assert((c2->*(fp3))(20, 3) == 123); +#ifndef __DMC__ + assert((c2->*(fp4))(20, 3, 0) == 123); +#endif +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test7925.d b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d new file mode 100644 index 0000000..2f52826 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d @@ -0,0 +1,151 @@ +// EXTRA_CPP_SOURCES: cpp7925.cpp + +/* +Exclude -O due to a codegen bug on OSX: +https://issues.dlang.org/show_bug.cgi?id=22556 + +PERMUTE_ARGS(osx): -inline -release -g +*/ + +import core.vararg; + +extern(C++) class C1 +{ +public: + ~this(); + + int i; + + final int f0(); + final int f1(int a); + final int f2(int a, int b); + int f3(int a, int b); + final int f4(int a, ...); +}; + +extern(C++) C1 createC1(); + +extern(C++) class C2 +{ +public: + ~this() + { + } + + int i; + + final int f0() + { + return i; + } + + final int f1(int a) + { + return i + a; + } + + final int f2(int a, int b) + { + return i + a + b; + } + + int f3(int a, int b) + { + return i + a + b; + } + + final int f4(int a, ...) + { + int r = i + a; + int last = a; + + va_list argp; + va_start(argp, a); + while (last) + { + last = va_arg!int(argp); + r += last; + } + va_end(argp); + return r; + } +}; + +extern(C++) C2 createC2() +{ + return new C2; +} + +auto callMember(alias F, Params...)(__traits(parent, F) obj, Params params) +{ + static if(__traits(getFunctionVariadicStyle, F) == "stdarg") + enum varargSuffix = ", ..."; + else + enum varargSuffix = ""; + + static if(is(typeof(&F) R == return) && is(typeof(F) P == __parameters)) + mixin("extern(" ~ __traits(getLinkage, F) ~ ") R delegate(P" ~ varargSuffix ~ ") dg;"); + dg.funcptr = &F; + dg.ptr = cast(void*)obj; + return dg(params); +} + +extern(C++) void runCPPTests(); + +void main() +{ + C1 c1 = createC1(); + c1.i = 100; + assert(c1.f0() == 100); + assert(c1.f1(1) == 101); + assert(c1.f2(20, 3) == 123); + assert(c1.f3(20, 3) == 123); + assert(c1.f4(20, 3, 0) == 123); + + auto dg0 = &c1.f0; + auto dg1 = &c1.f1; + auto dg2 = &c1.f2; + auto dg3 = &c1.f3; + auto dg4 = &c1.f4; + assert(dg0() == 100); + assert(dg1(1) == 101); + assert(dg2(20, 3) == 123); + assert(dg3(20, 3) == 123); + assert(dg4(20, 3, 0) == 123); + + assert(callMember!(C1.f0)(c1) == 100); + assert(callMember!(C1.f1)(c1, 1) == 101); + assert(callMember!(C1.f2)(c1, 20, 3) == 123); + assert(callMember!(C1.f3)(c1, 20, 3) == 123); + assert(callMember!(C1.f4)(c1, 20, 3, 0) == 123); + + int i; + extern(C++) void delegate() lamdba1 = () { + i = 5; + }; + lamdba1(); + assert(i == 5); + + extern(C++) int function(int, int) lamdba2 = (int a, int b) { + return a + b; + }; + assert(lamdba2(3, 4) == 7); + + extern(C++) void delegate(int, ...) lamdba3 = (int a, ...) { + i = a; + int last = a; + + va_list argp; + va_start(argp, a); + while (last) + { + last = va_arg!int(argp); + i += last; + } + va_end(argp); + }; + lamdba3(1000, 200, 30, 4, 0); + assert(i == 1234); + + runCPPTests(); +} diff --git a/gcc/testsuite/gfortran.dg/move_alloc_8.f90 b/gcc/testsuite/gfortran.dg/move_alloc_8.f90 index f624b70..d968ea0 100644 --- a/gcc/testsuite/gfortran.dg/move_alloc_8.f90 +++ b/gcc/testsuite/gfortran.dg/move_alloc_8.f90 @@ -60,7 +60,7 @@ subroutine test2 (x, px) integer, allocatable :: a type(t2), pointer :: ta - call move_alloc (px, ta) ! { dg-error "cannot be INTENT.IN." } + call move_alloc (px, ta) ! { dg-error "must be ALLOCATABLE" } call move_alloc (x%a, a) ! { dg-error "cannot be INTENT.IN." } call move_alloc (x%ptr%a, a) ! OK (3) call move_alloc (px%a, a) ! OK (4) @@ -84,7 +84,7 @@ subroutine test3 (x, px) integer, allocatable :: a class(t2), pointer :: ta - call move_alloc (px, ta) ! { dg-error "cannot be INTENT.IN." } + call move_alloc (px, ta) ! { dg-error "must be ALLOCATABLE" } call move_alloc (x%a, a) ! { dg-error "cannot be INTENT.IN." } call move_alloc (x%ptr%a, a) ! OK (6) call move_alloc (px%a, a) ! OK (7) diff --git a/gcc/testsuite/gfortran.dg/pointer_intent_9.f90 b/gcc/testsuite/gfortran.dg/pointer_intent_9.f90 new file mode 100644 index 0000000..30ddd02 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pointer_intent_9.f90 @@ -0,0 +1,33 @@ +! { dg-do compile } +! PR fortran/103418 +! Validate checks for dummy arguments with INTENT(IN), pointer attribute + +module m + type t + real, pointer :: a, b(:) + end type t +contains + subroutine s1 (a, b, c, d, e) + real, pointer, intent(in) :: a, b(:) + type(t), intent(in) :: c + class(t), intent(in) :: d + type(t), pointer, intent(in) :: e + real, pointer :: pa, pb(:) + call random_number (a) ! legal + call random_number (b) + call cpu_time (a) + call system_clock (count_rate=a) + call random_number (c% a) + call random_number (c% b) + call random_number (d% a) + call random_number (d% b) + call random_number (e% a) + call random_number (e% b) + call move_alloc (a, pa) ! { dg-error "must be ALLOCATABLE" } + call move_alloc (b, pb) ! { dg-error "must be ALLOCATABLE" } + allocate (a) ! { dg-error "pointer association context" } + allocate (b(10)) ! { dg-error "pointer association context" } + allocate (c% a) ! { dg-error "pointer association context" } + allocate (c% b(10)) ! { dg-error "pointer association context" } + end subroutine s1 +end module diff --git a/gcc/testsuite/gfortran.dg/pr103606.f90 b/gcc/testsuite/gfortran.dg/pr103606.f90 new file mode 100644 index 0000000..4328318 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr103606.f90 @@ -0,0 +1,12 @@ +! { dg-do compile } +! PR fortran/103606 - ICE in resolve_fl_procedure +! Contributed by G.Steinmetz + +program p + type t + end type +contains + elemental function f() result(z) ! { dg-error "CLASS variable" } + class(t) :: z + end +end diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index a7fddf9..350a30b 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -188,6 +188,20 @@ #undef create_code #undef verify_code +/* test-builtin-types.c */ +#define create_code create_code_builtin_types +#define verify_code verify_code_builtin_types +#include "test-builtin-types.c" +#undef create_code +#undef verify_code + +/* test-tls.c */ +#define create_code create_code_tls +#define verify_code verify_code_tls +#include "test-tls.c" +#undef create_code +#undef verify_code + /* test-hello-world.c */ #define create_code create_code_hello_world #define verify_code verify_code_hello_world @@ -230,6 +244,9 @@ #undef create_code #undef verify_code +/* test-pr103562.c: We don't add this one, since it touches + the optimization level of the context as a whole. */ + /* test-pr66700-observing-write-through-ptr.c */ #define create_code create_code_pr66700_observing_write_through_ptr #define verify_code verify_code_pr66700_observing_write_through_ptr @@ -408,6 +425,9 @@ const struct testcase testcases[] = { {"functions", create_code_functions, verify_code_functions}, + {"builtin-types", + create_code_builtin_types, + verify_code_builtin_types}, {"hello_world", create_code_hello_world, verify_code_hello_world}, @@ -453,6 +473,9 @@ const struct testcase testcases[] = { {"switch", create_code_switch, verify_code_switch}, + {"tls", + create_code_tls, + verify_code_tls}, {"types", create_code_types, verify_code_types}, diff --git a/gcc/testsuite/jit.dg/test-builtin-types.c b/gcc/testsuite/jit.dg/test-builtin-types.c new file mode 100644 index 0000000..15b026c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-builtin-types.c @@ -0,0 +1,43 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + CHECK_NON_NULL (gcc_jit_context_get_builtin_function (ctxt, "__atomic_fetch_add_4")); + + gcc_jit_function *atomic_load = gcc_jit_context_get_builtin_function (ctxt, "__atomic_load_8"); + + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *const_void_type = + gcc_jit_type_get_const (gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID)); + gcc_jit_type *volatile_void_ptr = + gcc_jit_type_get_pointer (gcc_jit_type_get_volatile (const_void_type)); + gcc_jit_type *long_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG); + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, void_type, "atomics", 0, NULL, 0); + + gcc_jit_lvalue *variable = gcc_jit_function_new_local (func, NULL, long_type, "variable"); + gcc_jit_rvalue *builtin_args[2]; + gcc_jit_rvalue *param1 = gcc_jit_lvalue_get_address(variable, NULL); + builtin_args[0] = gcc_jit_context_new_cast(ctxt, NULL, param1, volatile_void_ptr); + builtin_args[1] = gcc_jit_context_new_rvalue_from_long(ctxt, int_type, 0); + gcc_jit_context_new_call (ctxt, NULL, atomic_load, 2, builtin_args); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + /* Verify that no errors were emitted. */ + CHECK_NON_NULL (result); +} diff --git a/gcc/testsuite/jit.dg/test-error-bad-assignment.c b/gcc/testsuite/jit.dg/test-error-bad-assignment.c new file mode 100644 index 0000000..fea2b37 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-bad-assignment.c @@ -0,0 +1,78 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + void + test_fn () + { + long integer; + volatile const void *variable; + variable = &integer; + long aligned_integer __attribute__((aligned(4))); + variable = &aligned_integer; + } + + and verify that the API complains about the mismatching types + in the assignments. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *long_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG); + gcc_jit_type *const_void_type = + gcc_jit_type_get_const (void_type); + gcc_jit_type *volatile_void_ptr = + gcc_jit_type_get_pointer (gcc_jit_type_get_volatile (const_void_type)); + + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + + gcc_jit_lvalue *integer = gcc_jit_function_new_local (func, NULL, long_type, "integer"); + gcc_jit_rvalue *address = gcc_jit_lvalue_get_address(integer, NULL); + + gcc_jit_lvalue *variable = gcc_jit_function_new_local (func, NULL, volatile_void_ptr, "variable"); + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + gcc_jit_block_add_assignment(initial, NULL, variable, address); + + gcc_jit_type *aligned_long_type = gcc_jit_type_get_aligned (long_type, 4); + gcc_jit_lvalue *aligned_integer = gcc_jit_function_new_local (func, NULL, aligned_long_type, "aligned_integer"); + gcc_jit_rvalue *aligned_address = gcc_jit_lvalue_get_address(aligned_integer, NULL); + + gcc_jit_block_add_assignment(initial, NULL, variable, aligned_address); + + gcc_jit_block_end_with_void_return (initial, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error messages were emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_block_add_assignment:" + " mismatching types:" + " assignment to variable (type: volatile const void *)" + " from &integer (type: long *)"); + + CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt), + "gcc_jit_block_add_assignment:" + " mismatching types:" + " assignment to variable (type: volatile const void *)" + " from &aligned_integer (type: long __attribute__((aligned(4))) *)"); +} + diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c index 4fd49dac..6fa95d9 100644 --- a/gcc/testsuite/jit.dg/test-fuzzer.c +++ b/gcc/testsuite/jit.dg/test-fuzzer.c @@ -193,12 +193,18 @@ get_random_type (fuzzer *f) static gcc_jit_type * make_random_type (fuzzer *f) { - switch (fuzzer_randrange (f, 0, 5)) + switch (fuzzer_randrange (f, 0, 8)) { case 0: return gcc_jit_type_get_pointer (get_random_type (f)); case 1: return gcc_jit_type_get_const (get_random_type (f)); + case 2: + return gcc_jit_type_get_vector (get_random_type (f), 4); + case 3: + return gcc_jit_type_get_volatile (get_random_type (f)); + case 4: + return gcc_jit_type_get_aligned (get_random_type (f), 4); default: { /* Create a struct. */ diff --git a/gcc/testsuite/jit.dg/test-pr103562.c b/gcc/testsuite/jit.dg/test-pr103562.c new file mode 100644 index 0000000..de361b9 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-pr103562.c @@ -0,0 +1,62 @@ +#include <libgccjit.h> +#include "harness.h" + +struct my_struct { long a; long b; long c; }; + +void create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Create the equivalent of: + struct my_struct { long a; long b; long c; }; + static struct my_struct deref(struct my_struct *ptr) { return *ptr; } + long get_a(struct my_struct *s) { return deref(s).a; } + and compile it at -O1. */ + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 1); + + gcc_jit_type *long_type = gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_LONG); + gcc_jit_field* fields[3] = { + gcc_jit_context_new_field(ctxt, NULL, long_type, "a"), + gcc_jit_context_new_field(ctxt, NULL, long_type, "b"), + gcc_jit_context_new_field(ctxt, NULL, long_type, "c"), + }; + gcc_jit_struct *my_struct = + gcc_jit_context_new_struct_type(ctxt, NULL, "my_struct", 3, fields); + gcc_jit_type *my_struct_type = gcc_jit_struct_as_type(my_struct); + gcc_jit_type *my_struct_ptr_type = gcc_jit_type_get_pointer(my_struct_type); + + /* struct my_struct deref(struct my_struct *ptr) { return *ptr; } */ + gcc_jit_param *param_deref = + gcc_jit_context_new_param(ctxt, NULL, my_struct_ptr_type, "ptr"); + gcc_jit_function *func_deref = gcc_jit_context_new_function( + ctxt, NULL, GCC_JIT_FUNCTION_INTERNAL, + my_struct_type, "deref", + 1, ¶m_deref, + 0); + gcc_jit_block *blockDeref = gcc_jit_function_new_block(func_deref, NULL); + gcc_jit_block_end_with_return( + blockDeref, NULL, + gcc_jit_lvalue_as_rvalue(gcc_jit_rvalue_dereference(gcc_jit_param_as_rvalue(param_deref), NULL))); + + /* long get_a(struct my_struct *s) { return deref(s).a; } */ + gcc_jit_param *param_get_a = gcc_jit_context_new_param(ctxt, NULL, my_struct_ptr_type, "s"); + gcc_jit_function *func_get_a = gcc_jit_context_new_function( + ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, + long_type, "get_a", + 1, ¶m_get_a, + 0); + gcc_jit_block *block_get_a = gcc_jit_function_new_block(func_get_a, NULL); + gcc_jit_rvalue *argsForDeref[1] = {gcc_jit_param_as_rvalue(param_get_a)}; + gcc_jit_rvalue *callDeref = gcc_jit_context_new_call(ctxt, NULL, func_deref, 1, argsForDeref); + gcc_jit_block_end_with_return( + block_get_a, NULL, + gcc_jit_rvalue_access_field(callDeref, NULL, fields[0])); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef long(*fn_type) (struct my_struct*); + fn_type get_a = (fn_type) gcc_jit_result_get_code(result, "get_a"); + + struct my_struct s = {1, 2, 3}; + CHECK_VALUE (get_a(&s), 1); +} diff --git a/gcc/testsuite/jit.dg/test-tls.c b/gcc/testsuite/jit.dg/test-tls.c new file mode 100644 index 0000000..3b20182 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-tls.c @@ -0,0 +1,64 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "libgccjit.h" + +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + + _Thread_local int foo; + + int test_using_tls() + { + foo = 42; + return foo; + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_lvalue *foo = + gcc_jit_context_new_global ( + ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "foo"); + gcc_jit_lvalue_set_tls_model (foo, GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC); + + /* Build the test_fn. */ + gcc_jit_function *test_fn = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "test_using_tls", + 0, NULL, + 0); + gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL); + gcc_jit_block_add_assignment ( + block, NULL, + foo, + gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42)); + gcc_jit_block_end_with_return (block, + NULL, + gcc_jit_lvalue_as_rvalue (foo)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*fn_type) (void); + CHECK_NON_NULL (result); + + fn_type test_using_tls = + (fn_type)gcc_jit_result_get_code (result, "test_using_tls"); + CHECK_NON_NULL (test_using_tls); + int return_value = test_using_tls(); + CHECK_VALUE (return_value, 42); + + int *foo = (int *)gcc_jit_result_get_global (result, "foo"); + CHECK_NON_NULL (foo); + CHECK_VALUE (*foo, 42); +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index ebbd894..672e384 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -9946,13 +9946,13 @@ void gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie) { tree block = LOCATION_BLOCK (e->goto_locus); - op (&(e->src), cookie); - op (&(e->dest), cookie); + op (&(e->src), NULL, cookie); + op (&(e->dest), NULL, cookie); if (current_ir_type () == IR_GIMPLE) - op (&(e->insns.g), cookie); + op (&(e->insns.g), NULL, cookie); else - op (&(e->insns.r), cookie); - op (&(block), cookie); + op (&(e->insns.r), NULL, cookie); + op (&(block), &(block), cookie); } #if CHECKING_P diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 7f544ba..f700d5e 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -8065,6 +8065,15 @@ vectorizable_induction (loop_vec_info loop_vinfo, return false; } + step_expr = STMT_VINFO_LOOP_PHI_EVOLUTION_PART (stmt_info); + gcc_assert (step_expr != NULL_TREE); + tree step_vectype = get_same_sized_vectype (TREE_TYPE (step_expr), vectype); + + /* Check for backend support of PLUS/MINUS_EXPR. */ + if (!directly_supported_p (PLUS_EXPR, step_vectype) + || !directly_supported_p (MINUS_EXPR, step_vectype)) + return false; + if (!vec_stmt) /* transformation not required. */ { unsigned inside_cost = 0, prologue_cost = 0; @@ -8124,10 +8133,6 @@ vectorizable_induction (loop_vec_info loop_vinfo, if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "transform induction phi.\n"); - step_expr = STMT_VINFO_LOOP_PHI_EVOLUTION_PART (stmt_info); - gcc_assert (step_expr != NULL_TREE); - tree step_vectype = get_same_sized_vectype (TREE_TYPE (step_expr), vectype); - pe = loop_preheader_edge (iv_loop); /* Find the first insertion point in the BB. */ basic_block bb = gimple_bb (phi); diff --git a/gcc/value-range.h b/gcc/value-range.h index 32200ff..8cc8cca 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -365,8 +365,8 @@ gt_pch_nx (irange *x, gt_pointer_operator op, void *cookie) { for (unsigned i = 0; i < x->m_num_ranges; ++i) { - op (&x->m_base[i * 2], cookie); - op (&x->m_base[i * 2 + 1], cookie); + op (&x->m_base[i * 2], NULL, cookie); + op (&x->m_base[i * 2 + 1], NULL, cookie); } } @@ -1388,7 +1388,7 @@ void gt_pch_nx (vec<T *, A, vl_embed> *v, gt_pointer_operator op, void *cookie) { for (unsigned i = 0; i < v->length (); i++) - op (&((*v)[i]), cookie); + op (&((*v)[i]), NULL, cookie); } template<typename T, typename A> diff --git a/gcc/wide-int.h b/gcc/wide-int.h index 19bf65d..d03a174 100644 --- a/gcc/wide-int.h +++ b/gcc/wide-int.h @@ -3338,7 +3338,7 @@ gt_pch_nx (generic_wide_int <T> *) template<typename T> void -gt_pch_nx (generic_wide_int <T> *, void (*) (void *, void *), void *) +gt_pch_nx (generic_wide_int <T> *, void (*) (void *, void *, void *), void *) { } @@ -3356,7 +3356,7 @@ gt_pch_nx (trailing_wide_ints <N> *) template<int N> void -gt_pch_nx (trailing_wide_ints <N> *, void (*) (void *, void *), void *) +gt_pch_nx (trailing_wide_ints <N> *, void (*) (void *, void *, void *), void *) { } diff --git a/include/ChangeLog b/include/ChangeLog index 13e5b7e..88f15e4 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2021-12-10 Andrew Stubbs <ams@codesourcery.com> + + * gomp-constants.h (GOMP_VERSION_GCN): Bump. + 2021-12-08 Chung-Lin Tang <cltang@codesourcery.com> PR middle-end/92120 diff --git a/include/gomp-constants.h b/include/gomp-constants.h index 9e7db69..2cf0919 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -274,7 +274,7 @@ enum gomp_map_kind #define GOMP_VERSION 1 #define GOMP_VERSION_NVIDIA_PTX 1 #define GOMP_VERSION_INTEL_MIC 0 -#define GOMP_VERSION_GCN 1 +#define GOMP_VERSION_GCN 2 #define GOMP_VERSION_PACK(LIB, DEV) (((LIB) << 16) | (DEV)) #define GOMP_VERSION_LIB(PACK) (((PACK) >> 16) & 0xffff) diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 71e35b9..3c06a0a 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,36 @@ +2021-12-11 Rasmus Villemoes <rasmus.villemoes@prevas.dk> + + * config/vxcrtstuff.c: Make constructor and destructor + functions static when possible. + +2021-12-11 Rasmus Villemoes <rasmus.villemoes@prevas.dk> + + * config/vxcrtstuff.c: Remove constructor/destructor + declarations. + +2021-12-10 Iain Sandoe <iain@sandoe.co.uk> + + * config/t-darwin: Add libgcc_tm.h to the dependencies + for darwin10-unwind-find-enc-func. + +2021-12-10 Rasmus Villemoes <rv@rasmusvillemoes.dk> + + * config/rs6000/t-vxworks: New file. + * config.host (powerpc*-*-vxworks*): Use it instead of + t-ppccomm. + +2021-12-09 Fred Konrad <konrad@adacore.com> + + * config.host (powerpc*-wrs-vxworks7*): Fix path to + rs6000/t-ppc64-fp, relative to config/ not libgcc/. + +2021-12-09 Olivier Hainque <hainque@adacore.com> + Rasmus Villemoes <rv@rasmusvillemoes.dk> + + * config/t-vxworks: Set CRTSTUFF_T_CFLAGS to + $(LIBGCC2_INCLUDES). + * config/t-vxworks7: Likewise. + 2021-12-08 Iain Sandoe <iain@sandoe.co.uk> * config.host (*-*-darwin*): Add logic to build a shared diff --git a/libgcc/config.host b/libgcc/config.host index d4c035c..bd44f1b 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -1238,7 +1238,7 @@ powerpc*-*-linux*) md_unwind_header=rs6000/linux-unwind.h ;; powerpc*-wrs-vxworks7*) - tmake_file="$tmake_file rs6000/t-ppccomm rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-linux t-dfprules config/rs6000/t-ppc64-fp t-slibgcc-libgcc" + tmake_file="$tmake_file rs6000/t-vxworks rs6000/t-savresfgpr rs6000/t-crtstuff rs6000/t-linux t-dfprules rs6000/t-ppc64-fp t-slibgcc-libgcc" case $ppc_fp_type in 64) ;; @@ -1255,7 +1255,7 @@ powerpc*-wrs-vxworks7*) esac ;; powerpc-wrs-vxworks*) - tmake_file="$tmake_file rs6000/t-ppccomm rs6000/t-savresfgpr t-fdpbit" + tmake_file="$tmake_file rs6000/t-vxworks rs6000/t-savresfgpr t-fdpbit" ;; powerpc-*-lynxos*) tmake_file="$tmake_file rs6000/t-lynx t-fdpbit" diff --git a/libgcc/config/rs6000/t-vxworks b/libgcc/config/rs6000/t-vxworks new file mode 100644 index 0000000..8c7a56f --- /dev/null +++ b/libgcc/config/rs6000/t-vxworks @@ -0,0 +1 @@ +LIB2ADD += $(srcdir)/config/rs6000/tramp.S diff --git a/libgcc/config/t-darwin b/libgcc/config/t-darwin index a855ecf..299d26c 100644 --- a/libgcc/config/t-darwin +++ b/libgcc/config/t-darwin @@ -25,7 +25,7 @@ libemutls_w.a: emutls_s.o $(RANLIB_FOR_TARGET) $@ # Patch to __Unwind_Find_Enclosing_Function for Darwin10. -d10-uwfef.o: $(srcdir)/config/darwin10-unwind-find-enc-func.c +d10-uwfef.o: $(srcdir)/config/darwin10-unwind-find-enc-func.c libgcc_tm.h $(crt_compile) -mmacosx-version-min=10.6 -c $< # Using this crt as a library means that it will not be added to an exe diff --git a/libgcc/config/t-vxworks b/libgcc/config/t-vxworks index b4bb85b..5f7ced8 100644 --- a/libgcc/config/t-vxworks +++ b/libgcc/config/t-vxworks @@ -17,3 +17,5 @@ LIBGCC2_INCLUDES = -nostdinc -I. \ */mrtp*) echo -I$(WIND_USR)/h -I$(WIND_USR)/h/wrn/coreip ;; \ *) echo -I$(WIND_BASE)/target/h -I$(WIND_BASE)/target/h/wrn/coreip ;; \ esac` + +CRTSTUFF_T_CFLAGS = $(LIBGCC2_INCLUDES) diff --git a/libgcc/config/t-vxworks7 b/libgcc/config/t-vxworks7 index 6ddd3e8..180784b 100644 --- a/libgcc/config/t-vxworks7 +++ b/libgcc/config/t-vxworks7 @@ -18,3 +18,5 @@ LIBGCC2_INCLUDES = -nostdinc -I. \ */mrtp*) echo -I$(VSB_DIR)/usr/h/public -I$(VSB_DIR)/usr/h ;; \ *) echo -I$(VSB_DIR)/krnl/h/system -I$(VSB_DIR)/krnl/h/public ;; \ esac` + +CRTSTUFF_T_CFLAGS = $(LIBGCC2_INCLUDES) diff --git a/libgcc/config/vxcrtstuff.c b/libgcc/config/vxcrtstuff.c index 767b9de..c15e15e 100644 --- a/libgcc/config/vxcrtstuff.c +++ b/libgcc/config/vxcrtstuff.c @@ -66,14 +66,18 @@ __attribute__((section(__LIBGCC_EH_FRAME_SECTION_NAME__), aligned(4))) #define EH_CTOR_NAME _crtbe_register_frame #define EH_DTOR_NAME _ctrbe_deregister_frame +#define EH_LINKAGE static #else /* No specific sections for constructors or destructors: we thus use a symbol naming convention so that the constructors are then recognized - by munch or whatever tool is used for the final link phase. */ + by munch or whatever tool is used for the final link phase. Since the + pointers to the constructor/destructor functions are not created in this + translation unit, they must have external linkage. */ #define EH_CTOR_NAME _GLOBAL__I_00101_0__crtbe_register_frame #define EH_DTOR_NAME _GLOBAL__D_00101_1__crtbe_deregister_frame +#define EH_LINKAGE #endif @@ -96,16 +100,13 @@ __attribute__((section(__LIBGCC_EH_FRAME_SECTION_NAME__), aligned(4))) #endif /* USE_INITFINI_ARRAY */ -void EH_CTOR_NAME (void); -void EH_DTOR_NAME (void); - -EH_CTOR_ATTRIBUTE void EH_CTOR_NAME (void) +EH_LINKAGE EH_CTOR_ATTRIBUTE void EH_CTOR_NAME (void) { static struct object object; __register_frame_info (__EH_FRAME_BEGIN__, &object); } -EH_DTOR_ATTRIBUTE void EH_DTOR_NAME (void) +EH_LINKAGE EH_DTOR_ATTRIBUTE void EH_DTOR_NAME (void) { __deregister_frame_info (__EH_FRAME_BEGIN__); } diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 5f0b096..36ee660 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,16 @@ +2021-12-10 Andrew Stubbs <ams@codesourcery.com> + + * plugin/plugin-gcn.c (struct gcn_image_desc): Remove global_variables. + (GOMP_OFFLOAD_load_image): Locate the offload variables via the + table, not individual symbols. + +2021-12-09 Chung-Lin Tang <cltang@codesourcery.com> + + * testsuite/libgomp.c++/target-lambda-1.C: Only run under + "target offload_device_nonshared_as" + * testsuite/libgomp.c++/target-this-3.C: Likewise. + * testsuite/libgomp.c++/target-this-4.C: Likewise. + 2021-12-08 Chung-Lin Tang <cltang@codesourcery.com> * target.c (gomp_map_vars_existing): Make sure attached pointer is diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c index 9e7377c..694862b 100644 --- a/libgomp/plugin/plugin-gcn.c +++ b/libgomp/plugin/plugin-gcn.c @@ -392,7 +392,6 @@ struct gcn_image_desc const unsigned kernel_count; struct hsa_kernel_description *kernel_infos; const unsigned global_variable_count; - struct global_var_info *global_variables; }; /* This enum mirrors the corresponding LLVM enum's values for all ISAs that we @@ -3365,37 +3364,41 @@ GOMP_OFFLOAD_load_image (int ord, unsigned version, const void *target_data, if (!create_and_finalize_hsa_program (agent)) return -1; - for (unsigned i = 0; i < var_count; i++) + if (var_count > 0) { - struct global_var_info *v = &image_desc->global_variables[i]; - GCN_DEBUG ("Looking for variable %s\n", v->name); - hsa_status_t status; hsa_executable_symbol_t var_symbol; status = hsa_fns.hsa_executable_get_symbol_fn (agent->executable, NULL, - v->name, agent->id, + ".offload_var_table", + agent->id, 0, &var_symbol); if (status != HSA_STATUS_SUCCESS) hsa_fatal ("Could not find symbol for variable in the code object", status); - uint64_t var_addr; - uint32_t var_size; + uint64_t var_table_addr; status = hsa_fns.hsa_executable_symbol_get_info_fn - (var_symbol, HSA_EXECUTABLE_SYMBOL_INFO_VARIABLE_ADDRESS, &var_addr); + (var_symbol, HSA_EXECUTABLE_SYMBOL_INFO_VARIABLE_ADDRESS, + &var_table_addr); if (status != HSA_STATUS_SUCCESS) hsa_fatal ("Could not extract a variable from its symbol", status); - status = hsa_fns.hsa_executable_symbol_get_info_fn - (var_symbol, HSA_EXECUTABLE_SYMBOL_INFO_VARIABLE_SIZE, &var_size); - if (status != HSA_STATUS_SUCCESS) - hsa_fatal ("Could not extract a variable size from its symbol", status); - pair->start = var_addr; - pair->end = var_addr + var_size; - GCN_DEBUG ("Found variable %s at %p with size %u\n", v->name, - (void *)var_addr, var_size); - pair++; + struct { + uint64_t addr; + uint64_t size; + } var_table[var_count]; + GOMP_OFFLOAD_dev2host (agent->device_id, var_table, + (void*)var_table_addr, sizeof (var_table)); + + for (unsigned i = 0; i < var_count; i++) + { + pair->start = var_table[i].addr; + pair->end = var_table[i].addr + var_table[i].size; + GCN_DEBUG ("Found variable at %p with size %lu\n", + (void *)var_table[i].addr, var_table[i].size); + pair++; + } } GCN_DEBUG ("Looking for variable %s\n", STRINGX (GOMP_DEVICE_NUM_VAR)); diff --git a/libgomp/testsuite/libgomp.c++/target-lambda-1.C b/libgomp/testsuite/libgomp.c++/target-lambda-1.C index 06c6470..c5acbb8 100644 --- a/libgomp/testsuite/libgomp.c++/target-lambda-1.C +++ b/libgomp/testsuite/libgomp.c++/target-lambda-1.C @@ -1,3 +1,5 @@ +// { dg-do run { target offload_device_nonshared_as } } + #include <cstdlib> #include <cstring> diff --git a/libgomp/testsuite/libgomp.c++/target-this-3.C b/libgomp/testsuite/libgomp.c++/target-this-3.C index e15f69a..6049ba8 100644 --- a/libgomp/testsuite/libgomp.c++/target-this-3.C +++ b/libgomp/testsuite/libgomp.c++/target-this-3.C @@ -1,3 +1,5 @@ +// { dg-do run { target offload_device_nonshared_as } } + #include <stdio.h> #include <string.h> extern "C" void abort (); diff --git a/libgomp/testsuite/libgomp.c++/target-this-4.C b/libgomp/testsuite/libgomp.c++/target-this-4.C index 9f53677..f0237c9 100644 --- a/libgomp/testsuite/libgomp.c++/target-this-4.C +++ b/libgomp/testsuite/libgomp.c++/target-this-4.C @@ -1,6 +1,7 @@ - // We use 'auto' without a function return type, so specify dialect here // { dg-additional-options "-std=c++14" } +// { dg-do run { target offload_device_nonshared_as } } + #include <cstdlib> #include <cstring> diff --git a/libphobos/ChangeLog b/libphobos/ChangeLog index 70d63f0..ca647c5 100644 --- a/libphobos/ChangeLog +++ b/libphobos/ChangeLog @@ -1,3 +1,15 @@ +2021-12-10 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/103528 + * libdruntime/MERGE: Merge upstream druntime bc58b1e9. + * libdruntime/Makefile.am (DRUNTIME_DSOURCES_LINUX): Remove + core/sys/linux/syscalls.d. + * libdruntime/Makefile.in: Regenerate. + * src/MERGE: Merge upstream phobos 12329adb6. + * testsuite/libphobos.config/config.exp: Add test22523. + * libdruntime/core/sys/linux/syscalls.d: Removed. + * testsuite/libphobos.config/test22523.d: New test. + 2021-12-08 Iain Buclaw <ibuclaw@gdcproject.org> PR d/103558 diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index d0d3a25..edb1017 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -178c44ff362902af589603767055cfac89215652 +bc58b1e9ea68051af9094651a26313371297b79f The first line of this file holds the git revision number of the last merge done from the dlang/druntime repository. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 44d4fe1..224d06e 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -280,9 +280,8 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \ core/sys/linux/sys/procfs.d core/sys/linux/sys/signalfd.d \ core/sys/linux/sys/socket.d core/sys/linux/sys/sysinfo.d \ core/sys/linux/sys/time.d core/sys/linux/sys/xattr.d \ - core/sys/linux/syscalls.d core/sys/linux/termios.d \ - core/sys/linux/time.d core/sys/linux/timerfd.d core/sys/linux/tipc.d \ - core/sys/linux/unistd.d + core/sys/linux/termios.d core/sys/linux/time.d \ + core/sys/linux/timerfd.d core/sys/linux/tipc.d core/sys/linux/unistd.d DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \ core/sys/netbsd/err.d core/sys/netbsd/execinfo.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 84be808..bb936dd 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -367,9 +367,9 @@ am__objects_18 = core/sys/linux/config.lo core/sys/linux/dlfcn.lo \ core/sys/linux/sys/procfs.lo core/sys/linux/sys/signalfd.lo \ core/sys/linux/sys/socket.lo core/sys/linux/sys/sysinfo.lo \ core/sys/linux/sys/time.lo core/sys/linux/sys/xattr.lo \ - core/sys/linux/syscalls.lo core/sys/linux/termios.lo \ - core/sys/linux/time.lo core/sys/linux/timerfd.lo \ - core/sys/linux/tipc.lo core/sys/linux/unistd.lo + core/sys/linux/termios.lo core/sys/linux/time.lo \ + core/sys/linux/timerfd.lo core/sys/linux/tipc.lo \ + core/sys/linux/unistd.lo @DRUNTIME_OS_LINUX_TRUE@am__objects_19 = $(am__objects_18) am__objects_20 = core/sys/windows/accctrl.lo \ core/sys/windows/aclapi.lo core/sys/windows/aclui.lo \ @@ -944,9 +944,8 @@ DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \ core/sys/linux/sys/procfs.d core/sys/linux/sys/signalfd.d \ core/sys/linux/sys/socket.d core/sys/linux/sys/sysinfo.d \ core/sys/linux/sys/time.d core/sys/linux/sys/xattr.d \ - core/sys/linux/syscalls.d core/sys/linux/termios.d \ - core/sys/linux/time.d core/sys/linux/timerfd.d core/sys/linux/tipc.d \ - core/sys/linux/unistd.d + core/sys/linux/termios.d core/sys/linux/time.d \ + core/sys/linux/timerfd.d core/sys/linux/tipc.d core/sys/linux/unistd.d DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \ core/sys/netbsd/err.d core/sys/netbsd/execinfo.d \ @@ -1675,7 +1674,6 @@ core/sys/linux/sys/socket.lo: core/sys/linux/sys/$(am__dirstamp) core/sys/linux/sys/sysinfo.lo: core/sys/linux/sys/$(am__dirstamp) core/sys/linux/sys/time.lo: core/sys/linux/sys/$(am__dirstamp) core/sys/linux/sys/xattr.lo: core/sys/linux/sys/$(am__dirstamp) -core/sys/linux/syscalls.lo: core/sys/linux/$(am__dirstamp) core/sys/linux/termios.lo: core/sys/linux/$(am__dirstamp) core/sys/linux/time.lo: core/sys/linux/$(am__dirstamp) core/sys/linux/timerfd.lo: core/sys/linux/$(am__dirstamp) diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d index 33ca0ddc..1915fb0 100644 --- a/libphobos/libdruntime/core/demangle.d +++ b/libphobos/libdruntime/core/demangle.d @@ -54,13 +54,13 @@ pure @safe: enum AddType { no, yes } - this( return const(char)[] buf_, return char[] dst_ = null ) + this( return scope const(char)[] buf_, return scope char[] dst_ = null ) { this( buf_, AddType.yes, dst_ ); } - this( return const(char)[] buf_, AddType addType_, return char[] dst_ = null ) + this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null ) { buf = buf_; addType = addType_; @@ -105,7 +105,7 @@ pure @safe: //throw new ParseException( msg ); debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); throw __ctfe ? new ParseException(msg) - : cast(ParseException) cast(void*) typeid(ParseException).initializer; + : cast(ParseException) __traits(initSymbol, ParseException).ptr; } @@ -116,7 +116,7 @@ pure @safe: //throw new OverflowException( msg ); debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); - throw cast(OverflowException) cast(void*) typeid(OverflowException).initializer; + throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr; } diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d index 9c82237..ae71f51 100644 --- a/libphobos/libdruntime/core/internal/array/construction.d +++ b/libphobos/libdruntime/core/internal/array/construction.d @@ -14,16 +14,27 @@ import core.internal.traits : Unqual; /** * Does array initialization (not assignment) from another array of the same element type. * Params: + * to = what array to initialize * from = what data the array should be initialized with + * makeWeaklyPure = unused; its purpose is to prevent the function from becoming + * strongly pure and risk being optimised out * Returns: * The created and initialized array `to` * Bugs: * This function template was ported from a much older runtime hook that bypassed safety, * purity, and throwabilty checks. To prevent breaking existing code, this function template * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations. + * + * The third parameter is never used, but is necessary in order for the + * function be treated as weakly pure, instead of strongly pure. + * This is needed because constructions such as the one below can be ignored by + * the compiler if `_d_arrayctor` is believed to be pure, because purity would + * mean the call to `_d_arrayctor` has no effects (no side effects and the + * return value is ignored), despite it actually modifying the contents of `a`. + * const S[2] b; + * const S[2] a = b; // this would get lowered to _d_arrayctor(a, b) */ -Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @trusted - if (is(Unqual!T1 == Unqual!T2)) +Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* makeWeaklyPure = null) @trusted { pragma(inline, false); import core.internal.traits : hasElaborateCopyConstructor; @@ -32,14 +43,12 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste import core.stdc.stdint : uintptr_t; debug(PRINTF) import core.stdc.stdio : printf; - debug(PRINTF) printf("_d_arrayctor(to = %p,%d, from = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, T1.tsize); + debug(PRINTF) printf("_d_arrayctor(from = %p,%d) size = %d\n", from.ptr, from.length, T.sizeof); - Tarr1 to = void; + void[] vFrom = (cast(void*) from.ptr)[0..from.length]; + void[] vTo = (cast(void*) to.ptr)[0..to.length]; - void[] vFrom = (cast(void*)from.ptr)[0..from.length]; - void[] vTo = (cast(void*)to.ptr)[0..to.length]; - - // Force `enforceRawArraysConformable` to be `pure` + // Force `enforceRawArraysConformable` to remain weakly `pure` void enforceRawArraysConformable(const char[] action, const size_t elementSize, const void[] a1, const void[] a2) @trusted { @@ -50,9 +59,9 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste (cast(Type)&enforceRawArraysConformableNogc)(action, elementSize, a1, a2, false); } - enforceRawArraysConformable("initialization", T1.sizeof, vFrom, vTo); + enforceRawArraysConformable("initialization", T.sizeof, vFrom, vTo); - static if (hasElaborateCopyConstructor!T1) + static if (hasElaborateCopyConstructor!T) { size_t i; try @@ -66,7 +75,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste */ while (i--) { - auto elem = cast(Unqual!T1*)&to[i]; + auto elem = cast(Unqual!T*) &to[i]; destroy(*elem); } @@ -76,7 +85,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste else { // blit all elements at once - memcpy(cast(void*) to.ptr, from.ptr, to.length * T1.sizeof); + memcpy(cast(void*) to.ptr, from.ptr, to.length * T.sizeof); } return to; @@ -94,7 +103,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste S[4] arr1; S[4] arr2 = [S(0), S(1), S(2), S(3)]; - arr1 = _d_arrayctor!(typeof(arr1))(arr2[]); + _d_arrayctor(arr1[], arr2[]); assert(counter == 4); assert(arr1 == arr2); @@ -117,7 +126,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste S[4] arr1; S[4] arr2 = [S(0), S(1), S(2), S(3)]; - arr1 = _d_arrayctor!(typeof(arr1))(arr2[]); + _d_arrayctor(arr1[], arr2[]); assert(counter == 4); assert(arr1 == arr2); @@ -143,7 +152,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste { Throw[4] a; Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; - a = _d_arrayctor!(typeof(a))(b[]); + _d_arrayctor(a[], b[]); } catch (Exception) { @@ -168,7 +177,7 @@ Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @truste { NoThrow[4] a; NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)]; - a = _d_arrayctor!(typeof(a))(b[]); + _d_arrayctor(a[], b[]); } catch (Exception) { @@ -274,7 +283,7 @@ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted { Throw[4] a; Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; - a = _d_arrayctor!(typeof(a))(b[]); + _d_arrayctor(a[], b[]); } catch (Exception) { diff --git a/libphobos/libdruntime/core/internal/convert.d b/libphobos/libdruntime/core/internal/convert.d index 2789d29..a876fcc 100644 --- a/libphobos/libdruntime/core/internal/convert.d +++ b/libphobos/libdruntime/core/internal/convert.d @@ -801,7 +801,7 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == delegate) || is(T : V*, V } @trusted pure nothrow @nogc -const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == struct) || is(T == union)) +const(ubyte)[] toUbyte(T)(const return ref scope T val) if (is(T == struct) || is(T == union)) { if (__ctfe) { @@ -826,7 +826,11 @@ const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == struct) || i } else { - return (cast(const(ubyte)*)&val)[0 .. T.sizeof]; + // We're escaping a reference to `val` here because we cannot express + // ref return + scope, it's currently seen as ref + return scope + // https://issues.dlang.org/show_bug.cgi?id=22541 + // Once fixed, the @system lambda should be removed + return (() @system => (cast(const(ubyte)*)&val)[0 .. T.sizeof])(); } } diff --git a/libphobos/libdruntime/core/internal/lifetime.d b/libphobos/libdruntime/core/internal/lifetime.d index 7e9b5f2..a7446de 100644 --- a/libphobos/libdruntime/core/internal/lifetime.d +++ b/libphobos/libdruntime/core/internal/lifetime.d @@ -89,44 +89,35 @@ Emplaces T.init. In contrast to `emplaceRef(chunk)`, there are no checks for disabled default constructors etc. +/ -template emplaceInitializer(T) +void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted if (!is(T == const) && !is(T == immutable) && !is(T == inout)) { - import core.internal.traits : hasElaborateAssign, Unqual; + import core.internal.traits : hasElaborateAssign; - // Avoid stack allocation by hacking to get to the struct/union init symbol. - static if (is(T == struct) || is(T == union)) + static if (__traits(isZeroInit, T)) { - pragma(mangle, "_D" ~ Unqual!T.mangleof[1..$] ~ "6__initZ") - __gshared extern immutable T initializer; + import core.stdc.string : memset; + memset(cast(void*) &chunk, 0, T.sizeof); } - - void emplaceInitializer(scope ref T chunk) nothrow pure @trusted + else static if (__traits(isScalar, T) || + T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; })) { - static if (__traits(isZeroInit, T)) - { - import core.stdc.string : memset; - memset(cast(void*) &chunk, 0, T.sizeof); - } - else static if (__traits(isScalar, T) || - T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; })) - { - chunk = T.init; - } - else static if (__traits(isStaticArray, T)) - { - // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one. - foreach (i; 0 .. T.length) - { - emplaceInitializer(chunk[i]); - } - } - else + chunk = T.init; + } + else static if (__traits(isStaticArray, T)) + { + // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one. + foreach (i; 0 .. T.length) { - import core.stdc.string : memcpy; - memcpy(cast(void*)&chunk, &initializer, T.sizeof); + emplaceInitializer(chunk[i]); } } + else + { + import core.stdc.string : memcpy; + const initializer = __traits(initSymbol, T); + memcpy(cast(void*)&chunk, initializer.ptr, initializer.length); + } } @safe unittest diff --git a/libphobos/libdruntime/core/internal/string.d b/libphobos/libdruntime/core/internal/string.d index 529fee4..64a9cc9 100644 --- a/libphobos/libdruntime/core/internal/string.d +++ b/libphobos/libdruntime/core/internal/string.d @@ -119,7 +119,7 @@ char[] signedToTempString(uint radix = 10)(long value, return scope char[] buf) if (neg) { // about to do a slice without a bounds check - auto trustedSlice(return char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; } + auto trustedSlice(return scope char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; } r = trustedSlice(r); r[0] = '-'; } diff --git a/libphobos/libdruntime/core/internal/utf.d b/libphobos/libdruntime/core/internal/utf.d index ca0f7f5..27bf7f2b 100644 --- a/libphobos/libdruntime/core/internal/utf.d +++ b/libphobos/libdruntime/core/internal/utf.d @@ -583,7 +583,7 @@ void validate(S)(const scope S s) /* =================== Conversion to UTF8 ======================= */ @safe pure nothrow @nogc -char[] toUTF8(return char[] buf, dchar c) +char[] toUTF8(return scope char[] buf, dchar c) in { assert(isValidDchar(c)); @@ -623,7 +623,7 @@ char[] toUTF8(return char[] buf, dchar c) * Encodes string s into UTF-8 and returns the encoded string. */ @safe pure nothrow -string toUTF8(return string s) +string toUTF8(return scope string s) in { validate(s); @@ -692,7 +692,7 @@ string toUTF8(const scope dchar[] s) /* =================== Conversion to UTF16 ======================= */ @safe pure nothrow @nogc -wchar[] toUTF16(return wchar[] buf, dchar c) +wchar[] toUTF16(return scope wchar[] buf, dchar c) in { assert(isValidDchar(c)); @@ -784,7 +784,7 @@ wptr toUTF16z(const scope char[] s) /** ditto */ @safe pure nothrow -wstring toUTF16(return wstring s) +wstring toUTF16(return scope wstring s) in { validate(s); @@ -864,7 +864,7 @@ dstring toUTF32(const scope wchar[] s) /** ditto */ @safe pure nothrow -dstring toUTF32(return dstring s) +dstring toUTF32(return scope dstring s) in { validate(s); diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index d93b891..b45e95f 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -103,8 +103,8 @@ T emplace(T, Args...)(T chunk, auto ref Args args) " is abstract and it can't be emplaced"); // Initialize the object in its pre-ctor state - enum classSize = __traits(classInstanceSize, T); - (() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])(); + const initializer = __traits(initSymbol, T); + (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })(); static if (isInnerClass!T) { @@ -224,6 +224,31 @@ T emplace(T, Args...)(void[] chunk, auto ref Args args) assert(c.i == 5); } +/// +@betterC +@nogc pure nothrow @system unittest +{ + // works with -betterC too: + + static extern (C++) class C + { + @nogc pure nothrow @safe: + int i = 3; + this(int i) + { + assert(this.i == 3); + this.i = i; + } + int virtualGetI() { return i; } + } + + import core.internal.traits : classInstanceAlignment; + + align(classInstanceAlignment!C) byte[__traits(classInstanceSize, C)] buffer; + C c = emplace!C(buffer[], 42); + assert(c.virtualGetI() == 42); +} + @system unittest { class Outer @@ -1921,7 +1946,7 @@ private void moveImpl(T)(scope ref T target, return scope ref T source) static if (is(T == struct)) { - // Unsafe when compiling without -dip1000 + // Unsafe when compiling without -preview=dip1000 if ((() @trusted => &source == &target)()) return; // Destroy target before overwriting it static if (hasElaborateDestructor!T) target.__xdtor(); @@ -2099,7 +2124,7 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source) static if (is(T == struct)) { - // Unsafe when compiling without -dip1000 + // Unsafe when compiling without -preview=dip1000 assert((() @trusted => &source !is &target)(), "source and target must not be identical"); static if (hasElaborateAssign!T || !isAssignable!T) @@ -2123,12 +2148,7 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source) static if (__traits(isZeroInit, T)) () @trusted { memset(&source, 0, sz); }(); else - { - import core.internal.lifetime : emplaceInitializer; - ubyte[T.sizeof] init = void; - emplaceInitializer(*(() @trusted { return cast(T*)init.ptr; }())); - () @trusted { memcpy(&source, init.ptr, sz); }(); - } + () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }(); } } else static if (__traits(isStaticArray, T)) @@ -2201,3 +2221,74 @@ pure nothrow @nogc @system unittest static assert(!__traits(compiles, f(ncarray))); f(move(ncarray)); } + +/** + * This is called for a delete statement where the value + * being deleted is a pointer to a struct with a destructor + * but doesn't have an overloaded delete operator. + * + * Params: + * p = pointer to the value to be deleted + */ +void _d_delstruct(T)(ref T *p) +{ + if (p) + { + debug(PRINTF) printf("_d_delstruct(%p)\n", p); + + import core.memory : GC; + + destroy(*p); + GC.free(p); + p = null; + } +} + +@system unittest +{ + int dtors = 0; + struct S { ~this() { ++dtors; } } + + S *s = new S(); + _d_delstruct(s); + + assert(s == null); + assert(dtors == 1); +} + +@system unittest +{ + int innerDtors = 0; + int outerDtors = 0; + + struct Inner { ~this() { ++innerDtors; } } + struct Outer + { + Inner *i1; + Inner *i2; + + this(int x) + { + i1 = new Inner(); + i2 = new Inner(); + } + + ~this() + { + ++outerDtors; + + _d_delstruct(i1); + assert(i1 == null); + + _d_delstruct(i2); + assert(i2 == null); + } + } + + Outer *o = new Outer(0); + _d_delstruct(o); + + assert(o == null); + assert(innerDtors == 2); + assert(outerDtors == 1); +} diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d index 3770c13..c4df0f2 100644 --- a/libphobos/libdruntime/core/memory.d +++ b/libphobos/libdruntime/core/memory.d @@ -270,7 +270,7 @@ extern(C): * reentrant, and must be called once for every call to disable before * automatic collections are enabled. */ - pragma(mangle, "gc_enable") static void enable() nothrow; /* FIXME pure */ + pragma(mangle, "gc_enable") static void enable() nothrow pure; /** @@ -280,7 +280,7 @@ extern(C): * such as during an out of memory condition. This function is reentrant, * but enable must be called once for each call to disable. */ - pragma(mangle, "gc_disable") static void disable() nothrow; /* FIXME pure */ + pragma(mangle, "gc_disable") static void disable() nothrow pure; /** @@ -290,14 +290,14 @@ extern(C): * and then to reclaim free space. This action may need to suspend all * running threads for at least part of the collection process. */ - pragma(mangle, "gc_collect") static void collect() nothrow; /* FIXME pure */ + pragma(mangle, "gc_collect") static void collect() nothrow pure; /** * Indicates that the managed memory space be minimized by returning free * physical memory to the operating system. The amount of free memory * returned depends on the allocator design and on program behavior. */ - pragma(mangle, "gc_minimize") static void minimize() nothrow; /* FIXME pure */ + pragma(mangle, "gc_minimize") static void minimize() nothrow pure; extern(D): @@ -551,7 +551,7 @@ extern(C): * Throws: * `OutOfMemoryError` on allocation failure. */ - pragma(mangle, "gc_realloc") static void* realloc(return void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow; + pragma(mangle, "gc_realloc") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow; // https://issues.dlang.org/show_bug.cgi?id=13111 /// @@ -635,7 +635,7 @@ extern(C): * Returns: * The actual number of bytes reserved or zero on error. */ - pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow; /* FIXME pure */ + pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow pure; /** @@ -807,7 +807,7 @@ extern(C): * } * --- */ - pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc; /* FIXME pure */ + pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc pure; /** @@ -818,7 +818,7 @@ extern(C): * Params: * p = A pointer into a GC-managed memory block or null. */ - pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc; /* FIXME pure */ + pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc pure; /** @@ -849,7 +849,8 @@ extern(C): * // rawMemory will be recognized on collection. * --- */ - pragma(mangle, "gc_addRange") static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow; /* FIXME pure */ + pragma(mangle, "gc_addRange") + static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow pure; /** @@ -861,7 +862,7 @@ extern(C): * Params: * p = A pointer to a valid memory address or to null. */ - pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc; /* FIXME pure */ + pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc pure; /** diff --git a/libphobos/libdruntime/core/stdc/stdlib.d b/libphobos/libdruntime/core/stdc/stdlib.d index 2f11a66..92f8f70 100644 --- a/libphobos/libdruntime/core/stdc/stdlib.d +++ b/libphobos/libdruntime/core/stdc/stdlib.d @@ -26,6 +26,10 @@ else version (TVOS) else version (WatchOS) version = Darwin; +version (CRuntime_Glibc) + version = AlignedAllocSupported; +else {} + extern (C): @system: @@ -166,6 +170,12 @@ void* realloc(void* ptr, size_t size); /// void free(void* ptr); +/// since C11 +version (AlignedAllocSupported) +{ + void* aligned_alloc(size_t alignment, size_t size); +} + /// noreturn abort() @safe; /// diff --git a/libphobos/libdruntime/core/stdc/string.d b/libphobos/libdruntime/core/stdc/string.d index a26811c..f15ef85 100644 --- a/libphobos/libdruntime/core/stdc/string.d +++ b/libphobos/libdruntime/core/stdc/string.d @@ -35,31 +35,31 @@ nothrow: @nogc: /// -inout(void)* memchr(return inout void* s, int c, size_t n) pure; +inout(void)* memchr(return scope inout void* s, int c, size_t n) pure; /// int memcmp(scope const void* s1, scope const void* s2, size_t n) pure; /// -void* memcpy(return void* s1, scope const void* s2, size_t n) pure; +void* memcpy(return scope void* s1, scope const void* s2, size_t n) pure; version (Windows) { /// int memicmp(scope const char* s1, scope const char* s2, size_t n); } /// -void* memmove(return void* s1, scope const void* s2, size_t n) pure; +void* memmove(return scope void* s1, scope const void* s2, size_t n) pure; /// -void* memset(return void* s, int c, size_t n) pure; +void* memset(return scope void* s, int c, size_t n) pure; /// -char* strcat(return char* s1, scope const char* s2) pure; +char* strcat(return scope char* s1, scope const char* s2) pure; /// -inout(char)* strchr(return inout(char)* s, int c) pure; +inout(char)* strchr(return scope inout(char)* s, int c) pure; /// int strcmp(scope const char* s1, scope const char* s2) pure; /// int strcoll(scope const char* s1, scope const char* s2); /// -char* strcpy(return char* s1, scope const char* s2) pure; +char* strcpy(return scope char* s1, scope const char* s2) pure; /// size_t strcspn(scope const char* s1, scope const char* s2) pure; /// @@ -70,7 +70,7 @@ char* strerror(int errnum); version (ReturnStrerrorR) { /// - const(char)* strerror_r(int errnum, return char* buf, size_t buflen); + const(char)* strerror_r(int errnum, return scope char* buf, size_t buflen); } // This one is else @@ -80,20 +80,20 @@ else /// size_t strlen(scope const char* s) pure; /// -char* strncat(return char* s1, scope const char* s2, size_t n) pure; +char* strncat(return scope char* s1, scope const char* s2, size_t n) pure; /// int strncmp(scope const char* s1, scope const char* s2, size_t n) pure; /// -char* strncpy(return char* s1, scope const char* s2, size_t n) pure; +char* strncpy(return scope char* s1, scope const char* s2, size_t n) pure; /// -inout(char)* strpbrk(return inout(char)* s1, scope const char* s2) pure; +inout(char)* strpbrk(return scope inout(char)* s1, scope const char* s2) pure; /// -inout(char)* strrchr(return inout(char)* s, int c) pure; +inout(char)* strrchr(return scope inout(char)* s, int c) pure; /// size_t strspn(scope const char* s1, scope const char* s2) pure; /// -inout(char)* strstr(return inout(char)* s1, scope const char* s2) pure; +inout(char)* strstr(return scope inout(char)* s1, scope const char* s2) pure; /// -char* strtok(return char* s1, scope const char* s2); +char* strtok(return scope char* s1, scope const char* s2); /// size_t strxfrm(scope char* s1, scope const char* s2, size_t n); diff --git a/libphobos/libdruntime/core/stdc/wchar_.d b/libphobos/libdruntime/core/stdc/wchar_.d index 6da5618..e8fb94b 100644 --- a/libphobos/libdruntime/core/stdc/wchar_.d +++ b/libphobos/libdruntime/core/stdc/wchar_.d @@ -213,13 +213,13 @@ c_ulong wcstoul(const scope wchar_t* nptr, wchar_t** endptr, int base); ulong wcstoull(const scope wchar_t* nptr, wchar_t** endptr, int base); /// -pure wchar_t* wcscpy(return wchar_t* s1, scope const wchar_t* s2); +pure wchar_t* wcscpy(return scope wchar_t* s1, scope const wchar_t* s2); /// -pure wchar_t* wcsncpy(return wchar_t* s1, scope const wchar_t* s2, size_t n); +pure wchar_t* wcsncpy(return scope wchar_t* s1, scope const wchar_t* s2, size_t n); /// -pure wchar_t* wcscat(return wchar_t* s1, scope const wchar_t* s2); +pure wchar_t* wcscat(return scope wchar_t* s1, scope const wchar_t* s2); /// -pure wchar_t* wcsncat(return wchar_t* s1, scope const wchar_t* s2, size_t n); +pure wchar_t* wcsncat(return scope wchar_t* s1, scope const wchar_t* s2, size_t n); /// pure int wcscmp(scope const wchar_t* s1, scope const wchar_t* s2); /// @@ -229,32 +229,32 @@ pure int wcsncmp(scope const wchar_t* s1, scope const wchar_t* s2, size_t n); /// size_t wcsxfrm(scope wchar_t* s1, scope const wchar_t* s2, size_t n); /// -pure inout(wchar_t)* wcschr(return inout(wchar_t)* s, wchar_t c); +pure inout(wchar_t)* wcschr(return scope inout(wchar_t)* s, wchar_t c); /// pure size_t wcscspn(scope const wchar_t* s1, scope const wchar_t* s2); /// -pure inout(wchar_t)* wcspbrk(return inout(wchar_t)* s1, scope const wchar_t* s2); +pure inout(wchar_t)* wcspbrk(return scope inout(wchar_t)* s1, scope const wchar_t* s2); /// -pure inout(wchar_t)* wcsrchr(return inout(wchar_t)* s, wchar_t c); +pure inout(wchar_t)* wcsrchr(return scope inout(wchar_t)* s, wchar_t c); /// pure size_t wcsspn(scope const wchar_t* s1, scope const wchar_t* s2); /// -pure inout(wchar_t)* wcsstr(return inout(wchar_t)* s1, scope const wchar_t* s2); +pure inout(wchar_t)* wcsstr(return scope inout(wchar_t)* s1, scope const wchar_t* s2); /// -wchar_t* wcstok(return wchar_t* s1, scope const wchar_t* s2, wchar_t** ptr); +wchar_t* wcstok(return scope wchar_t* s1, scope const wchar_t* s2, wchar_t** ptr); /// pure size_t wcslen(scope const wchar_t* s); /// -pure inout(wchar_t)* wmemchr(return inout wchar_t* s, wchar_t c, size_t n); +pure inout(wchar_t)* wmemchr(return scope inout wchar_t* s, wchar_t c, size_t n); /// pure int wmemcmp(scope const wchar_t* s1, scope const wchar_t* s2, size_t n); /// -pure wchar_t* wmemcpy(return wchar_t* s1, scope const wchar_t* s2, size_t n); +pure wchar_t* wmemcpy(return scope wchar_t* s1, scope const wchar_t* s2, size_t n); /// -pure wchar_t* wmemmove(return wchar_t* s1, scope const wchar_t* s2, size_t n); +pure wchar_t* wmemmove(return scope wchar_t* s1, scope const wchar_t* s2, size_t n); /// -pure wchar_t* wmemset(return wchar_t* s, wchar_t c, size_t n); +pure wchar_t* wmemset(return scope wchar_t* s, wchar_t c, size_t n); /// size_t wcsftime(wchar_t* s, size_t maxsize, const scope wchar_t* format, const scope tm* timeptr); diff --git a/libphobos/libdruntime/core/stdcpp/exception.d b/libphobos/libdruntime/core/stdcpp/exception.d index f920057..d65cd8d 100644 --- a/libphobos/libdruntime/core/stdcpp/exception.d +++ b/libphobos/libdruntime/core/stdcpp/exception.d @@ -19,6 +19,8 @@ version (CppRuntime_Gcc) version = GenericBaseException; version (CppRuntime_Clang) version = GenericBaseException; +version (CppRuntime_Sun) + version = GenericBaseException; extern (C++, "std"): @nogc: diff --git a/libphobos/libdruntime/core/sync/mutex.d b/libphobos/libdruntime/core/sync/mutex.d index b153ab9..b848a14 100644 --- a/libphobos/libdruntime/core/sync/mutex.d +++ b/libphobos/libdruntime/core/sync/mutex.d @@ -189,7 +189,7 @@ class Mutex : if (pthread_mutex_lock(&m_hndl) == 0) return; - SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; + SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr; syncErr.msg = "Unable to lock mutex."; throw syncErr; } @@ -227,7 +227,7 @@ class Mutex : if (pthread_mutex_unlock(&m_hndl) == 0) return; - SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer; + SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr; syncErr.msg = "Unable to unlock mutex."; throw syncErr; } diff --git a/libphobos/libdruntime/core/sys/bionic/string.d b/libphobos/libdruntime/core/sys/bionic/string.d index cbee06c..10a5610 100644 --- a/libphobos/libdruntime/core/sys/bionic/string.d +++ b/libphobos/libdruntime/core/sys/bionic/string.d @@ -14,4 +14,4 @@ extern (C): nothrow: @nogc: -pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); +pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); diff --git a/libphobos/libdruntime/core/sys/darwin/mach/nlist.d b/libphobos/libdruntime/core/sys/darwin/mach/nlist.d index 11e5ced..4d400f2 100644 --- a/libphobos/libdruntime/core/sys/darwin/mach/nlist.d +++ b/libphobos/libdruntime/core/sys/darwin/mach/nlist.d @@ -222,7 +222,7 @@ enum */ ubyte GET_LIBRARY_ORDINAL(uint n_desc) @safe { return ((n_desc) >> 8) & 0xff; } /// Ditto -ref ushort SET_LIBRARY_ORDINAL(return scope ref ushort n_desc, uint ordinal) @safe +ref ushort SET_LIBRARY_ORDINAL(return ref ushort n_desc, uint ordinal) @safe { return n_desc = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8)); } diff --git a/libphobos/libdruntime/core/sys/darwin/string.d b/libphobos/libdruntime/core/sys/darwin/string.d index bd65fde..ac988b5 100644 --- a/libphobos/libdruntime/core/sys/darwin/string.d +++ b/libphobos/libdruntime/core/sys/darwin/string.d @@ -27,5 +27,5 @@ nothrow: static if (__DARWIN_C_LEVEL >= __DARWIN_C_FULL) { // ^ __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); - pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); + pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); } diff --git a/libphobos/libdruntime/core/sys/dragonflybsd/string.d b/libphobos/libdruntime/core/sys/dragonflybsd/string.d index b64178f..4b84227 100644 --- a/libphobos/libdruntime/core/sys/dragonflybsd/string.d +++ b/libphobos/libdruntime/core/sys/dragonflybsd/string.d @@ -17,6 +17,6 @@ nothrow: static if (__BSD_VISIBLE) { - pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); + pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); } diff --git a/libphobos/libdruntime/core/sys/freebsd/string.d b/libphobos/libdruntime/core/sys/freebsd/string.d index 3602ea8..459e911 100644 --- a/libphobos/libdruntime/core/sys/freebsd/string.d +++ b/libphobos/libdruntime/core/sys/freebsd/string.d @@ -17,5 +17,5 @@ nothrow: static if (__BSD_VISIBLE) { - pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); + pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); } diff --git a/libphobos/libdruntime/core/sys/linux/string.d b/libphobos/libdruntime/core/sys/linux/string.d index 1b2c8d8..e3c94cf6 100644 --- a/libphobos/libdruntime/core/sys/linux/string.d +++ b/libphobos/libdruntime/core/sys/linux/string.d @@ -18,5 +18,5 @@ nothrow: static if (__USE_GNU) { - pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); + pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); } diff --git a/libphobos/libdruntime/core/sys/linux/syscalls.d b/libphobos/libdruntime/core/sys/linux/syscalls.d deleted file mode 100644 index 8c65371..0000000 --- a/libphobos/libdruntime/core/sys/linux/syscalls.d +++ /dev/null @@ -1,745 +0,0 @@ -module core.sys.linux.syscalls; - -version (linux): -extern (C): -@system: -nothrow: -@nogc: - -import core.stdc.config : c_long; - -version (CoreDdoc) -{ - /// Linux system call number from Linux's asm/unistd.h - enum SystemCall : c_long; -} -else version (X86_64) -{ - // https://github.com/torvalds/linux/blob/v4.14/arch/sh/include/uapi/asm/unistd_64.h - // https://github.com/torvalds/linux/blob/v4.14/arch/x86/entry/syscalls/syscall_64.tbl - enum SystemCall : c_long - { - read = 0, - write = 1, - open = 2, - close = 3, - stat = 4, - fstat = 5, - lstat = 6, - poll = 7, - lseek = 8, - mmap = 9, - mprotect = 10, - munmap = 11, - brk = 12, - rt_sigaction = 13, - rt_sigprocmask = 14, - rt_sigreturn = 15, - ioctl = 16, - pread64 = 17, - pwrite64 = 18, - readv = 19, - writev = 20, - access = 21, - pipe = 22, - select = 23, - sched_yield = 24, - mremap = 25, - msync = 26, - mincore = 27, - madvise = 28, - shmget = 29, - shmat = 30, - shmctl = 31, - dup = 32, - dup2 = 33, - pause = 34, - nanosleep = 35, - getitimer = 36, - alarm = 37, - setitimer = 38, - getpid = 39, - sendfile = 40, - socket = 41, - connect = 42, - accept = 43, - sendto = 44, - recvfrom = 45, - sendmsg = 46, - recvmsg = 47, - shutdown = 48, - bind = 49, - listen = 50, - getsockname = 51, - getpeername = 52, - socketpair = 53, - setsockopt = 54, - getsockopt = 55, - clone = 56, - fork = 57, - vfork = 58, - execve = 59, - exit = 60, - wait4 = 61, - kill = 62, - uname = 63, - semget = 64, - semop = 65, - semctl = 66, - shmdt = 67, - msgget = 68, - msgsnd = 69, - msgrcv = 70, - msgctl = 71, - fcntl = 72, - flock = 73, - fsync = 74, - fdatasync = 75, - truncate = 76, - ftruncate = 77, - getdents = 78, - getcwd = 79, - chdir = 80, - fchdir = 81, - rename = 82, - mkdir = 83, - rmdir = 84, - creat = 85, - link = 86, - unlink = 87, - symlink = 88, - readlink = 89, - chmod = 90, - fchmod = 91, - chown = 92, - fchown = 93, - lchown = 94, - umask = 95, - gettimeofday = 96, - getrlimit = 97, - getrusage = 98, - sysinfo = 99, - times = 100, - ptrace = 101, - getuid = 102, - syslog = 103, - getgid = 104, - setuid = 105, - setgid = 106, - geteuid = 107, - getegid = 108, - setpgid = 109, - getppid = 110, - getpgrp = 111, - setsid = 112, - setreuid = 113, - setregid = 114, - getgroups = 115, - setgroups = 116, - setresuid = 117, - getresuid = 118, - setresgid = 119, - getresgid = 120, - getpgid = 121, - setfsuid = 122, - setfsgid = 123, - getsid = 124, - capget = 125, - capset = 126, - rt_sigpending = 127, - rt_sigtimedwait = 128, - rt_sigqueueinfo = 129, - rt_sigsuspend = 130, - sigaltstack = 131, - utime = 132, - mknod = 133, - uselib = 134, - personality = 135, - ustat = 136, - statfs = 137, - fstatfs = 138, - sysfs = 139, - getpriority = 140, - setpriority = 141, - sched_setparam = 142, - sched_getparam = 143, - sched_setscheduler = 144, - sched_getscheduler = 145, - sched_get_priority_max = 146, - sched_get_priority_min = 147, - sched_rr_get_interval = 148, - mlock = 149, - munlock = 150, - mlockall = 151, - munlockall = 152, - vhangup = 153, - modify_ldt = 154, - pivot_root = 155, - _sysctl = 156, - prctl = 157, - arch_prctl = 158, - adjtimex = 159, - setrlimit = 160, - chroot = 161, - sync = 162, - acct = 163, - settimeofday = 164, - mount = 165, - umount2 = 166, - swapon = 167, - swapoff = 168, - reboot = 169, - sethostname = 170, - setdomainname = 171, - iopl = 172, - ioperm = 173, - create_module = 174, - init_module = 175, - delete_module = 176, - get_kernel_syms = 177, - query_module = 178, - quotactl = 179, - nfsservctl = 180, - getpmsg = 181, - putpmsg = 182, - afs_syscall = 183, - tuxcall = 184, - security = 185, - gettid = 186, - readahead = 187, - setxattr = 188, - lsetxattr = 189, - fsetxattr = 190, - getxattr = 191, - lgetxattr = 192, - fgetxattr = 193, - listxattr = 194, - llistxattr = 195, - flistxattr = 196, - removexattr = 197, - lremovexattr = 198, - fremovexattr = 199, - tkill = 200, - time = 201, - futex = 202, - sched_setaffinity = 203, - sched_getaffinity = 204, - set_thread_area = 205, - io_setup = 206, - io_destroy = 207, - io_getevents = 208, - io_submit = 209, - io_cancel = 210, - get_thread_area = 211, - lookup_dcookie = 212, - epoll_create = 213, - epoll_ctl_old = 214, - epoll_wait_old = 215, - remap_file_pages = 216, - getdents64 = 217, - set_tid_address = 218, - restart_syscall = 219, - semtimedop = 220, - fadvise64 = 221, - timer_create = 222, - timer_settime = 223, - timer_gettime = 224, - timer_getoverrun = 225, - timer_delete = 226, - clock_settime = 227, - clock_gettime = 228, - clock_getres = 229, - clock_nanosleep = 230, - exit_group = 231, - epoll_wait = 232, - epoll_ctl = 233, - tgkill = 234, - utimes = 235, - vserver = 236, - mbind = 237, - set_mempolicy = 238, - get_mempolicy = 239, - mq_open = 240, - mq_unlink = 241, - mq_timedsend = 242, - mq_timedreceive = 243, - mq_notify = 244, - mq_getsetattr = 245, - kexec_load = 246, - waitid = 247, - add_key = 248, - request_key = 249, - keyctl = 250, - ioprio_set = 251, - ioprio_get = 252, - inotify_init = 253, - inotify_add_watch = 254, - inotify_rm_watch = 255, - migrate_pages = 256, - openat = 257, - mkdirat = 258, - mknodat = 259, - fchownat = 260, - futimesat = 261, - newfstatat = 262, - unlinkat = 263, - renameat = 264, - linkat = 265, - symlinkat = 266, - readlinkat = 267, - fchmodat = 268, - faccessat = 269, - pselect6 = 270, - ppoll = 271, - unshare = 272, - set_robust_list = 273, - get_robust_list = 274, - splice = 275, - tee = 276, - sync_file_range = 277, - vmsplice = 278, - move_pages = 279, - utimensat = 280, - epoll_pwait = 281, - signalfd = 282, - timerfd_create = 283, - eventfd = 284, - fallocate = 285, - timerfd_settime = 286, - timerfd_gettime = 287, - accept4 = 288, - signalfd4 = 289, - eventfd2 = 290, - epoll_create1 = 291, - dup3 = 292, - pipe2 = 293, - inotify_init1 = 294, - preadv = 295, - pwritev = 296, - rt_tgsigqueueinfo = 297, - perf_event_open = 298, - recvmmsg = 299, - fanotify_init = 300, - fanotify_mark = 301, - prlimit64 = 302, - name_to_handle_at = 303, - open_by_handle_at = 304, - clock_adjtime = 305, - syncfs = 306, - sendmmsg = 307, - setns = 308, - getcpu = 309, - process_vm_readv = 310, - process_vm_writev = 311, - kcmp = 312, - finit_module = 313, - sched_setattr = 314, - sched_getattr = 315, - renameat2 = 316, - seccomp = 317, - getrandom = 318, - memfd_create = 319, - kexec_file_load = 320, - bpf = 321, - execveat = 322, - userfaultfd = 323, - membarrier = 324, - mlock2 = 325, - copy_file_range = 326, - preadv2 = 327, - pwritev2 = 328, - pkey_mprotect = 329, - pkey_alloc = 330, - pkey_free = 331, - statx = 332, - } -} -else version (X86) -{ - // https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl - // https://github.com/torvalds/linux/blob/v4.14/arch/sh/include/uapi/asm/unistd_32.h - enum SystemCall : c_long - { - restart_syscall = 0, - exit = 1, - fork = 2, - read = 3, - write = 4, - open = 5, - close = 6, - waitpid = 7, - creat = 8, - link = 9, - unlink = 10, - execve = 11, - chdir = 12, - time = 13, - mknod = 14, - chmod = 15, - lchown = 16, - break_ = 17, - oldstat = 18, - lseek = 19, - getpid = 20, - mount = 21, - umount = 22, - setuid = 23, - getuid = 24, - stime = 25, - ptrace = 26, - alarm = 27, - oldfstat = 28, - pause = 29, - utime = 30, - stty = 31, - gtty = 32, - access = 33, - nice = 34, - ftime = 35, - sync = 36, - kill = 37, - rename = 38, - mkdir = 39, - rmdir = 40, - dup = 41, - pipe = 42, - times = 43, - prof = 44, - brk = 45, - setgid = 46, - getgid = 47, - signal = 48, - geteuid = 49, - getegid = 50, - acct = 51, - umount2 = 52, - lock = 53, - ioctl = 54, - fcntl = 55, - mpx = 56, - setpgid = 57, - ulimit = 58, - oldolduname = 59, - umask = 60, - chroot = 61, - ustat = 62, - dup2 = 63, - getppid = 64, - getpgrp = 65, - setsid = 66, - sigaction = 67, - sgetmask = 68, - ssetmask = 69, - setreuid = 70, - setregid = 71, - sigsuspend = 72, - sigpending = 73, - sethostname = 74, - setrlimit = 75, - getrlimit = 76, - getrusage = 77, - gettimeofday = 78, - settimeofday = 79, - getgroups = 80, - setgroups = 81, - select = 82, - symlink = 83, - oldlstat = 84, - readlink = 85, - uselib = 86, - swapon = 87, - reboot = 88, - readdir = 89, - mmap = 90, - munmap = 91, - truncate = 92, - ftruncate = 93, - fchmod = 94, - fchown = 95, - getpriority = 96, - setpriority = 97, - profil = 98, - statfs = 99, - fstatfs = 100, - ioperm = 101, - socketcall = 102, - syslog = 103, - setitimer = 104, - getitimer = 105, - stat = 106, - lstat = 107, - fstat = 108, - olduname = 109, - iopl = 110, - vhangup = 111, - idle = 112, - vm86old = 113, - wait4 = 114, - swapoff = 115, - sysinfo = 116, - ipc = 117, - fsync = 118, - sigreturn = 119, - clone = 120, - setdomainname = 121, - uname = 122, - modify_ldt = 123, - adjtimex = 124, - mprotect = 125, - sigprocmask = 126, - create_module = 127, - init_module = 128, - delete_module = 129, - get_kernel_syms = 130, - quotactl = 131, - getpgid = 132, - fchdir = 133, - bdflush = 134, - sysfs = 135, - personality = 136, - afs_syscall = 137, - setfsuid = 138, - setfsgid = 139, - _llseek = 140, - getdents = 141, - _newselect = 142, - flock = 143, - msync = 144, - readv = 145, - writev = 146, - getsid = 147, - fdatasync = 148, - _sysctl = 149, - mlock = 150, - munlock = 151, - mlockall = 152, - munlockall = 153, - sched_setparam = 154, - sched_getparam = 155, - sched_setscheduler = 156, - sched_getscheduler = 157, - sched_yield = 158, - sched_get_priority_max = 159, - sched_get_priority_min = 160, - sched_rr_get_interval = 161, - nanosleep = 162, - mremap = 163, - setresuid = 164, - getresuid = 165, - vm86 = 166, - query_module = 167, - poll = 168, - nfsservctl = 169, - setresgid = 170, - getresgid = 171, - prctl = 172, - rt_sigreturn = 173, - rt_sigaction = 174, - rt_sigprocmask = 175, - rt_sigpending = 176, - rt_sigtimedwait = 177, - rt_sigqueueinfo = 178, - rt_sigsuspend = 179, - pread64 = 180, - pwrite64 = 181, - chown = 182, - getcwd = 183, - capget = 184, - capset = 185, - sigaltstack = 186, - sendfile = 187, - getpmsg = 188, - putpmsg = 189, - vfork = 190, - ugetrlimit = 191, - mmap2 = 192, - truncate64 = 193, - ftruncate64 = 194, - stat64 = 195, - lstat64 = 196, - fstat64 = 197, - lchown32 = 198, - getuid32 = 199, - getgid32 = 200, - geteuid32 = 201, - getegid32 = 202, - setreuid32 = 203, - setregid32 = 204, - getgroups32 = 205, - setgroups32 = 206, - fchown32 = 207, - setresuid32 = 208, - getresuid32 = 209, - setresgid32 = 210, - getresgid32 = 211, - chown32 = 212, - setuid32 = 213, - setgid32 = 214, - setfsuid32 = 215, - setfsgid32 = 216, - pivot_root = 217, - mincore = 218, - madvise = 219, - getdents64 = 220, - fcntl64 = 221, - gettid = 224, - readahead = 225, - setxattr = 226, - lsetxattr = 227, - fsetxattr = 228, - getxattr = 229, - lgetxattr = 230, - fgetxattr = 231, - listxattr = 232, - llistxattr = 233, - flistxattr = 234, - removexattr = 235, - lremovexattr = 236, - fremovexattr = 237, - tkill = 238, - sendfile64 = 239, - futex = 240, - sched_setaffinity = 241, - sched_getaffinity = 242, - set_thread_area = 243, - get_thread_area = 244, - io_setup = 245, - io_destroy = 246, - io_getevents = 247, - io_submit = 248, - io_cancel = 249, - fadvise64 = 250, - exit_group = 252, - lookup_dcookie = 253, - epoll_create = 254, - epoll_ctl = 255, - epoll_wait = 256, - remap_file_pages = 257, - set_tid_address = 258, - timer_create = 259, - timer_settime = 260, - timer_gettime = 261, - timer_getoverrun = 262, - timer_delete = 263, - clock_settime = 264, - clock_gettime = 265, - clock_getres = 266, - clock_nanosleep = 267, - statfs64 = 268, - fstatfs64 = 269, - tgkill = 270, - utimes = 271, - fadvise64_64 = 272, - vserver = 273, - mbind = 274, - get_mempolicy = 275, - set_mempolicy = 276, - mq_open = 277, - mq_unlink = 278, - mq_timedsend = 279, - mq_timedreceive = 280, - mq_notify = 281, - mq_getsetattr = 282, - kexec_load = 283, - waitid = 284, - add_key = 286, - request_key = 287, - keyctl = 288, - ioprio_set = 289, - ioprio_get = 290, - inotify_init = 291, - inotify_add_watch = 292, - inotify_rm_watch = 293, - migrate_pages = 294, - openat = 295, - mkdirat = 296, - mknodat = 297, - fchownat = 298, - futimesat = 299, - fstatat64 = 300, - unlinkat = 301, - renameat = 302, - linkat = 303, - symlinkat = 304, - readlinkat = 305, - fchmodat = 306, - faccessat = 307, - pselect6 = 308, - ppoll = 309, - unshare = 310, - set_robust_list = 311, - get_robust_list = 312, - splice = 313, - sync_file_range = 314, - tee = 315, - vmsplice = 316, - move_pages = 317, - getcpu = 318, - epoll_pwait = 319, - utimensat = 320, - signalfd = 321, - timerfd_create = 322, - eventfd = 323, - fallocate = 324, - timerfd_settime = 325, - timerfd_gettime = 326, - signalfd4 = 327, - eventfd2 = 328, - epoll_create1 = 329, - dup3 = 330, - pipe2 = 331, - inotify_init1 = 332, - preadv = 333, - pwritev = 334, - rt_tgsigqueueinfo = 335, - perf_event_open = 336, - recvmmsg = 337, - fanotify_init = 338, - fanotify_mark = 339, - prlimit64 = 340, - name_to_handle_at = 341, - open_by_handle_at = 342, - clock_adjtime = 343, - syncfs = 344, - sendmmsg = 345, - setns = 346, - process_vm_readv = 347, - process_vm_writev = 348, - kcmp = 349, - finit_module = 350, - sched_setattr = 351, - sched_getattr = 352, - renameat2 = 353, - seccomp = 354, - getrandom = 355, - memfd_create = 356, - bpf = 357, - execveat = 358, - socket = 359, - socketpair = 360, - bind = 361, - connect = 362, - listen = 363, - accept4 = 364, - getsockopt = 365, - setsockopt = 366, - getsockname = 367, - getpeername = 368, - sendto = 369, - sendmsg = 370, - recvfrom = 371, - recvmsg = 372, - shutdown = 373, - userfaultfd = 374, - membarrier = 375, - mlock2 = 376, - copy_file_range = 377, - preadv2 = 378, - pwritev2 = 379, - pkey_mprotect = 380, - pkey_alloc = 381, - pkey_free = 382, - statx = 383, - arch_prctl = 384, - } -} diff --git a/libphobos/libdruntime/core/sys/linux/unistd.d b/libphobos/libdruntime/core/sys/linux/unistd.d index 1ef16c1..4845746 100644 --- a/libphobos/libdruntime/core/sys/linux/unistd.d +++ b/libphobos/libdruntime/core/sys/linux/unistd.d @@ -1,20 +1,16 @@ module core.sys.linux.unistd; +public import core.sys.posix.unistd; + version (linux): -extern (C): +extern(C): nothrow: @system: -@nogc: - -public import core.sys.posix.unistd; -public import core.sys.linux.syscalls : SystemCall; -import core.stdc.config : c_long; // Additional seek constants for sparse file handling // from Linux's unistd.h, stdio.h, and linux/fs.h // (see http://man7.org/linux/man-pages/man2/lseek.2.html) -enum -{ +enum { /// Offset is relative to the next location containing data SEEK_DATA = 3, /// Offset is relative to the next hole (or EOF if file is not sparse) @@ -26,17 +22,3 @@ char* getpass(const(char)* prompt); // Exit all threads in a process void exit_group(int status); - -/** -Invoke system call specified by number, passing it the remaining arguments. -This is completely system-dependent, and not often useful. - -In Unix, `syscall' sets `errno' for all errors and most calls return -1 -for errors; in many systems you cannot pass arguments or get return -values for all system calls (`pipe', `fork', and `getppid' typically -among them). - -In Mach, all system calls take normal arguments and always return an -error code (zero for success). -*/ -c_long syscall(SystemCall number, ...) @nogc nothrow; diff --git a/libphobos/libdruntime/core/sys/netbsd/string.d b/libphobos/libdruntime/core/sys/netbsd/string.d index ab9ced8..f1281da 100644 --- a/libphobos/libdruntime/core/sys/netbsd/string.d +++ b/libphobos/libdruntime/core/sys/netbsd/string.d @@ -17,5 +17,5 @@ nothrow: static if (_NETBSD_SOURCE) { - pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); + pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); } diff --git a/libphobos/libdruntime/core/sys/openbsd/string.d b/libphobos/libdruntime/core/sys/openbsd/string.d index 131e677..4480c94 100644 --- a/libphobos/libdruntime/core/sys/openbsd/string.d +++ b/libphobos/libdruntime/core/sys/openbsd/string.d @@ -18,7 +18,7 @@ nothrow: static if (__BSD_VISIBLE) { void explicit_bzero(void*, size_t); - pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); + pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen); void* memrchr(scope const void*, int, size_t); size_t strlcat(char*, scope const char*, size_t); size_t strlcpy(char*, scope const char*, size_t); diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d index 0dce8c5..32e5156 100644 --- a/libphobos/libdruntime/core/sys/posix/signal.d +++ b/libphobos/libdruntime/core/sys/posix/signal.d @@ -513,15 +513,21 @@ else version (DragonFlyBSD) } else version (Solaris) { + //SIGABRT (defined in core.stdc.signal) enum SIGALRM = 14; enum SIGBUS = 10; enum SIGCHLD = 18; enum SIGCONT = 25; + //SIGFPE (defined in core.stdc.signal) enum SIGHUP = 1; + //SIGILL (defined in core.stdc.signal) + //SIGINT (defined in core.stdc.signal) enum SIGKILL = 9; enum SIGPIPE = 13; enum SIGQUIT = 3; + //SIGSEGV (defined in core.stdc.signal) enum SIGSTOP = 23; + //SIGTERM (defined in core.stdc.signal) enum SIGTSTP = 24; enum SIGTTIN = 26; enum SIGTTOU = 27; @@ -1339,6 +1345,10 @@ else version (Solaris) uint[4] __bits; } + enum SIG_BLOCK = 1; + enum SIG_UNBLOCK = 2; + enum SIG_SETMASK = 3; + struct siginfo_t { int si_signo; @@ -1427,6 +1437,18 @@ else version (Solaris) ___data __data; } + enum SI_NOINFO = 32767; + enum SI_DTRACE = 2050; + enum SI_RCTL = 2049; + enum SI_USER = 0; + enum SI_LWP = -1; + enum SI_QUEUE = -2; + enum SI_TIMER = -3; + enum SI_ASYNCIO = -4; + enum SI_MESGQ = -5; + + enum SIGIO = SIGPOLL; + int kill(pid_t, int); int sigaction(int, const scope sigaction_t*, sigaction_t*); int sigaddset(sigset_t*, int); @@ -2833,9 +2855,9 @@ else version (Solaris) enum SIGPROF = 29; enum SIGSYS = 12; enum SIGTRAP = 5; - enum SIGVTALRM = 31; + enum SIGVTALRM = 28; enum SIGXCPU = 30; - enum SIGXFSZ = 25; + enum SIGXFSZ = 31; enum { diff --git a/libphobos/libdruntime/core/sys/posix/string.d b/libphobos/libdruntime/core/sys/posix/string.d index b9e1c1c..79d2562 100644 --- a/libphobos/libdruntime/core/sys/posix/string.d +++ b/libphobos/libdruntime/core/sys/posix/string.d @@ -31,11 +31,11 @@ public import core.sys.posix.locale : locale_t; public import core.stdc.string; /// Copy string until character found -void* memccpy(return void* dst, scope const void* src, int c, size_t n) pure; +void* memccpy(return scope void* dst, scope const void* src, int c, size_t n) pure; /// Copy string (including terminating '\0') -char* stpcpy(return char* dst, scope const char* src) pure; +char* stpcpy(return scope char* dst, scope const char* src) pure; /// Ditto -char* stpncpy(return char* dst, const char* src, size_t len) pure; +char* stpncpy(return scope char* dst, const char* src, size_t len) pure; /// Compare strings according to current collation int strcoll_l(scope const char* s1, scope const char* s2, locale_t locale); /// @@ -47,6 +47,6 @@ size_t strnlen(scope const char* str, size_t maxlen) pure; /// System signal messages const(char)* strsignal(int); /// Isolate sequential tokens in a null-terminated string -char* strtok_r(return char* str, scope const char* sep, char** context) pure; +char* strtok_r(return scope char* str, scope const char* sep, char** context) pure; /// Transform a string under locale size_t strxfrm_l(char* s1, scope const char* s2, size_t n, locale_t locale); diff --git a/libphobos/libdruntime/core/sys/posix/sys/socket.d b/libphobos/libdruntime/core/sys/posix/sys/socket.d index de51c6a..6e0cfd3 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/socket.d +++ b/libphobos/libdruntime/core/sys/posix/sys/socket.d @@ -217,7 +217,7 @@ version (CRuntime_Glibc) } else { - extern (D) inout(ubyte)* CMSG_DATA( return inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); } + extern (D) inout(ubyte)* CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); } } private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc; diff --git a/libphobos/libdruntime/core/sys/solaris/sys/elf.d b/libphobos/libdruntime/core/sys/solaris/sys/elf.d index 7da2631..7a46d52 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/elf.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/elf.d @@ -393,7 +393,7 @@ enum SHF_LINK_ORDER = 0x80; enum SHF_OS_NONCONFORMING = 0x100; enum SHF_GROUP = 0x200; enum SHF_TLS = 0x400; - +enum SHF_COMPRESSED = 0x800; enum SHF_MASKOS = 0x0ff00000; enum SHF_MASKPROC = 0xf0000000; @@ -656,3 +656,6 @@ enum NT_ZONENAME = 21; enum NT_FDINFO = 22; enum NT_SPYMASTER = 23; enum NT_NUM = 23; + +enum SHF_ORDERED = 0x40000000; +enum SHF_EXCLUDE = 0x80000000; diff --git a/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d b/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d index 0c81985..9927b64 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/elf_386.d @@ -52,9 +52,6 @@ enum R_386_NUM = 39; enum ELF_386_MAXPGSZ = 0x10000; -enum SHF_ORDERED = 0x40000000; -enum SHF_EXCLUDE = 0x80000000; - enum SHN_BEFORE = 0xff00; enum SHN_AFTER = 0xff01; diff --git a/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d b/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d index 81d0234..e43bd40 100644 --- a/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d +++ b/libphobos/libdruntime/core/sys/solaris/sys/elf_SPARC.d @@ -118,9 +118,6 @@ enum ELF_SPARCV9_MAXPGSZ = 0x100000; enum SHT_SPARC_GOTDATA = 0x70000000; -enum SHF_ORDERED = 0x40000000; -enum SHF_EXCLUDE = 0x80000000; - enum SHN_BEFORE = 0xff00; enum SHN_AFTER = 0xff01; diff --git a/libphobos/libdruntime/core/sys/windows/dbghelp.d b/libphobos/libdruntime/core/sys/windows/dbghelp.d index 9848fb9..96698e8 100644 --- a/libphobos/libdruntime/core/sys/windows/dbghelp.d +++ b/libphobos/libdruntime/core/sys/windows/dbghelp.d @@ -39,7 +39,8 @@ extern(Windows) alias BOOL function(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, IMAGEHLP_SYMBOLA64 *Symbol) SymGetSymFromAddr64Func; alias DWORD function(PCSTR DecoratedName, PSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) UnDecorateSymbolNameFunc; alias DWORD64 function(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) SymLoadModule64Func; - alias BOOL function(HANDLE HProcess, PTSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc; + alias BOOL function(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc; + alias BOOL function(HANDLE hProcess, PCSTR SearchPath) SymSetSearchPathFunc; alias BOOL function(HANDLE hProcess, DWORD64 Address) SymUnloadModule64Func; alias BOOL function(HANDLE hProcess, ULONG ActionCode, ulong CallbackContext, ulong UserContext) PSYMBOL_REGISTERED_CALLBACK64; alias BOOL function(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ulong UserContext) SymRegisterCallback64Func; @@ -61,6 +62,7 @@ struct DbgHelp UnDecorateSymbolNameFunc UnDecorateSymbolName; SymLoadModule64Func SymLoadModule64; SymGetSearchPathFunc SymGetSearchPath; + SymSetSearchPathFunc SymSetSearchPath; SymUnloadModule64Func SymUnloadModule64; SymRegisterCallback64Func SymRegisterCallback64; ImagehlpApiVersionFunc ImagehlpApiVersion; @@ -84,6 +86,7 @@ struct DbgHelp sm_inst.UnDecorateSymbolName = cast(UnDecorateSymbolNameFunc) GetProcAddress(sm_hndl,"UnDecorateSymbolName"); sm_inst.SymLoadModule64 = cast(SymLoadModule64Func) GetProcAddress(sm_hndl,"SymLoadModule64"); sm_inst.SymGetSearchPath = cast(SymGetSearchPathFunc) GetProcAddress(sm_hndl,"SymGetSearchPath"); + sm_inst.SymSetSearchPath = cast(SymSetSearchPathFunc) GetProcAddress(sm_hndl,"SymSetSearchPath"); sm_inst.SymUnloadModule64 = cast(SymUnloadModule64Func) GetProcAddress(sm_hndl,"SymUnloadModule64"); sm_inst.SymRegisterCallback64 = cast(SymRegisterCallback64Func) GetProcAddress(sm_hndl, "SymRegisterCallback64"); sm_inst.ImagehlpApiVersion = cast(ImagehlpApiVersionFunc) GetProcAddress(sm_hndl, "ImagehlpApiVersion"); @@ -91,7 +94,8 @@ struct DbgHelp sm_inst.SymSetOptions && sm_inst.SymFunctionTableAccess64 && sm_inst.SymGetLineFromAddr64 && sm_inst.SymGetModuleBase64 && sm_inst.SymGetModuleInfo64 && sm_inst.SymGetSymFromAddr64 && sm_inst.UnDecorateSymbolName && sm_inst.SymLoadModule64 && sm_inst.SymGetSearchPath && - sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 && sm_inst.ImagehlpApiVersion); + sm_inst.SymSetSearchPath && sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 && + sm_inst.ImagehlpApiVersion); return &sm_inst; } diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index b7dde93..fe4d24f 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -719,7 +719,7 @@ class Thread : ThreadBase // the effective maximum. // maxupri - result.PRIORITY_MIN = -clinfo[0]; + result.PRIORITY_MIN = -cast(int)(clinfo[0]); // by definition result.PRIORITY_DEFAULT = 0; } @@ -2196,8 +2196,7 @@ extern (C) void thread_init() @nogc status = sem_init( &suspendCount, 0, 0 ); assert( status == 0 ); } - if (typeid(Thread).initializer.ptr) - _mainThreadStore[] = typeid(Thread).initializer[]; + _mainThreadStore[] = __traits(initSymbol, Thread)[]; Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor()); } diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d index 4592bf1..9cee4d8 100644 --- a/libphobos/libdruntime/core/thread/threadbase.d +++ b/libphobos/libdruntime/core/thread/threadbase.d @@ -771,10 +771,7 @@ package void thread_term_tpl(ThreadT, MainThreadStore)(ref MainThreadStore _main // destruct manually as object.destroy is not @nogc (cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor(); _d_monitordelete_nogc(ThreadBase.sm_main); - if (typeid(ThreadT).initializer.ptr) - _mainThreadStore[] = typeid(ThreadT).initializer[]; - else - (cast(ubyte[])_mainThreadStore)[] = 0; + _mainThreadStore[] = __traits(initSymbol, ThreadT)[]; ThreadBase.sm_main = null; assert(ThreadBase.sm_tbeg && ThreadBase.sm_tlen == 1); diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index a079e0e..fee19ae 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -3485,7 +3485,7 @@ enum immutable(void)* rtinfoHasPointers = cast(void*)1; // Helper functions -private inout(TypeInfo) getElement(return inout TypeInfo value) @trusted pure nothrow +private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow { TypeInfo element = cast() value; for (;;) @@ -4215,8 +4215,8 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == class)) static if (initialize) { - enum classSize = __traits(classInstanceSize, T); - (cast(void*)obj)[0 .. classSize] = typeid(T).initializer[]; + const initializer = __traits(initSymbol, T); + (cast(void*)obj)[0 .. initializer.length] = initializer[]; } } else @@ -4651,6 +4651,8 @@ public import core.internal.array.construction : _d_arrayctor; public import core.internal.array.construction : _d_arraysetctor; public import core.internal.array.capacity: _d_arraysetlengthTImpl; +public import core.lifetime : _d_delstruct; + public import core.internal.dassert: _d_assert_fail; public import core.internal.destruction: __ArrayDtor; diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d index 6ff93f7..0c38622 100644 --- a/libphobos/libdruntime/rt/aaA.d +++ b/libphobos/libdruntime/rt/aaA.d @@ -287,7 +287,7 @@ TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo va void* p = GC.malloc(sizeti + (2 + rtisize) * (void*).sizeof); import core.stdc.string : memcpy; - memcpy(p, typeid(TypeInfo_Struct).initializer().ptr, sizeti); + memcpy(p, __traits(initSymbol, TypeInfo_Struct).ptr, sizeti); auto ti = cast(TypeInfo_Struct) p; auto extra = cast(TypeInfo*)(p + sizeti); @@ -853,7 +853,7 @@ struct Range extern (C) pure nothrow @nogc @safe { - Range _aaRange(return AA aa) + Range _aaRange(return scope AA aa) { if (!aa) return Range(); diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d index dcb4438..1604510 100644 --- a/libphobos/libdruntime/rt/cast_.d +++ b/libphobos/libdruntime/rt/cast_.d @@ -36,7 +36,7 @@ extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const * If it is null, return null. * Else, undefined crash */ -Object _d_toObject(return void* p) +Object _d_toObject(return scope void* p) { if (!p) return null; diff --git a/libphobos/libdruntime/rt/config.d b/libphobos/libdruntime/rt/config.d index f7682f3..a6605f4 100644 --- a/libphobos/libdruntime/rt/config.d +++ b/libphobos/libdruntime/rt/config.d @@ -101,6 +101,9 @@ string rt_cmdlineOption(string opt, scope rt_configCallBack dg) @nogc nothrow { foreach (a; rt_args) { + if (a == "--") + break; + if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" && a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=') { diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index f1a9d87..1f7a81d 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -181,7 +181,7 @@ extern (C) void _d_delstruct(void** p, TypeInfo_Struct inf) @weak } // strip const/immutable/shared/inout from type info -inout(TypeInfo) unqualify(return inout(TypeInfo) cti) pure nothrow @nogc +inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc { TypeInfo ti = cast() cti; while (ti) @@ -381,7 +381,7 @@ size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow /** get the start of the array for the given block */ -void *__arrayStart(return BlkInfo info) nothrow pure +void *__arrayStart(return scope BlkInfo info) nothrow pure { return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0); } diff --git a/libphobos/libdruntime/rt/monitor_.d b/libphobos/libdruntime/rt/monitor_.d index 6bfce63..763f439 100644 --- a/libphobos/libdruntime/rt/monitor_.d +++ b/libphobos/libdruntime/rt/monitor_.d @@ -264,7 +264,7 @@ struct Monitor private: -@property ref shared(Monitor*) monitor(return Object h) pure nothrow @nogc +@property ref shared(Monitor*) monitor(return scope Object h) pure nothrow @nogc { return *cast(shared Monitor**)&h.__monitor; } diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 29bcf33..68fefcb 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -574bf883b790340fb753d6542ec48a3ba3e6cb82 +12329adb67fb43891d6e4e543e7257bc34db0aa7 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d index 9e728e4..af665c4 100644 --- a/libphobos/src/std/algorithm/iteration.d +++ b/libphobos/src/std/algorithm/iteration.d @@ -3595,7 +3595,6 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR) assert(res.equal("cba")); } - /// Ditto auto joiner(RoR)(RoR r) if (isInputRange!RoR && isInputRange!(ElementType!RoR)) @@ -3621,14 +3620,32 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)) _currentBack = typeof(_currentBack).init; } + void replaceCurrent(typeof(_current) current) @trusted + { + import core.lifetime : move; + + current.move(_current); + } + + static if (isBidirectional) + { + void replaceCurrentBack(typeof(_currentBack) currentBack) @trusted + { + import core.lifetime : move; + + currentBack.move(_currentBack); + } + } + public: this(RoR r) { _items = r; + // field _current must be initialized in constructor, because it is nested struct + _current = typeof(_current).init; static if (isBidirectional && hasNested!Result) _currentBack = typeof(_currentBack).init; - // field _current must be initialized in constructor, because it is nested struct mixin(popFrontEmptyElements); static if (isBidirectional) mixin(popBackEmptyElements); @@ -3673,13 +3690,13 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)) // consumed when a .save'd copy of ourselves is iterated over. So // we need to .save each subrange we traverse. static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) - _current = _items.front.save; + replaceCurrent(_items.front.save); else - _current = _items.front; + replaceCurrent(_items.front); } else { - _current = typeof(_current).init; + replaceCurrent(typeof(_current).init); } }; @@ -3696,9 +3713,9 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)) static if (isBidirectional) { static if (is(typeof(null) : typeof(_currentBack))) - r._currentBack = _currentBack is null ? null : _currentBack.save; + r.replaceCurrentBack(_currentBack is null ? null : _currentBack.save); else - r._currentBack = _currentBack.save; + r.replaceCurrentBack(_currentBack.save); r.reachedFinalElement = reachedFinalElement; } return r; @@ -3784,22 +3801,22 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)) static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR)) { if (reachedFinalElement) - _current = _items.back.save; + replaceCurrent(_items.back.save); else - _currentBack = _items.back.save; + replaceCurrentBack(_items.back.save); } else { if (reachedFinalElement) - _current = _items.back; + replaceCurrent(_items.back); else - _currentBack = _items.back; + replaceCurrentBack(_items.back); } } else { - _current = typeof(_current).init; - _currentBack = typeof(_currentBack).init; + replaceCurrent(typeof(_current).init); + replaceCurrentBack(typeof(_currentBack).init); } }; @@ -4232,6 +4249,15 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR)) assert([[0]].joiner.save.back == 0); } +// https://issues.dlang.org/show_bug.cgi?id=22561 +@safe pure unittest +{ + import std.range : only; + + static immutable struct S { int[] array; } + assert([only(S(null))].joiner.front == S(null)); +} + /++ Implements the homonym function (also known as `accumulate`, $(D compress), `inject`, or `foldl`) present in various programming diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d index 07cbb9b..22b7b98 100644 --- a/libphobos/src/std/algorithm/mutation.d +++ b/libphobos/src/std/algorithm/mutation.d @@ -886,31 +886,13 @@ if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range static if (hasElaborateAssign!T) { import std.algorithm.internal : addressOf; - //Elaborate opAssign. Must go the memcpy road. - //We avoid calling emplace here, because our goal is to initialize to - //the static state of T.init, - //So we want to avoid any un-necassarilly CC'ing of T.init + //Elaborate opAssign. Must go the memcpy/memset road. static if (!__traits(isZeroInit, T)) { - auto p = typeid(T).initializer(); for ( ; !range.empty ; range.popFront() ) { - static if (__traits(isStaticArray, T)) - { - // static array initializer only contains initialization - // for one element of the static array. - auto elemp = cast(void *) addressOf(range.front); - auto endp = elemp + T.sizeof; - while (elemp < endp) - { - memcpy(elemp, p.ptr, p.length); - elemp += p.length; - } - } - else - { - memcpy(addressOf(range.front), p.ptr, T.sizeof); - } + import core.internal.lifetime : emplaceInitializer; + emplaceInitializer(range.front); } } else @@ -1456,10 +1438,7 @@ private void moveEmplaceImpl(T)(ref scope T target, ref return scope T source) static if (__traits(isZeroInit, T)) () @trusted { memset(&source, 0, sz); }(); else - { - auto init = typeid(T).initializer(); - () @trusted { memcpy(&source, init.ptr, sz); }(); - } + () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }(); } } else static if (isStaticArray!T) diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d index f2877cc..ee68b23 100644 --- a/libphobos/src/std/algorithm/sorting.d +++ b/libphobos/src/std/algorithm/sorting.d @@ -3121,14 +3121,14 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R && else static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof); - static trustedMalloc(size_t len) @trusted + static trustedMalloc()(size_t len) @trusted { import core.checkedint : mulu; - import core.stdc.stdlib : malloc; + import core.memory : pureMalloc; bool overflow; const nbytes = mulu(len, T.sizeof, overflow); if (overflow) assert(false, "multiplication overflowed"); - T[] result = (cast(T*) malloc(nbytes))[0 .. len]; + T[] result = (cast(T*) pureMalloc(nbytes))[0 .. len]; static if (hasIndirections!T) { import core.memory : GC; @@ -3145,15 +3145,15 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R && { foreach (i; 0 .. length) collectException(destroy(xform1[i])); } - static void trustedFree(T[] p) @trusted + static void trustedFree()(T[] p) @trusted { - import core.stdc.stdlib : free; + import core.memory : pureFree; static if (hasIndirections!T) { import core.memory : GC; GC.removeRange(p.ptr); } - free(p.ptr); + pureFree(p.ptr); } trustedFree(xform1); } @@ -3186,7 +3186,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) } /// -@safe unittest +@safe pure unittest { import std.algorithm.iteration : map; import std.numeric : entropy; @@ -3207,7 +3207,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) assert(isSorted!("a > b")(map!(entropy)(arr))); } -@safe unittest +@safe pure unittest { import std.algorithm.iteration : map; import std.numeric : entropy; @@ -3228,7 +3228,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) assert(isSorted!("a < b")(map!(entropy)(arr))); } -@safe unittest +@safe pure unittest { // binary transform function string[] strings = [ "one", "two", "three" ]; @@ -3237,7 +3237,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) } // https://issues.dlang.org/show_bug.cgi?id=4909 -@safe unittest +@safe pure unittest { import std.typecons : Tuple; Tuple!(char)[] chars; @@ -3245,7 +3245,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) } // https://issues.dlang.org/show_bug.cgi?id=5924 -@safe unittest +@safe pure unittest { import std.typecons : Tuple; Tuple!(char)[] chars; @@ -3253,7 +3253,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) } // https://issues.dlang.org/show_bug.cgi?id=13965 -@safe unittest +@safe pure unittest { import std.typecons : Tuple; Tuple!(char)[] chars; @@ -3261,7 +3261,7 @@ if (isRandomAccessRange!R && hasLength!R && hasSwappableElements!R) } // https://issues.dlang.org/show_bug.cgi?id=13965 -@safe unittest +@safe pure unittest { import std.algorithm.iteration : map; import std.numeric : entropy; diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d index a9830af..fb383ae 100644 --- a/libphobos/src/std/concurrency.d +++ b/libphobos/src/std/concurrency.d @@ -2149,14 +2149,16 @@ private if (msg.convertsTo!(Args)) { - static if (is(ReturnType!(t) == bool)) + alias RT = ReturnType!(t); + static if (is(RT == bool)) { return msg.map(op); } else { msg.map(op); - return true; + static if (!is(immutable RT == immutable noreturn)) + return true; } } } @@ -2745,7 +2747,8 @@ auto ref initOnce(alias var)(lazy typeof(var) init, shared Mutex mutex) if (!atomicLoad!(MemoryOrder.raw)(flag)) { var = init; - atomicStore!(MemoryOrder.rel)(flag, true); + static if (!is(immutable typeof(var) == immutable noreturn)) + atomicStore!(MemoryOrder.rel)(flag, true); } } } @@ -2827,3 +2830,26 @@ auto ref initOnce(alias var)(lazy typeof(var) init, Mutex mutex) immutable expected = Aggregate(42, [1, 2, 3, 4, 5]); assert(result1 == expected); } + +// Noreturn support +@system unittest +{ + static noreturn foo(int) { throw new Exception(""); } + + if (false) spawn(&foo, 1); + if (false) spawnLinked(&foo, 1); + + if (false) receive(&foo); + if (false) receiveTimeout(Duration.init, &foo); + + // Wrapped in __traits(compiles) to skip codegen which crashes dmd's backend + static assert(__traits(compiles, receiveOnly!noreturn() )); + static assert(__traits(compiles, send(Tid.init, noreturn.init) )); + static assert(__traits(compiles, prioritySend(Tid.init, noreturn.init) )); + static assert(__traits(compiles, yield(noreturn.init) )); + + static assert(__traits(compiles, { + __gshared noreturn n; + initOnce!n(noreturn.init); + })); +} diff --git a/libphobos/src/std/container/dlist.d b/libphobos/src/std/container/dlist.d index cc3e2e8..32d56ec 100644 --- a/libphobos/src/std/container/dlist.d +++ b/libphobos/src/std/container/dlist.d @@ -196,6 +196,12 @@ struct DList(T) T _payload = T.init; + this (BaseNode _base, T _payload) + { + this._base = _base; + this._payload = _payload; + } + inout(BaseNode)* asBaseNode() inout @trusted { return &_base; diff --git a/libphobos/src/std/container/rbtree.d b/libphobos/src/std/container/rbtree.d index f8e70fc..0b0a0b2 100644 --- a/libphobos/src/std/container/rbtree.d +++ b/libphobos/src/std/container/rbtree.d @@ -887,7 +887,7 @@ if (is(typeof(binaryFun!less(T.init, T.init)))) * Returns: * true if node was added */ - private bool _add(return Elem n) + private bool _add(return scope Elem n) { Node result; static if (!allowDuplicates) diff --git a/libphobos/src/std/datetime/interval.d b/libphobos/src/std/datetime/interval.d index 741088a..ba2a210 100644 --- a/libphobos/src/std/datetime/interval.d +++ b/libphobos/src/std/datetime/interval.d @@ -8349,7 +8349,7 @@ private: } { - SysTime stFunc(scope const SysTime st) { return cast(SysTime) st; } + SysTime stFunc(scope const SysTime st) { return SysTime.init; } auto interval = Interval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)), SysTime(DateTime(2012, 1, 7, 14, 0, 0))); auto ir = IntervalRange!(SysTime, Direction.fwd)(interval, &stFunc); @@ -8794,7 +8794,7 @@ private: } { - SysTime stFunc(scope const SysTime st) { return cast(SysTime) st; } + SysTime stFunc(scope const SysTime st) { return SysTime.init; } auto posInfInterval = PosInfInterval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7))); auto ir = PosInfIntervalRange!SysTime(posInfInterval, &stFunc); } @@ -9076,7 +9076,7 @@ private: } { - SysTime stFunc(scope const SysTime st) { return cast(SysTime)(st); } + SysTime stFunc(scope const SysTime st) { return SysTime.init; } auto negInfInterval = NegInfInterval!SysTime(SysTime(DateTime(2012, 1, 7, 14, 0, 0))); auto ir = NegInfIntervalRange!(SysTime)(negInfInterval, &stFunc); } diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d index 4da1281..9b2a844 100644 --- a/libphobos/src/std/datetime/systime.d +++ b/libphobos/src/std/datetime/systime.d @@ -503,7 +503,7 @@ public: given $(REF DateTime,std,datetime,date) is assumed to be in the given time zone. +/ - this(DateTime dateTime, immutable TimeZone tz = null) @safe nothrow + this(DateTime dateTime, return scope immutable TimeZone tz = null) return scope @safe nothrow { try this(dateTime, Duration.zero, tz); @@ -554,7 +554,7 @@ public: $(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's greater than or equal to one second. +/ - this(DateTime dateTime, Duration fracSecs, immutable TimeZone tz = null) @safe + this(DateTime dateTime, Duration fracSecs, return scope immutable TimeZone tz = null) return scope @safe { enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds.")); enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second.")); @@ -611,7 +611,7 @@ public: given $(REF Date,std,datetime,date) is assumed to be in the given time zone. +/ - this(Date date, immutable TimeZone tz = null) @safe nothrow + this(Date date, return scope immutable TimeZone tz = null) return scope @safe nothrow { _timezone = tz is null ? LocalTime() : tz; @@ -664,7 +664,7 @@ public: $(LREF SysTime). If null, $(REF LocalTime,std,datetime,timezone) will be used. +/ - this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow + this(long stdTime, return scope immutable TimeZone tz = null) return scope @safe pure nothrow { _stdTime = stdTime; _timezone = tz is null ? LocalTime() : tz; @@ -693,7 +693,7 @@ public: Returns: The `this` of this `SysTime`. +/ - ref SysTime opAssign()(auto ref const(SysTime) rhs) return @safe pure nothrow scope + ref SysTime opAssign()(auto ref const(SysTime) rhs) return scope @safe pure nothrow { _stdTime = rhs._stdTime; _timezone = rhs._timezone; @@ -710,6 +710,7 @@ public: st = other; assert(st == other); + version (none) // https://issues.dlang.org/show_bug.cgi?id=21175 static void testScope(scope ref SysTime left, const scope SysTime right) @safe { left = right; @@ -2184,7 +2185,7 @@ public: hours - adjust the time to this $(LREF SysTime)'s time zone before returning. +/ - @property immutable(TimeZone) timezone() @safe const pure nothrow scope + @property immutable(TimeZone) timezone() @safe const pure nothrow return scope { return _timezone; } @@ -2238,7 +2239,7 @@ public: /++ Returns whether DST is in effect for this $(LREF SysTime). +/ - @property bool dstInEffect() @safe const nothrow scope + @property bool dstInEffect() @safe const nothrow return scope { return _timezone.dstInEffect(_stdTime); } @@ -2261,7 +2262,7 @@ public: Returns what the offset from UTC is for this $(LREF SysTime). It includes the DST offset in effect at that time (if any). +/ - @property Duration utcOffset() @safe const nothrow scope + @property Duration utcOffset() @safe const nothrow return scope { return _timezone.utcOffsetAt(_stdTime); } @@ -9586,13 +9587,13 @@ private: @property override bool hasDST() @safe const nothrow @nogc { return false; } - override bool dstInEffect(long stdTime) @safe const nothrow @nogc { return false; } + override bool dstInEffect(long stdTime) @safe const scope nothrow @nogc { return false; } - override long utcToTZ(long stdTime) @safe const nothrow @nogc { return 0; } + override long utcToTZ(long stdTime) @safe const scope nothrow @nogc { return 0; } - override long tzToUTC(long adjTime) @safe const nothrow @nogc { return 0; } + override long tzToUTC(long adjTime) @safe const scope nothrow @nogc { return 0; } - override Duration utcOffsetAt(long stdTime) @safe const nothrow @nogc { return Duration.zero; } + override Duration utcOffsetAt(long stdTime) @safe const scope nothrow @nogc { return Duration.zero; } private: @@ -9628,7 +9629,7 @@ private: return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage; } - pragma(inline, true) @property void _timezone(immutable TimeZone tz) @safe pure nothrow @nogc scope + pragma(inline, true) @property void _timezone(return scope immutable TimeZone tz) @safe pure nothrow @nogc scope { _timezoneStorage = tz; } diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d index 0527580..a55411b 100644 --- a/libphobos/src/std/datetime/timezone.d +++ b/libphobos/src/std/datetime/timezone.d @@ -100,7 +100,7 @@ public: However, on Windows, it may be the unabbreviated name (e.g. Pacific Standard Time). Regardless, it is not the same as name. +/ - @property string stdName() @safe const nothrow + @property string stdName() @safe const scope nothrow { return _stdName; } @@ -113,7 +113,7 @@ public: However, on Windows, it may be the unabbreviated name (e.g. Pacific Daylight Time). Regardless, it is not the same as name. +/ - @property string dstName() @safe const nothrow + @property string dstName() @safe const scope nothrow { return _dstName; } @@ -137,7 +137,7 @@ public: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ - abstract bool dstInEffect(long stdTime) @safe const nothrow; + abstract bool dstInEffect(long stdTime) @safe const scope nothrow; /++ @@ -148,7 +148,7 @@ public: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ - abstract long utcToTZ(long stdTime) @safe const nothrow; + abstract long utcToTZ(long stdTime) @safe const scope nothrow; /++ @@ -159,7 +159,7 @@ public: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ - abstract long tzToUTC(long adjTime) @safe const nothrow; + abstract long tzToUTC(long adjTime) @safe const scope nothrow; /++ @@ -170,7 +170,7 @@ public: stdTime = The UTC time for which to get the offset from UTC for this time zone. +/ - Duration utcOffsetAt(long stdTime) @safe const nothrow + Duration utcOffsetAt(long stdTime) @safe const scope nothrow { return dur!"hnsecs"(utcToTZ(stdTime) - stdTime); } @@ -580,7 +580,7 @@ public: dynamically rather than it being fixed like it would be with most time zones. +/ - @property override string stdName() @trusted const nothrow + @property override string stdName() @trusted const scope nothrow { version (Posix) { @@ -665,7 +665,7 @@ public: dynamically rather than it being fixed like it would be with most time zones. +/ - @property override string dstName() @trusted const nothrow + @property override string dstName() @trusted const scope nothrow { version (Posix) { @@ -809,7 +809,7 @@ public: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ - override bool dstInEffect(long stdTime) @trusted const nothrow + override bool dstInEffect(long stdTime) @trusted const scope nothrow { import core.stdc.time : tm; @@ -863,7 +863,7 @@ public: See_Also: `TimeZone.utcToTZ` +/ - override long utcToTZ(long stdTime) @trusted const nothrow + override long utcToTZ(long stdTime) @trusted const scope nothrow { version (Solaris) return stdTime + convert!("seconds", "hnsecs")(tm_gmtoff(stdTime)); @@ -904,7 +904,7 @@ public: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ - override long tzToUTC(long adjTime) @trusted const nothrow + override long tzToUTC(long adjTime) @trusted const scope nothrow { version (Posix) { @@ -1159,7 +1159,7 @@ public: /++ Always returns false. +/ - override bool dstInEffect(long stdTime) @safe const nothrow + override bool dstInEffect(long stdTime) @safe const scope nothrow { return false; } @@ -1175,7 +1175,7 @@ public: See_Also: `TimeZone.utcToTZ` +/ - override long utcToTZ(long stdTime) @safe const nothrow + override long utcToTZ(long stdTime) @safe const scope nothrow { return stdTime; } @@ -1208,7 +1208,7 @@ public: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ - override long tzToUTC(long adjTime) @safe const nothrow + override long tzToUTC(long adjTime) @safe const scope nothrow { return adjTime; } @@ -1238,7 +1238,7 @@ public: stdTime = The UTC time for which to get the offset from UTC for this time zone. +/ - override Duration utcOffsetAt(long stdTime) @safe const nothrow + override Duration utcOffsetAt(long stdTime) @safe const scope nothrow { return dur!"hnsecs"(0); } @@ -1285,7 +1285,7 @@ public: /++ Always returns false. +/ - override bool dstInEffect(long stdTime) @safe const nothrow + override bool dstInEffect(long stdTime) @safe const scope nothrow { return false; } @@ -1299,7 +1299,7 @@ public: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ - override long utcToTZ(long stdTime) @safe const nothrow + override long utcToTZ(long stdTime) @safe const scope nothrow { return stdTime + _utcOffset.total!"hnsecs"; } @@ -1326,7 +1326,7 @@ public: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ - override long tzToUTC(long adjTime) @safe const nothrow + override long tzToUTC(long adjTime) @safe const scope nothrow { return adjTime - _utcOffset.total!"hnsecs"; } @@ -1352,7 +1352,7 @@ public: stdTime = The UTC time for which to get the offset from UTC for this time zone. +/ - override Duration utcOffsetAt(long stdTime) @safe const nothrow + override Duration utcOffsetAt(long stdTime) @safe const scope nothrow { return _utcOffset; } @@ -1919,7 +1919,7 @@ public: stdTime = The UTC time that needs to be checked for DST in this time zone. +/ - override bool dstInEffect(long stdTime) @safe const nothrow + override bool dstInEffect(long stdTime) @safe const scope nothrow { assert(!_transitions.empty); @@ -1943,7 +1943,7 @@ public: stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ - override long utcToTZ(long stdTime) @safe const nothrow + override long utcToTZ(long stdTime) @safe const scope nothrow { assert(!_transitions.empty); @@ -1968,7 +1968,7 @@ public: adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ - override long tzToUTC(long adjTime) @safe const nothrow + override long tzToUTC(long adjTime) @safe const scope nothrow { assert(!_transitions.empty, "UTC offset's not available"); @@ -2691,7 +2691,7 @@ private: } - int calculateLeapSeconds(long stdTime) @safe const pure nothrow + int calculateLeapSeconds(long stdTime) @safe const scope pure nothrow { if (_leapSeconds.empty) return 0; @@ -2864,7 +2864,7 @@ version (StdDdoc) current dates but will still return true for `hasDST` because the time zone did at some point have DST. +/ - @property override bool hasDST() @safe const nothrow; + @property override bool hasDST() @safe const scope nothrow; /++ @@ -2876,7 +2876,7 @@ version (StdDdoc) stdTime = The UTC time that needs to be checked for DST in this time zone. +/ - override bool dstInEffect(long stdTime) @safe const nothrow; + override bool dstInEffect(long stdTime) @safe const scope nothrow; /++ @@ -2888,7 +2888,7 @@ version (StdDdoc) stdTime = The UTC time that needs to be adjusted to this time zone's time. +/ - override long utcToTZ(long stdTime) @safe const nothrow; + override long utcToTZ(long stdTime) @safe const scope nothrow; /++ @@ -2900,7 +2900,7 @@ version (StdDdoc) adjTime = The time in this time zone that needs to be adjusted to UTC time. +/ - override long tzToUTC(long adjTime) @safe const nothrow; + override long tzToUTC(long adjTime) @safe const scope nothrow; /++ @@ -2945,9 +2945,9 @@ version (StdDdoc) else alias TIME_ZONE_INFORMATION = void*; - static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow; - static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow; - static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow; + static bool _dstInEffect(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow; + static long _utcToTZ(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow; + static long _tzToUTC(const scope TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow; this() immutable pure { @@ -2967,25 +2967,25 @@ else version (Windows) public: - @property override bool hasDST() @safe const nothrow + @property override bool hasDST() @safe const scope nothrow { return _tzInfo.DaylightDate.wMonth != 0; } - override bool dstInEffect(long stdTime) @safe const nothrow + override bool dstInEffect(long stdTime) @safe const scope nothrow { return _dstInEffect(&_tzInfo, stdTime); } - override long utcToTZ(long stdTime) @safe const nothrow + override long utcToTZ(long stdTime) @safe const scope nothrow { return _utcToTZ(&_tzInfo, stdTime, hasDST); } - override long tzToUTC(long adjTime) @safe const nothrow + override long tzToUTC(long adjTime) @safe const scope nothrow { return _tzToUTC(&_tzInfo, adjTime, hasDST); } @@ -3071,7 +3071,7 @@ else version (Windows) private: - static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow + static bool _dstInEffect(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow { try { @@ -3155,7 +3155,7 @@ else version (Windows) } - static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow + static long _utcToTZ(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow { if (hasDST && WindowsTimeZone._dstInEffect(tzInfo, stdTime)) return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias); @@ -3164,7 +3164,7 @@ else version (Windows) } - static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow + static long _tzToUTC(const scope TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow { if (hasDST) { diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index 1bfed64..315e054 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -1124,7 +1124,7 @@ version (Windows) private ulong makeUlong(DWORD dwLow, DWORD dwHigh) @safe pure } version (Posix) private extern (C) pragma(mangle, stat.mangleof) -int trustedStat(const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted; +int trustedStat(scope const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted; /** Get size of file `name` in bytes. @@ -1928,7 +1928,7 @@ if (isConvertibleToString!R) assert(!f.exists); } -private bool existsImpl(const(FSChar)* namez) @trusted nothrow @nogc +private bool existsImpl(scope const(FSChar)* namez) @trusted nothrow @nogc { version (Windows) { @@ -2010,7 +2010,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && version (Windows) { auto namez = name.tempCString!FSChar(); - static auto trustedGetFileAttributesW(const(FSChar)* namez) @trusted + static auto trustedGetFileAttributesW(scope const(FSChar)* namez) @trusted { return GetFileAttributesW(namez); } @@ -2220,7 +2220,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && version (Windows) { auto namez = name.tempCString!FSChar(); - static auto trustedSetFileAttributesW(const(FSChar)* namez, uint dwFileAttributes) @trusted + static auto trustedSetFileAttributesW(scope const(FSChar)* namez, uint dwFileAttributes) @trusted { return SetFileAttributesW(namez, dwFileAttributes); } @@ -2233,7 +2233,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && else version (Posix) { auto namez = name.tempCString!FSChar(); - static auto trustedChmod(const(FSChar)* namez, mode_t mode) @trusted + static auto trustedChmod(scope const(FSChar)* namez, mode_t mode) @trusted { return chmod(namez, mode); } @@ -2868,14 +2868,14 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && version (Windows) { - static auto trustedChdir(const(FSChar)* pathz) @trusted + static auto trustedChdir(scope const(FSChar)* pathz) @trusted { return SetCurrentDirectoryW(pathz); } } else version (Posix) { - static auto trustedChdir(const(FSChar)* pathz) @trusted + static auto trustedChdir(scope const(FSChar)* pathz) @trusted { return core.sys.posix.unistd.chdir(pathz) == 0; } @@ -2939,7 +2939,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && version (Windows) { - static auto trustedCreateDirectoryW(const(FSChar)* pathz) @trusted + static auto trustedCreateDirectoryW(scope const(FSChar)* pathz) @trusted { return CreateDirectoryW(pathz, null); } @@ -2953,7 +2953,7 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && { import std.conv : octal; - static auto trustedMkdir(const(FSChar)* pathz, mode_t mode) @trusted + static auto trustedMkdir(scope const(FSChar)* pathz, mode_t mode) @trusted { return core.sys.posix.sys.stat.mkdir(pathz, mode); } @@ -3143,14 +3143,14 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) && version (Windows) { - static auto trustedRmdir(const(FSChar)* pathz) @trusted + static auto trustedRmdir(scope const(FSChar)* pathz) @trusted { return RemoveDirectoryW(pathz); } } else version (Posix) { - static auto trustedRmdir(const(FSChar)* pathz) @trusted + static auto trustedRmdir(scope const(FSChar)* pathz) @trusted { return core.sys.posix.unistd.rmdir(pathz) == 0; } @@ -3859,17 +3859,17 @@ else version (Windows) return _size; } - @property SysTime timeCreated() const pure nothrow scope + @property SysTime timeCreated() const pure nothrow return scope { return cast(SysTime)_timeCreated; } - @property SysTime timeLastAccessed() const pure nothrow scope + @property SysTime timeLastAccessed() const pure nothrow return scope { return cast(SysTime)_timeLastAccessed; } - @property SysTime timeLastModified() const pure nothrow scope + @property SysTime timeLastModified() const pure nothrow return scope { return cast(SysTime)_timeLastModified; } diff --git a/libphobos/src/std/internal/cstring.d b/libphobos/src/std/internal/cstring.d index a61ee81..b21f58d 100644 --- a/libphobos/src/std/internal/cstring.d +++ b/libphobos/src/std/internal/cstring.d @@ -227,7 +227,7 @@ private struct TempCStringBuffer(To = char) @disable this(this); alias ptr this; /// implicitly covert to raw pointer - @property inout(To)* buffPtr() inout + @property inout(To)* buffPtr() return inout { return _ptr == useStack ? _buff.ptr : _ptr; } diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d index 7944675..6a93e0a 100644 --- a/libphobos/src/std/internal/math/biguintcore.d +++ b/libphobos/src/std/internal/math/biguintcore.d @@ -879,7 +879,7 @@ public: } // return x / y - static BigUint divInt(T)(scope return BigUint x, T y_) pure nothrow @safe + static BigUint divInt(T)(return scope BigUint x, T y_) pure nothrow @safe if ( is(immutable T == immutable uint) ) { uint y = y_; @@ -942,7 +942,7 @@ public: } // return x / y - static BigUint div(scope return BigUint x, scope BigUint y) pure nothrow @safe + static BigUint div(return scope BigUint x, scope BigUint y) pure nothrow @safe { if (y.data.length > x.data.length) return BigUint(ZERO); @@ -954,7 +954,7 @@ public: } // return x % y - static BigUint mod(scope return BigUint x, scope BigUint y) pure nothrow @safe + static BigUint mod(return scope BigUint x, scope BigUint y) pure nothrow @safe { if (y.data.length > x.data.length) return x; if (y.data.length == 1) @@ -1020,7 +1020,7 @@ public: * exponentiation is used. * Memory allocation is minimized: at most one temporary BigUint is used. */ - static BigUint pow(scope return BigUint x, ulong y) pure nothrow @safe + static BigUint pow(return scope BigUint x, ulong y) pure nothrow @safe { // Deal with the degenerate cases first. if (y == 0) return BigUint(ONE); @@ -1259,7 +1259,7 @@ public: } // Remove leading zeros from x, to restore the BigUint invariant -inout(BigDigit) [] removeLeadingZeros(scope return inout(BigDigit) [] x) pure nothrow @safe +inout(BigDigit) [] removeLeadingZeros(return scope inout(BigDigit) [] x) pure nothrow @safe { size_t k = x.length; while (k>1 && x[k - 1]==0) --k; @@ -1916,7 +1916,7 @@ pure @safe unittest // every 8 digits. // buff.length must be data.length*8 if separator is zero, // or data.length*9 if separator is non-zero. It will be completely filled. -char [] biguintToHex(scope return char [] buff, const scope BigDigit [] data, char separator=0, +char [] biguintToHex(return scope char [] buff, const scope BigDigit [] data, char separator=0, LetterCase letterCase = LetterCase.upper) pure nothrow @safe { int x=0; diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d index af7aa38..ea22d63 100644 --- a/libphobos/src/std/json.d +++ b/libphobos/src/std/json.d @@ -159,7 +159,7 @@ struct JSONValue return store.str; } /// ditto - @property string str(return string v) pure nothrow @nogc @trusted return // TODO make @safe + @property string str(return scope string v) pure nothrow @nogc @trusted return // TODO make @safe { assign(v); return v; @@ -282,7 +282,7 @@ struct JSONValue return store.object; } /// ditto - @property JSONValue[string] object(return JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe + @property JSONValue[string] object(return scope JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe { assign(v); return v; @@ -321,14 +321,14 @@ struct JSONValue (*a)[0] = "world"; // segmentation fault --- */ - @property ref inout(JSONValue[]) array() inout pure @system + @property ref inout(JSONValue[]) array() return scope inout pure @system { enforce!JSONException(type == JSONType.array, "JSONValue is not an array"); return store.array; } /// ditto - @property JSONValue[] array(return JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe + @property JSONValue[] array(return scope JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe { assign(v); return v; @@ -635,7 +635,7 @@ struct JSONValue * Hash syntax for json objects. * Throws: `JSONException` if `type` is not `JSONType.object`. */ - ref inout(JSONValue) opIndex(return string k) inout pure @safe + ref inout(JSONValue) opIndex(return scope string k) inout pure @safe { auto o = this.objectNoRef; return *enforce!JSONException(k in o, diff --git a/libphobos/src/std/net/isemail.d b/libphobos/src/std/net/isemail.d index f2a8ff3..12a29fe 100644 --- a/libphobos/src/std/net/isemail.d +++ b/libphobos/src/std/net/isemail.d @@ -1893,7 +1893,7 @@ Note that only the first item of "matchAll" was ever used in practice so we can return `const(Char)[]` instead of `const(Char)[][]` using a zero-length string to indicate no match. +/ -const(Char)[] matchIPSuffix(Char)(return const(Char)[] s) @nogc nothrow pure @safe +const(Char)[] matchIPSuffix(Char)(return scope const(Char)[] s) @nogc nothrow pure @safe { size_t end = s.length; if (end < 7) return null; diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d index 98c5b94..958f606 100644 --- a/libphobos/src/std/process.d +++ b/libphobos/src/std/process.d @@ -276,7 +276,7 @@ static: multi-threaded programs. See e.g. $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc). */ - inout(char)[] opIndexAssign(return inout char[] value, scope const(char)[] name) @trusted + inout(char)[] opIndexAssign(return scope inout char[] value, scope const(char)[] name) @trusted { version (Posix) { @@ -4385,6 +4385,7 @@ else version (Posix) void browse(scope const(char)[] url) nothrow @nogc @safe { + const buffer = url.tempCString(); // Retain buffer until end of scope const(char)*[3] args; // Trusted because it's called with a zero-terminated literal @@ -4408,7 +4409,6 @@ else version (Posix) } } - const buffer = url.tempCString(); // Retain buffer until end of scope args[1] = buffer; args[2] = null; diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d index a348356..106e51c 100644 --- a/libphobos/src/std/random.d +++ b/libphobos/src/std/random.d @@ -166,12 +166,16 @@ version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; assert(10.iota.randomSample(3, rnd2).equal([7, 8, 9])); // Cover all elements in an array in random order - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 - assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); + else + assert(10.iota.randomCover(rnd2).equal([4, 8, 7, 3, 5, 9, 2, 6, 0, 1])); // Shuffle an array - version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147 - assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1])); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1])); + else + assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([4, 2, 5, 0, 1])); } version (StdUnittest) diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d index d3097d5..f30ea80 100644 --- a/libphobos/src/std/stdio.d +++ b/libphobos/src/std/stdio.d @@ -4650,7 +4650,7 @@ if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) auto namez = name.tempCString!FSChar(); auto modez = mode.tempCString!FSChar(); - static _fopenImpl(const(FSChar)* namez, const(FSChar)* modez) @trusted nothrow @nogc + static _fopenImpl(scope const(FSChar)* namez, scope const(FSChar)* modez) @trusted nothrow @nogc { version (Windows) { diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d index db0e3da..6dee863 100644 --- a/libphobos/src/std/typecons.d +++ b/libphobos/src/std/typecons.d @@ -2239,7 +2239,7 @@ if (is(T == class) || is(T == interface) || isAssociativeArray!T) U stripped; } - void opAssign(T another) pure nothrow @nogc + void opAssign(return scope T another) pure nothrow @nogc { // If `T` defines `opCast` we must infer the safety static if (hasMember!(T, "opCast")) @@ -2271,7 +2271,7 @@ if (is(T == class) || is(T == interface) || isAssociativeArray!T) opAssign(initializer); } - @property inout(T) get() @trusted pure nothrow @nogc inout + @property inout(T) get() @trusted pure nothrow @nogc return scope inout { return original; } @@ -2792,6 +2792,15 @@ struct Nullable(T) } } + this (ref return scope inout Nullable!T rhs) inout + { + _isNull = rhs._isNull; + if (!_isNull) + _value.payload = rhs._value.payload; + else + _value = DontCallDestructorT.init; + } + /** * If they are both null, then they are equal. If one is null and the other * is not, then they are not equal. If they are both non-null, then they are @@ -3284,11 +3293,11 @@ auto nullable(T)(T t) static struct S2 //inspired from 9404 { Nullable!int ni; - this(S2 other) + this(ref S2 other) { ni = other.ni; } - void opAssign(S2 other) + void opAssign(ref S2 other) { ni = other.ni; } @@ -9566,3 +9575,21 @@ unittest assert((a ^ true) == Ternary.no); assert((a ^ false) == Ternary.yes); } + +// https://issues.dlang.org/show_bug.cgi?id=22511 +@safe unittest +{ + static struct S + { + int b; + @disable this(this); + this (ref return scope inout S rhs) inout + { + this.b = rhs.b + 1; + } + } + + Nullable!S s1 = S(1); + Nullable!S s2 = s1; + assert(s2.get().b > s1.get().b); +} diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d index 45b7207c..a27cbea 100644 --- a/libphobos/src/std/uni/package.d +++ b/libphobos/src/std/uni/package.d @@ -1987,8 +1987,8 @@ pure: { return this[0] == val[0] && this[1] == val[1]; } - @property ref inout(uint) a() inout { return _tuple[0]; } - @property ref inout(uint) b() inout { return _tuple[1]; } + @property ref inout(uint) a() return inout { return _tuple[0]; } + @property ref inout(uint) b() return inout { return _tuple[1]; } } /** diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index be60e7a..866ec48 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -4315,12 +4315,12 @@ if (isSomeChar!C) { enum Empty = uint.max; // range is empty or just constructed - this(return R r) + this(return scope R r) { this.r = r; } - this(return R r, uint buff) + this(return scope R r, uint buff) { this.r = r; this.buff = buff; @@ -4328,7 +4328,7 @@ if (isSomeChar!C) static if (isBidirectionalRange!R) { - this(return R r, uint frontBuff, uint backBuff) + this(return scope R r, uint frontBuff, uint backBuff) { this.r = r; this.buff = frontBuff; @@ -4436,12 +4436,12 @@ if (isSomeChar!C) { static struct Result { - this(return R r) + this(return scope R r) { this.r = r; } - this(return R r, ushort pos, ushort fill, C[4 / C.sizeof] buf) + this(return scope R r, ushort pos, ushort fill, C[4 / C.sizeof] buf) { this.r = r; this.pos = pos; @@ -4451,7 +4451,7 @@ if (isSomeChar!C) static if (isBidirectionalRange!R) { - this(return R r, ushort frontPos, ushort frontFill, + this(return scope R r, ushort frontPos, ushort frontFill, ushort backPos, ushort backFill, C[4 / C.sizeof] buf) { this.r = r; diff --git a/libphobos/testsuite/libphobos.config/config.exp b/libphobos/testsuite/libphobos.config/config.exp index e8f4d94..544caa2 100644 --- a/libphobos/testsuite/libphobos.config/config.exp +++ b/libphobos/testsuite/libphobos.config/config.exp @@ -22,6 +22,7 @@ set dg-output-text [list] set config_test_list [list \ { test19433 "--DRT-dont-eat-me" 0 } \ { test20459 "foo bar -- --DRT-gcopts=profile:1" 0 } \ + { test22523 "-- --DRT-testmode=run-main" 0 } \ ] # Initialize dg. diff --git a/libphobos/testsuite/libphobos.config/test22523.d b/libphobos/testsuite/libphobos.config/test22523.d new file mode 100644 index 0000000..f308696 --- /dev/null +++ b/libphobos/testsuite/libphobos.config/test22523.d @@ -0,0 +1,11 @@ +// https://issues.dlang.org/show_bug.cgi?id=22523 + +import core.stdc.stdio; + +int main() +{ + puts("Executed main although it should be skipped!"); + return 1; +} + +unittest {} diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index fa193c6..b41b211 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,195 @@ +2021-12-11 Jason Merrill <jason@redhat.com> + + PR c++/103534 + * include/bits/basic_string.h (append (basic_string)): Call pointer + append instead of _M_append directly. + +2021-12-10 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/71367 + * config/locale/dragonfly/time_members.cc (_M_initialize_timepunct): + Initialize "C" _M_am_pm_format to %I:%M:%S %p rather than empty + string. + * config/locale/gnu/time_members.cc (_M_initialize_timepunct): + Likewise. + * config/locale/generic/time_members.cc (_M_initialize_timepunct): + Likewise. + * include/bits/locale_facets_nonio.h (_M_am_pm_format): New method. + * include/bits/locale_facets_nonio.tcc (_M_extract_via_format): Handle + %r. + * config/abi/pre/gnu.ver (GLIBCXX_3.4.30): Export _M_am_pm_format + with const _CharT** argument, ensure it isn't exported in GLIBCXX_3.4. + * testsuite/22_locale/time_get/get/char/71367.cc: New test. + * testsuite/22_locale/time_get/get/wchar_t/71367.cc: New test. + +2021-12-10 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/78714 + * include/bits/locale_facets_nonio.tcc (_M_extract_via_format): + Mention in function comment it interprets strptime format string + rather than strftime. Handle %a and %A the same by accepting both + full and abbreviated names. Similarly handle %h, %b and %B the same. + Handle %d and %e the same by accepting possibly optional single space + and 1 or 2 digits. For %I store tm_hour 0 instead of tm_hour 12. For + %t and %n skip any whitespace. Handle %p and %%. For whitespace in + the string skip any whitespace. + (_M_extract_num): For __len == 2 accept 1 or 2 digits rather than + always 2. Don't punt early if __value * __mult is larget than __max + or smaller than __min - __mult, instead punt if __value > __max. + At the end verify __value is in between __min and __max and punt + otherwise. + (_M_extract_name): Allow non-unique names or names which are prefixes + of other names. Don't recompute lengths of names for every character. + * testsuite/22_locale/time_get/get/char/3.cc: New test. + * testsuite/22_locale/time_get/get/wchar_t/3.cc: New test. + * testsuite/22_locale/time_get/get_date/char/12791.cc (test01): Use + 62 instead 60 and expect 6 to be accepted and thus *ret01 == '2'. + * testsuite/22_locale/time_get/get_date/wchar_t/12791.cc (test01): + Similarly. + * testsuite/22_locale/time_get/get_time/char/2.cc (test02): Add " PM" + to the string. + * testsuite/22_locale/time_get/get_time/char/5.cc (test01): Expect + tm_hour 1 rather than 0. + * testsuite/22_locale/time_get/get_time/wchar_t/2.cc (test02): Add + " PM" to the string. + * testsuite/22_locale/time_get/get_time/wchar_t/5.cc (test01): Expect + tm_hour 1 rather than 0. + +2021-12-10 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/103638 + * include/bits/atomic_timed_wait.h: Check _GLIBCXX_HAS_GTHREADS + before using std::mutex and std::__condvar. + +2021-12-10 Jonathan Wakely <jwakely@redhat.com> + + * acinclude.m4 (GLIBCXX_ENABLE_LIBSTDCXX_TIME): Add _GLIBCXX_ + prefix to NO_SLEEP macro. + * config.h.in: Regenerate. + * configure: Regenerate. + +2021-12-10 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/char_traits.h: Change pragma push to pop. + +2021-12-10 Thomas Rodgers <rodgert@twrodgers.com> + + PR libstdc++/102994 + * include/bits/atomic_base.h (__atomic_base<_PTp*>::wait()): + Add const qualifier. + * include/std/atomic (atomic<_Tp*>::wait(), atomic_wait()): + Likewise. + * testsuite/29_atomics/atomic/wait_notify/102994.cc: + New test. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/stl_iterator.h (operator==, operator<=>): Define + overloads for homogeneous specializations of reverse_iterator, + __normal_iterator and move_iterator. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + * testsuite/20_util/scoped_allocator/69293_neg.cc: Remove + dg-error for c++20. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/85813 + * libsupc++/exception_ptr.h (__dest_thunk): Add macro for + destructor calling convention. + (make_exception_ptr): Enable non-throwing implementation for + -fno-exceptions and for non-standard calling conventions. Use + always_inline attribute on the useless no-rtti no-exceptions + definition. + * testsuite/18_support/exception_ptr/64241.cc: Add -fno-rtti so + the no-op implementation is still used. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/103630 + * libsupc++/exception_ptr.h (exception_ptr): Fix exception + specifications on inline definitions. + (make_exception_ptr): Decay the template parameter. Use typeid + of the static type. + * testsuite/18_support/exception_ptr/103630.cc: New test. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/59769 + * config/io/basic_file_stdio.cc (fopen_mode): Add support for + exclusive mode. + * include/bits/ios_base.h (_S_noreplace): Define new enumerator. + (ios_base::__noreplace): Define. + (ios_base::noreplace): Define for C++23. + * include/std/version (__cpp_lib_ios_noreplace): Define. + * testsuite/27_io/basic_ofstream/open/char/noreplace.cc: New test. + * testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc: New test. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/103382 + * config/abi/pre/gnu.ver (GLIBCXX_3.4.11): Do not export old + symbol if .symver renaming is supported. + (GLIBCXX_3.4.30): Export new symbol if .symver renaming is + supported. + * doc/xml/manual/evolution.xml: Document change. + * doc/html/manual/api.html: Regenerate. + * include/bits/std_mutex.h (__condvar::wait, __condvar::wait_until): + Remove noexcept. + * include/std/condition_variable (condition_variable::wait): + Likewise. + * src/c++11/condition_variable.cc (condition_variable::wait): + Likewise. + * src/c++11/compatibility-condvar.cc (__nothrow_wait_cv::wait): + Define nothrow wrapper around std::condition_variable::wait and + export the old symbol as an alias to it. + * testsuite/30_threads/condition_variable/members/103382.cc: New test. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/92300 + * include/bits/stl_map.h (insert(Pair&&), emplace(Args&&...)): + Check whether the arguments can be looked up directly without + constructing a temporary node first. + * include/bits/stl_pair.h (__is_pair): Move to here, from ... + * include/bits/uses_allocator_args.h (__is_pair): ... here. + * testsuite/23_containers/map/modifiers/emplace/92300.cc: New test. + * testsuite/23_containers/map/modifiers/insert/92300.cc: New test. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + * include/bits/cow_string.h (basic_string::_M_leak_hard): Do not + reallocate an empty string. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/103332 + PR libstdc++/102958 + PR libstdc++/103483 + * include/bits/char_traits.h: Suppress stringop and array-bounds + warnings. + +2021-12-09 Jonathan Wakely <jwakely@redhat.com> + + PR libstdc++/64135 + * config/allocator/new_allocator_base.h: Include + <bits/new_allocator.h> instead of <ext/new_allocator.h>. + (__allocator_base): Use std::__new_allocator instead of + __gnu_cxx::new_allocator. + * doc/xml/manual/allocator.xml: Document new default base class + for std::allocator. + * doc/xml/manual/evolution.xml: Likewise. + * doc/html/*: Regenerate. + * include/Makefile.am: Add bits/new_allocator.h. + * include/Makefile.in: Regenerate. + * include/experimental/memory_resource (new_delete_resource): + Use std::__new_allocator instead of __gnu_cxx::new_allocator. + * include/ext/new_allocator.h (new_allocator): Derive from + std::__new_allocator. Move implementation to ... + * include/bits/new_allocator.h: New file. + * testsuite/20_util/allocator/64135.cc: New test. + 2021-12-08 Jonathan Wakely <jwakely@redhat.com> * include/bits/shared_ptr_base.h (_Sp_counted_base::_M_release()): diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 6d9a8875..635168d 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -1562,7 +1562,7 @@ AC_DEFUN([GLIBCXX_ENABLE_LIBSTDCXX_TIME], [ fi if test x"$ac_no_sleep" = x"yes"; then - AC_DEFINE(NO_SLEEP,1, [Defined if no way to sleep is available.]) + AC_DEFINE(_GLIBCXX_NO_SLEEP,1, [Defined if no way to sleep is available.]) fi AC_SUBST(GLIBCXX_LIBS) diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index 420021f..10675fe 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -714,9 +714,6 @@ */ #undef LT_OBJDIR -/* Defined if no way to sleep is available. */ -#undef NO_SLEEP - /* Name of package */ #undef PACKAGE @@ -838,6 +835,9 @@ /* Define if C99 llrint and llround functions are missing from <math.h>. */ #undef _GLIBCXX_NO_C99_ROUNDING_FUNCS +/* Defined if no way to sleep is available. */ +#undef _GLIBCXX_NO_SLEEP + /* Define if ptrdiff_t is int. */ #undef _GLIBCXX_PTRDIFF_T_IS_INT diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index 8f3c7b3..6dd16f6 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -185,7 +185,13 @@ GLIBCXX_3.4 { std::_List_node_base::unhook*; std::_List_node_base::reverse*; std::_List_node_base::transfer*; - std::__timepunct*; +# std::__timepunct*; + std::__timepunct?char?::[^_]*; + std::__timepunct?char?::_[^M]*; + std::__timepunct?char?::_M_[^a]*; + std::__timepunct?wchar_t?::[^_]*; + std::__timepunct?wchar_t?::_[^M]*; + std::__timepunct?wchar_t?::_M_[^a]*; # std::__numeric_limits_base*; std::__num_base::_S_format_float*; std::__num_base::_S_format_int*; @@ -684,6 +690,10 @@ GLIBCXX_3.4 { # std::__convert_to_v _ZSt14__convert_to_vI[^gU]*; + # std::__timepunct + _ZNKSt11__timepunctI[cw]E8_M_am_pmEPPK[cw]; + _ZNKSt11__timepunctI[cw]E15_M_am_pm_formatEPK[cw]; + # __gnu_cxx::stdio_sync_filebuf _ZTVN9__gnu_cxx18stdio_sync_filebufI[cw]St11char_traitsI[cw]EEE; @@ -1285,7 +1295,6 @@ GLIBCXX_3.4.11 { # condition_variable _ZNSt18condition_variable10notify_allEv; _ZNSt18condition_variable10notify_oneEv; - _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE; _ZNSt18condition_variableC1Ev; _ZNSt18condition_variableC2Ev; _ZNSt18condition_variableD1Ev; @@ -1295,6 +1304,12 @@ GLIBCXX_3.4.11 { _ZNSt22condition_variable_anyD1Ev; _ZNSt22condition_variable_anyD2Ev; +#ifndef HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT + # The original definition of this symbol gets versioned as @GLIBCXX_3.4.11 + # if ".symver" is supported, or as @@GLIBCXX_3.4.11 otherwise. + _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE; +#endif + # thread _ZNSt6thread4joinEv; _ZNSt6thread6detachEv; @@ -2401,6 +2416,14 @@ GLIBCXX_3.4.30 { _ZSt21__glibcxx_assert_fail*; +#ifdef HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT + # The new definition of this symbol gets versioned as @@GLIBCXX_3.4.30 + _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE; +#endif + + # std::__timepunct<char>::_M_am_pm_format(const char**) + _ZNKSt11__timepunctI[cw]E15_M_am_pm_formatEPPK[cw]; + } GLIBCXX_3.4.29; # Symbols in the support library (libsupc++) have their own tag. diff --git a/libstdc++-v3/config/allocator/new_allocator_base.h b/libstdc++-v3/config/allocator/new_allocator_base.h index 7c52fef..a139f2f 100644 --- a/libstdc++-v3/config/allocator/new_allocator_base.h +++ b/libstdc++-v3/config/allocator/new_allocator_base.h @@ -30,7 +30,7 @@ #ifndef _GLIBCXX_CXX_ALLOCATOR_H #define _GLIBCXX_CXX_ALLOCATOR_H 1 -#include <ext/new_allocator.h> +#include <bits/new_allocator.h> #if __cplusplus >= 201103L namespace std @@ -38,18 +38,17 @@ namespace std /** * @brief An alias to the base class for std::allocator. * - * Used to set the std::allocator base class to - * __gnu_cxx::new_allocator. + * Used to set the std::allocator base class to std::__new_allocator. * * @ingroup allocators * @tparam _Tp Type of allocated object. */ template<typename _Tp> - using __allocator_base = __gnu_cxx::new_allocator<_Tp>; + using __allocator_base = __new_allocator<_Tp>; } #else -// Define new_allocator as the base class to std::allocator. -# define __allocator_base __gnu_cxx::new_allocator +// Define __new_allocator as the base class to std::allocator. +# define __allocator_base __new_allocator #endif #ifndef _GLIBCXX_SANITIZE_STD_ALLOCATOR diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc index ce4a638..06ee016 100644 --- a/libstdc++-v3/config/io/basic_file_stdio.cc +++ b/libstdc++-v3/config/io/basic_file_stdio.cc @@ -78,32 +78,38 @@ namespace out = std::ios_base::out, trunc = std::ios_base::trunc, app = std::ios_base::app, - binary = std::ios_base::binary + binary = std::ios_base::binary, + noreplace = std::_S_noreplace }; // _GLIBCXX_RESOLVE_LIB_DEFECTS // 596. 27.8.1.3 Table 112 omits "a+" and "a+b" modes. - switch (mode & (in|out|trunc|app|binary)) + switch (mode & (in|out|trunc|app|binary|noreplace)) { - case ( out ): return "w"; - case ( out |app ): return "a"; - case ( app ): return "a"; - case ( out|trunc ): return "w"; - case (in ): return "r"; - case (in|out ): return "r+"; - case (in|out|trunc ): return "w+"; - case (in|out |app ): return "a+"; - case (in |app ): return "a+"; - - case ( out |binary): return "wb"; - case ( out |app|binary): return "ab"; - case ( app|binary): return "ab"; - case ( out|trunc |binary): return "wb"; - case (in |binary): return "rb"; - case (in|out |binary): return "r+b"; - case (in|out|trunc |binary): return "w+b"; - case (in|out |app|binary): return "a+b"; - case (in |app|binary): return "a+b"; + case ( out ): return "w"; + case ( out |noreplace): return "wx"; + case ( out|trunc ): return "w"; + case ( out|trunc |noreplace): return "wx"; + case ( out |app ): return "a"; + case ( app ): return "a"; + case (in ): return "r"; + case (in|out ): return "r+"; + case (in|out|trunc ): return "w+"; + case (in|out|trunc |noreplace): return "w+x"; + case (in|out |app ): return "a+"; + case (in |app ): return "a+"; + + case ( out |binary ): return "wb"; + case ( out |binary|noreplace): return "wbx"; + case ( out |app|binary ): return "ab"; + case ( app|binary ): return "ab"; + case ( out|trunc |binary ): return "wb"; + case (in |binary ): return "rb"; + case (in|out |binary ): return "r+b"; + case (in|out|trunc |binary ): return "w+b"; + case (in|out|trunc |binary|noreplace): return "w+bx"; + case (in|out |app|binary ): return "a+b"; + case (in |app|binary ): return "a+b"; default: return 0; // invalid } diff --git a/libstdc++-v3/config/locale/dragonfly/time_members.cc b/libstdc++-v3/config/locale/dragonfly/time_members.cc index c8b621a..5dbf5e5 100644 --- a/libstdc++-v3/config/locale/dragonfly/time_members.cc +++ b/libstdc++-v3/config/locale/dragonfly/time_members.cc @@ -74,7 +74,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data->_M_date_time_era_format = ""; _M_data->_M_am = "AM"; _M_data->_M_pm = "PM"; - _M_data->_M_am_pm_format = ""; + _M_data->_M_am_pm_format = "%I:%M:%S %p"; // Day names, starting with "C"'s Sunday. _M_data->_M_day1 = "Sunday"; @@ -231,7 +231,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data->_M_date_time_era_format = L""; _M_data->_M_am = L"AM"; _M_data->_M_pm = L"PM"; - _M_data->_M_am_pm_format = L""; + _M_data->_M_am_pm_format = L"%I:%M:%S %p"; // Day names, starting with "C"'s Sunday. _M_data->_M_day1 = L"Sunday"; diff --git a/libstdc++-v3/config/locale/generic/time_members.cc b/libstdc++-v3/config/locale/generic/time_members.cc index c45a0a3..7bd16be 100644 --- a/libstdc++-v3/config/locale/generic/time_members.cc +++ b/libstdc++-v3/config/locale/generic/time_members.cc @@ -72,7 +72,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data->_M_date_time_era_format = ""; _M_data->_M_am = "AM"; _M_data->_M_pm = "PM"; - _M_data->_M_am_pm_format = ""; + _M_data->_M_am_pm_format = "%I:%M:%S %p"; // Day names, starting with "C"'s Sunday. _M_data->_M_day1 = "Sunday"; @@ -157,7 +157,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data->_M_date_time_era_format = L""; _M_data->_M_am = L"AM"; _M_data->_M_pm = L"PM"; - _M_data->_M_am_pm_format = L""; + _M_data->_M_am_pm_format = L"%I:%M:%S %p"; // Day names, starting with "C"'s Sunday. _M_data->_M_day1 = L"Sunday"; diff --git a/libstdc++-v3/config/locale/gnu/time_members.cc b/libstdc++-v3/config/locale/gnu/time_members.cc index c98c15c..6233fba 100644 --- a/libstdc++-v3/config/locale/gnu/time_members.cc +++ b/libstdc++-v3/config/locale/gnu/time_members.cc @@ -80,7 +80,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data->_M_date_time_era_format = ""; _M_data->_M_am = "AM"; _M_data->_M_pm = "PM"; - _M_data->_M_am_pm_format = ""; + _M_data->_M_am_pm_format = "%I:%M:%S %p"; // Day names, starting with "C"'s Sunday. _M_data->_M_day1 = "Sunday"; @@ -236,7 +236,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_data->_M_date_time_era_format = L""; _M_data->_M_am = L"AM"; _M_data->_M_pm = L"PM"; - _M_data->_M_am_pm_format = L""; + _M_data->_M_am_pm_format = L"%I:%M:%S %p"; // Day names, starting with "C"'s Sunday. _M_data->_M_day1 = L"Sunday"; diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index 61a14a2..b1a0157 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -21006,7 +21006,7 @@ $as_echo "$ac_has_win32_sleep" >&6; } if test x"$ac_no_sleep" = x"yes"; then -$as_echo "#define NO_SLEEP 1" >>confdefs.h +$as_echo "#define _GLIBCXX_NO_SLEEP 1" >>confdefs.h fi diff --git a/libstdc++-v3/doc/html/manual/api.html b/libstdc++-v3/doc/html/manual/api.html index 2cc44ae..1c7fdaa 100644 --- a/libstdc++-v3/doc/html/manual/api.html +++ b/libstdc++-v3/doc/html/manual/api.html @@ -447,4 +447,12 @@ Dynamic exception specifications should be replaced with <code class="code">noex </p><p> The <code class="literal">bitmap</code>, <code class="literal">mt</code>, and <code class="literal">pool</code> options for <code class="option">--enable-libstdcxx-allocator</code> were removed. +For the <code class="literal">new</code> option, <code class="classname">std::allocator</code> +no longer derives from <code class="classname">__gnu_cxx::new_allocator</code>; +they both derive from <code class="classname">std::__new_allocator</code> instead. +</p><p> +<code class="function">std::condition_variable::wait</code> changed to be +<code class="code">noexcept(false)</code> to allow thread cancellation exceptions to +be thrown from <code class="function">pthread_cond_wait</code> without aborting +the process. </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="abi.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="appendix_porting.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="backwards.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">ABI Policy and Guidelines </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Backwards Compatibility</td></tr></table></div></body></html>
\ No newline at end of file diff --git a/libstdc++-v3/doc/html/manual/memory.html b/libstdc++-v3/doc/html/manual/memory.html index 1681d98..d9abdaf 100644 --- a/libstdc++-v3/doc/html/manual/memory.html +++ b/libstdc++-v3/doc/html/manual/memory.html @@ -140,9 +140,11 @@ <a class="link" href="http://gcc.gnu.org/viewcvs/gcc/trunk/libstdc++-v3/testsuite/performance/23_containers/producer_consumer/associative.cc?view=markup" target="_top">associative</a> containers. </p></li></ol></div><p> - The current default choice for + Since GCC 12 the default choice for <code class="classname">allocator</code> is - <code class="classname">__gnu_cxx::new_allocator</code>. + <code class="classname">std::__new_allocator</code>. + Before GCC 12 it was the <code class="classname">__gnu_cxx::new_allocator</code> + extension (which has identical behaviour). </p></div><div class="section"><div class="titlepage"><div><div><h5 class="title"><a id="allocator.caching"></a>Disabling Memory Caching</h5></div></div></div><p> In use, <code class="classname">allocator</code> may allocate and deallocate using implementation-specific strategies and diff --git a/libstdc++-v3/doc/xml/manual/allocator.xml b/libstdc++-v3/doc/xml/manual/allocator.xml index aaab4e2..2418539 100644 --- a/libstdc++-v3/doc/xml/manual/allocator.xml +++ b/libstdc++-v3/doc/xml/manual/allocator.xml @@ -219,9 +219,11 @@ </orderedlist> <para> - The current default choice for + Since GCC 12 the default choice for <classname>allocator</classname> is - <classname>__gnu_cxx::new_allocator</classname>. + <classname>std::__new_allocator</classname>. + Before GCC 12 it was the <classname>__gnu_cxx::new_allocator</classname> + extension (which has identical behaviour). </para> </section> diff --git a/libstdc++-v3/doc/xml/manual/evolution.xml b/libstdc++-v3/doc/xml/manual/evolution.xml index 271d222..34e44ee 100644 --- a/libstdc++-v3/doc/xml/manual/evolution.xml +++ b/libstdc++-v3/doc/xml/manual/evolution.xml @@ -1036,6 +1036,16 @@ Dynamic exception specifications should be replaced with <code>noexcept</code>. <para> The <literal>bitmap</literal>, <literal>mt</literal>, and <literal>pool</literal> options for <option>--enable-libstdcxx-allocator</option> were removed. +For the <literal>new</literal> option, <classname>std::allocator</classname> +no longer derives from <classname>__gnu_cxx::new_allocator</classname>; +they both derive from <classname>std::__new_allocator</classname> instead. +</para> + +<para> +<function>std::condition_variable::wait</function> changed to be +<code>noexcept(false)</code> to allow thread cancellation exceptions to +be thrown from <function>pthread_cond_wait</function> without aborting +the process. </para> </section> diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 25a8d9c8..f1cf796 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -159,6 +159,7 @@ bits_headers = \ ${bits_srcdir}/mofunc_impl.h \ ${bits_srcdir}/move.h \ ${bits_srcdir}/move_only_function.h \ + ${bits_srcdir}/new_allocator.h \ ${bits_srcdir}/node_handle.h \ ${bits_srcdir}/ostream.tcc \ ${bits_srcdir}/ostream_insert.h \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 47a5d98..4e4a240 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -509,6 +509,7 @@ bits_headers = \ ${bits_srcdir}/mofunc_impl.h \ ${bits_srcdir}/move.h \ ${bits_srcdir}/move_only_function.h \ + ${bits_srcdir}/new_allocator.h \ ${bits_srcdir}/node_handle.h \ ${bits_srcdir}/ostream.tcc \ ${bits_srcdir}/ostream_insert.h \ diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 9e18aad..a104adc 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -893,7 +893,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cpp_lib_atomic_wait _GLIBCXX_ALWAYS_INLINE void wait(__pointer_type __old, - memory_order __m = memory_order_seq_cst) noexcept + memory_order __m = memory_order_seq_cst) const noexcept { std::__atomic_wait_address_v(&_M_p, __old, [__m, this] diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h index efbe3da..ba83398 100644 --- a/libstdc++-v3/include/bits/atomic_timed_wait.h +++ b/libstdc++-v3/include/bits/atomic_timed_wait.h @@ -137,6 +137,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // (e.g. __ulock_wait())which is better than pthread_cond_clockwait #endif // ! PLATFORM_TIMED_WAIT +#ifdef _GLIBCXX_HAS_GTHREADS // Returns true if wait ended before timeout. // _Clock must be either steady_clock or system_clock. template<typename _Clock, typename _Dur> @@ -192,6 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; } } +#endif // _GLIBCXX_HAS_GTHREADS struct __timed_waiter_pool : __waiter_pool_base { @@ -239,6 +241,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_deadline <= __now) return false; + // FIXME: this_thread::sleep_for not available #ifdef _GLIBCXX_NO_SLEEP + auto __elapsed = __now - _M_t0; if (__elapsed > 128ms) { diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 4007a8d..3da2f80 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -1382,7 +1382,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX20_CONSTEXPR basic_string& append(const basic_string& __str) - { return _M_append(__str._M_data(), __str.size()); } + { return this->append(__str._M_data(), __str.size()); } /** * @brief Append a substring. @@ -1400,9 +1400,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX20_CONSTEXPR basic_string& append(const basic_string& __str, size_type __pos, size_type __n = npos) - { return _M_append(__str._M_data() - + __str._M_check(__pos, "basic_string::append"), - __str._M_limit(__pos, __n)); } + { return this->append(__str._M_data() + + __str._M_check(__pos, "basic_string::append"), + __str._M_limit(__pos, __n)); } /** * @brief Append a C substring. diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h index da3e0ff..1323958 100644 --- a/libstdc++-v3/include/bits/char_traits.h +++ b/libstdc++-v3/include/bits/char_traits.h @@ -54,6 +54,11 @@ namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#pragma GCC diagnostic ignored "-Wstringop-overread" +#pragma GCC diagnostic ignored "-Warray-bounds" + /** * @brief Mapping from character type to associated types. * @@ -990,6 +995,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // namespace __detail #endif // C++20 +#pragma GCC diagnostic pop + _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/include/bits/cow_string.h b/libstdc++-v3/include/bits/cow_string.h index 389b395..b21a742 100644 --- a/libstdc++-v3/include/bits/cow_string.h +++ b/libstdc++-v3/include/bits/cow_string.h @@ -3366,10 +3366,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION basic_string<_CharT, _Traits, _Alloc>:: _M_leak_hard() { -#if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 - if (_M_rep() == &_S_empty_rep()) + // No need to create a new copy of an empty string when a non-const + // reference/pointer/iterator into it is obtained. Modifying the + // trailing null character is undefined, so the ref/pointer/iterator + // is effectively const anyway. + if (this->empty()) return; -#endif + if (_M_rep()->_M_is_shared()) _M_mutate(0, 0, 0); _M_rep()->_M_set_leaked(); diff --git a/libstdc++-v3/include/bits/ios_base.h b/libstdc++-v3/include/bits/ios_base.h index d6626d4..5db0552 100644 --- a/libstdc++-v3/include/bits/ios_base.h +++ b/libstdc++-v3/include/bits/ios_base.h @@ -116,6 +116,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_in = 1L << 3, _S_out = 1L << 4, _S_trunc = 1L << 5, + _S_noreplace = 1L << 6, _S_ios_openmode_end = 1L << 16, _S_ios_openmode_max = __INT_MAX__, _S_ios_openmode_min = ~__INT_MAX__ @@ -466,6 +467,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Truncate an existing stream when opening. Default for @c ofstream. static const openmode trunc = _S_trunc; + static const openmode __noreplace = _S_noreplace; + +#if __cplusplus >= 202100L +#define __cpp_lib_ios_noreplace 202200L + /// Open a file in exclusive mode. + static const openmode noreplace = _S_noreplace; +#endif + // 27.4.2.1.5 Type ios_base::seekdir /** * @brief This is an enumerated type. diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.h b/libstdc++-v3/include/bits/locale_facets_nonio.h index e518df9..501824f 100644 --- a/libstdc++-v3/include/bits/locale_facets_nonio.h +++ b/libstdc++-v3/include/bits/locale_facets_nonio.h @@ -243,6 +243,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif void + _M_am_pm_format(const _CharT** __ampm_format) const + { + __ampm_format[0] = _M_data->_M_am_pm_format; + } + + void _M_am_pm(const _CharT** __ampm) const { __ampm[0] = _M_data->_M_am; diff --git a/libstdc++-v3/include/bits/locale_facets_nonio.tcc b/libstdc++-v3/include/bits/locale_facets_nonio.tcc index 51c23d8..48d5e8c 100644 --- a/libstdc++-v3/include/bits/locale_facets_nonio.tcc +++ b/libstdc++-v3/include/bits/locale_facets_nonio.tcc @@ -684,7 +684,7 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 time_get<_CharT, _InIter>::do_date_order() const { return time_base::no_order; } - // Expand a strftime format string and parse it. E.g., do_get_date() may + // Expand a strptime format string and parse it. E.g., do_get_date() may // pass %m/%d/%Y => extracted characters. template<typename _CharT, typename _InIter> _InIter @@ -714,41 +714,27 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 const char* __cs; _CharT __wcs[10]; case 'a': - // Abbreviated weekday name [tm_wday] - const char_type* __days1[7]; - __tp._M_days_abbreviated(__days1); - __beg = _M_extract_name(__beg, __end, __mem, __days1, - 7, __io, __tmperr); - if (!__tmperr) - __tm->tm_wday = __mem; - break; case 'A': - // Weekday name [tm_wday]. - const char_type* __days2[7]; - __tp._M_days(__days2); - __beg = _M_extract_name(__beg, __end, __mem, __days2, - 7, __io, __tmperr); + // Weekday name (possibly abbreviated) [tm_wday] + const char_type* __days[14]; + __tp._M_days(&__days[0]); + __tp._M_days_abbreviated(&__days[7]); + __beg = _M_extract_name(__beg, __end, __mem, __days, + 14, __io, __tmperr); if (!__tmperr) - __tm->tm_wday = __mem; + __tm->tm_wday = __mem % 7; break; case 'h': case 'b': - // Abbreviated month name [tm_mon] - const char_type* __months1[12]; - __tp._M_months_abbreviated(__months1); - __beg = _M_extract_name(__beg, __end, __mem, - __months1, 12, __io, __tmperr); - if (!__tmperr) - __tm->tm_mon = __mem; - break; case 'B': - // Month name [tm_mon]. - const char_type* __months2[12]; - __tp._M_months(__months2); + // Month name (possibly abbreviated) [tm_mon] + const char_type* __months[24]; + __tp._M_months(&__months[0]); + __tp._M_months_abbreviated(&__months[12]); __beg = _M_extract_name(__beg, __end, __mem, - __months2, 12, __io, __tmperr); + __months, 24, __io, __tmperr); if (!__tmperr) - __tm->tm_mon = __mem; + __tm->tm_mon = __mem % 12; break; case 'c': // Default time and date representation. @@ -758,21 +744,12 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 __tm, __dt[0]); break; case 'd': - // Day [01, 31]. [tm_mday] - __beg = _M_extract_num(__beg, __end, __mem, 1, 31, 2, - __io, __tmperr); - if (!__tmperr) - __tm->tm_mday = __mem; - break; case 'e': - // Day [1, 31], with single digits preceded by - // space. [tm_mday] + // Day [1, 31]. [tm_mday] if (__ctype.is(ctype_base::space, *__beg)) - __beg = _M_extract_num(++__beg, __end, __mem, 1, 9, - 1, __io, __tmperr); - else - __beg = _M_extract_num(__beg, __end, __mem, 10, 31, - 2, __io, __tmperr); + ++__beg; + __beg = _M_extract_num(__beg, __end, __mem, 1, 31, 2, + __io, __tmperr); if (!__tmperr) __tm->tm_mday = __mem; break; @@ -795,7 +772,7 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 __beg = _M_extract_num(__beg, __end, __mem, 1, 12, 2, __io, __tmperr); if (!__tmperr) - __tm->tm_hour = __mem; + __tm->tm_hour = __mem % 12; break; case 'm': // Month [01, 12]. [tm_mon] @@ -812,10 +789,29 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 __tm->tm_min = __mem; break; case 'n': - if (__ctype.narrow(*__beg, 0) == '\n') + case 't': + while (__beg != __end + && __ctype.is(ctype_base::space, *__beg)) ++__beg; - else - __tmperr |= ios_base::failbit; + break; + case 'p': + // Locale's a.m. or p.m. + const char_type* __ampm[2]; + __tp._M_am_pm(&__ampm[0]); + if (!__ampm[0][0] || !__ampm[1][0]) + break; + __beg = _M_extract_name(__beg, __end, __mem, __ampm, + 2, __io, __tmperr); + // FIXME: This only works if %I comes before %p. + if (!__tmperr && __mem) + __tm->tm_hour += 12; + break; + case 'r': + // Locale's 12-hour clock time format (in C %I:%M:%S %p). + const char_type* __ampm_format; + __tp._M_am_pm_format(&__ampm_format); + __beg = _M_extract_via_format(__beg, __end, __io, __tmperr, + __tm, __ampm_format); break; case 'R': // Equivalent to (%H:%M). @@ -836,12 +832,6 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 if (!__tmperr) __tm->tm_sec = __mem; break; - case 't': - if (__ctype.narrow(*__beg, 0) == '\t') - ++__beg; - else - __tmperr |= ios_base::failbit; - break; case 'T': // Equivalent to (%H:%M:%S). __cs = "%H:%M:%S"; @@ -899,11 +889,24 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 else __tmperr |= ios_base::failbit; break; + case '%': + if (*__beg == __ctype.widen('%')) + ++__beg; + else + __tmperr |= ios_base::failbit; + break; default: // Not recognized. __tmperr |= ios_base::failbit; } } + else if (__ctype.is(ctype_base::space, __format[__i])) + { + // Skip any whitespace. + while (__beg != __end + && __ctype.is(ctype_base::space, *__beg)) + ++__beg; + } else { // Verify format and input match, extract and discard. @@ -930,10 +933,6 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 const locale& __loc = __io._M_getloc(); const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); - // As-is works for __len = 1, 2, 4, the values actually used. - int __mult = __len == 2 ? 10 : (__len == 4 ? 1000 : 1); - - ++__min; size_t __i = 0; int __value = 0; for (; __beg != __end && __i < __len; ++__beg, (void)++__i) @@ -942,19 +941,20 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 if (__c >= '0' && __c <= '9') { __value = __value * 10 + (__c - '0'); - const int __valuec = __value * __mult; - if (__valuec > __max || __valuec + __mult < __min) + if (__value > __max) break; - __mult /= 10; } else break; } - if (__i == __len) - __member = __value; // Special encoding for do_get_year, 'y', and 'Y' above. - else if (__len == 4 && __i == 2) + if (__len == 4 && __i == 2) __member = __value - 100; + else if (__len == 4 && __i == 4) + __member = __value; + else if (__len == 2 && __i && __i <= 2 + && __value >= __min && __value <= __max) + __member = __value; else __err |= ios_base::failbit; @@ -962,7 +962,10 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 } // Assumptions: - // All elements in __names are unique. + // All elements in __names are unique, except if __indexlen is + // even __names in the first half could be the same as corresponding + // __names in the second half (May is abbreviated as May). Some __names + // elements could be prefixes of other __names elements. template<typename _CharT, typename _InIter> _InIter time_get<_CharT, _InIter>:: @@ -974,12 +977,15 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 const locale& __loc = __io._M_getloc(); const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc); - int* __matches = static_cast<int*>(__builtin_alloca(sizeof(int) - * __indexlen)); + size_t* __matches + = static_cast<size_t*>(__builtin_alloca(2 * sizeof(size_t) + * __indexlen)); + size_t* __lengths = __matches + __indexlen; size_t __nmatches = 0; size_t __pos = 0; bool __testvalid = true; const char_type* __name; + bool __begupdated = false; // Look for initial matches. // NB: Some of the locale data is in the form of all lowercase @@ -991,26 +997,88 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 for (size_t __i1 = 0; __i1 < __indexlen; ++__i1) if (__c == __names[__i1][0] || __c == __ctype.toupper(__names[__i1][0])) - __matches[__nmatches++] = __i1; + { + __lengths[__nmatches] + = __traits_type::length(__names[__i1]); + __matches[__nmatches++] = __i1; + } } while (__nmatches > 1) { // Find smallest matching string. - size_t __minlen = __traits_type::length(__names[__matches[0]]); + size_t __minlen = __lengths[0]; for (size_t __i2 = 1; __i2 < __nmatches; ++__i2) - __minlen = std::min(__minlen, - __traits_type::length(__names[__matches[__i2]])); - ++__beg; + __minlen = std::min(__minlen, __lengths[__i2]); ++__pos; + ++__beg; + if (__pos == __minlen) + { + // If some match has remaining length of 0, + // need to decide if any match with remaining + // length non-zero matches the next character. + // If so, remove all matches with remaining length + // 0 from consideration, otherwise keep only matches + // with remaining length 0. + bool __match_longer = false; + + if (__beg != __end) + for (size_t __i3 = 0; __i3 < __nmatches; ++__i3) + { + __name = __names[__matches[__i3]]; + if (__lengths[__i3] > __pos && (__name[__pos] == *__beg)) + { + __match_longer = true; + break; + } + } + for (size_t __i4 = 0; __i4 < __nmatches;) + if (__match_longer == (__lengths[__i4] == __pos)) + { + __matches[__i4] = __matches[--__nmatches]; + __lengths[__i4] = __lengths[__nmatches]; + } + else + ++__i4; + if (__match_longer) + { + __minlen = __lengths[0]; + for (size_t __i5 = 1; __i5 < __nmatches; ++__i5) + __minlen = std::min(__minlen, __lengths[__i5]); + } + else + { + // Deal with May being full as well as abbreviated month + // name. Pick the smaller index. + if (__nmatches == 2 && (__indexlen & 1) == 0) + { + if (__matches[0] < __indexlen / 2) + { + if (__matches[1] == __matches[0] + __indexlen / 2) + __nmatches = 1; + } + else if (__matches[1] == __matches[0] - __indexlen / 2) + { + __matches[0] = __matches[1]; + __lengths[0] = __lengths[1]; + __nmatches = 1; + } + } + __begupdated = true; + break; + } + } if (__pos < __minlen && __beg != __end) - for (size_t __i3 = 0; __i3 < __nmatches;) + for (size_t __i6 = 0; __i6 < __nmatches;) { - __name = __names[__matches[__i3]]; + __name = __names[__matches[__i6]]; if (!(__name[__pos] == *__beg)) - __matches[__i3] = __matches[--__nmatches]; + { + __matches[__i6] = __matches[--__nmatches]; + __lengths[__i6] = __lengths[__nmatches]; + } else - ++__i3; + ++__i6; } else break; @@ -1019,10 +1087,13 @@ _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 if (__nmatches == 1) { // Make sure found name is completely extracted. - ++__beg; - ++__pos; + if (!__begupdated) + { + ++__beg; + ++__pos; + } __name = __names[__matches[0]]; - const size_t __len = __traits_type::length(__name); + const size_t __len = __lengths[0]; while (__pos < __len && __beg != __end && __name[__pos] == *__beg) ++__beg, (void)++__pos; diff --git a/libstdc++-v3/include/bits/new_allocator.h b/libstdc++-v3/include/bits/new_allocator.h new file mode 100644 index 0000000..4d85612 --- /dev/null +++ b/libstdc++-v3/include/bits/new_allocator.h @@ -0,0 +1,223 @@ +// Allocator that wraps operator new -*- C++ -*- + +// Copyright (C) 2001-2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file bits/new_allocator.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _STD_NEW_ALLOCATOR_H +#define _STD_NEW_ALLOCATOR_H 1 + +#include <bits/c++config.h> +#include <new> +#include <bits/functexcept.h> +#include <bits/move.h> +#if __cplusplus >= 201103L +#include <type_traits> +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @brief An allocator that uses global new, as per C++03 [20.4.1]. + * @ingroup allocators + * + * This is precisely the allocator defined in the C++ Standard. + * - all allocation calls operator new + * - all deallocation calls operator delete + * + * @tparam _Tp Type of allocated object. + */ + template<typename _Tp> + class __new_allocator + { + public: + typedef _Tp value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; +#if __cplusplus <= 201703L + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + + template<typename _Tp1> + struct rebind + { typedef __new_allocator<_Tp1> other; }; +#endif + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2103. propagate_on_container_move_assignment + typedef std::true_type propagate_on_container_move_assignment; +#endif + + _GLIBCXX20_CONSTEXPR + __new_allocator() _GLIBCXX_USE_NOEXCEPT { } + + _GLIBCXX20_CONSTEXPR + __new_allocator(const __new_allocator&) _GLIBCXX_USE_NOEXCEPT { } + + template<typename _Tp1> + _GLIBCXX20_CONSTEXPR + __new_allocator(const __new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { } + +#if __cplusplus <= 201703L + ~__new_allocator() _GLIBCXX_USE_NOEXCEPT { } + + pointer + address(reference __x) const _GLIBCXX_NOEXCEPT + { return std::__addressof(__x); } + + const_pointer + address(const_reference __x) const _GLIBCXX_NOEXCEPT + { return std::__addressof(__x); } +#endif + +#if __has_builtin(__builtin_operator_new) >= 201802L +# define _GLIBCXX_OPERATOR_NEW __builtin_operator_new +# define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete +#else +# define _GLIBCXX_OPERATOR_NEW ::operator new +# define _GLIBCXX_OPERATOR_DELETE ::operator delete +#endif + + // NB: __n is permitted to be 0. The C++ standard says nothing + // about what the return value is when __n == 0. + _GLIBCXX_NODISCARD _Tp* + allocate(size_type __n, const void* = static_cast<const void*>(0)) + { +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3308. std::allocator<void>().allocate(n) + static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types"); +#endif + + if (__builtin_expect(__n > this->_M_max_size(), false)) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3190. allocator::allocate sometimes returns too little storage + if (__n > (std::size_t(-1) / sizeof(_Tp))) + std::__throw_bad_array_new_length(); + std::__throw_bad_alloc(); + } + +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + std::align_val_t __al = std::align_val_t(alignof(_Tp)); + return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp), + __al)); + } +#endif + return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp))); + } + + // __p is not permitted to be a null pointer. + void + deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__))) + { +#if __cpp_sized_deallocation +# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp) +#else +# define _GLIBCXX_SIZED_DEALLOC(p, n) (p) +#endif + +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n), + std::align_val_t(alignof(_Tp))); + return; + } +#endif + _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); + } + +#undef _GLIBCXX_SIZED_DEALLOC +#undef _GLIBCXX_OPERATOR_DELETE +#undef _GLIBCXX_OPERATOR_NEW + +#if __cplusplus <= 201703L + size_type + max_size() const _GLIBCXX_USE_NOEXCEPT + { return _M_max_size(); } + +#if __cplusplus >= 201103L + template<typename _Up, typename... _Args> + void + construct(_Up* __p, _Args&&... __args) + noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) + { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } + + template<typename _Up> + void + destroy(_Up* __p) + noexcept(std::is_nothrow_destructible<_Up>::value) + { __p->~_Up(); } +#else + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 402. wrong new expression in [some_] allocator::construct + void + construct(pointer __p, const _Tp& __val) + { ::new((void *)__p) _Tp(__val); } + + void + destroy(pointer __p) { __p->~_Tp(); } +#endif +#endif // ! C++20 + + template<typename _Up> + friend _GLIBCXX20_CONSTEXPR bool + operator==(const __new_allocator&, const __new_allocator<_Up>&) + _GLIBCXX_NOTHROW + { return true; } + +#if __cpp_impl_three_way_comparison < 201907L + template<typename _Up> + friend _GLIBCXX20_CONSTEXPR bool + operator!=(const __new_allocator&, const __new_allocator<_Up>&) + _GLIBCXX_NOTHROW + { return false; } +#endif + + private: + _GLIBCXX_CONSTEXPR size_type + _M_max_size() const _GLIBCXX_USE_NOEXCEPT + { +#if __PTRDIFF_MAX__ < __SIZE_MAX__ + return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp); +#else + return std::size_t(-1) / sizeof(_Tp); +#endif + } + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif diff --git a/libstdc++-v3/include/bits/std_mutex.h b/libstdc++-v3/include/bits/std_mutex.h index 357c689..6618a54 100644 --- a/libstdc++-v3/include/bits/std_mutex.h +++ b/libstdc++-v3/include/bits/std_mutex.h @@ -149,7 +149,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Expects: Calling thread has locked __m. void - wait(mutex& __m) noexcept + wait(mutex& __m) { int __e __attribute__((__unused__)) = __gthread_cond_wait(&_M_cond, __m.native_handle()); @@ -157,14 +157,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } void - wait_until(mutex& __m, timespec& __abs_time) noexcept + wait_until(mutex& __m, timespec& __abs_time) { __gthread_cond_timedwait(&_M_cond, __m.native_handle(), &__abs_time); } #ifdef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT void - wait_until(mutex& __m, clockid_t __clock, timespec& __abs_time) noexcept + wait_until(mutex& __m, clockid_t __clock, timespec& __abs_time) { pthread_cond_clockwait(&_M_cond, __m.native_handle(), __clock, &__abs_time); diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index f6504ec..6bd860b 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -574,6 +574,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator<=>(const reverse_iterator<_IteratorL>& __x, const reverse_iterator<_IteratorR>& __y) { return __y.base() <=> __x.base(); } + + // Additional, non-standard overloads to avoid ambiguities with greedy, + // unconstrained overloads in associated namespaces. + + template<typename _Iterator> + [[nodiscard]] + constexpr bool + operator==(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + requires requires { { __x.base() == __y.base() } -> convertible_to<bool>; } + { return __x.base() == __y.base(); } + + template<three_way_comparable _Iterator> + [[nodiscard]] + constexpr compare_three_way_result_t<_Iterator, _Iterator> + operator<=>(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return __y.base() <=> __x.base(); } #endif // C++20 ///@} @@ -1161,6 +1179,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } + + template<typename _Iterator, typename _Container> + [[nodiscard]] + constexpr bool + operator==(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + noexcept(noexcept(__lhs.base() == __rhs.base())) + requires requires { + { __lhs.base() == __rhs.base() } -> std::convertible_to<bool>; + } + { return __lhs.base() == __rhs.base(); } + + template<typename _Iterator, typename _Container> + [[nodiscard]] + constexpr std::__detail::__synth3way_t<_Iterator> + operator<=>(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + noexcept(noexcept(std::__detail::__synth3way(__lhs.base(), __rhs.base()))) + { return std::__detail::__synth3way(__lhs.base(), __rhs.base()); } #else // Forward iterator requirements template<typename _IteratorL, typename _IteratorR, typename _Container> @@ -1689,14 +1726,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif { return !(__x < __y); } -#if ! (__cplusplus > 201703L && __cpp_lib_concepts) // Note: See __normal_iterator operators note from Gaby to understand // why we have these extra overloads for some move_iterator operators. - // These extra overloads are not needed in C++20, because the ones above - // are constrained with a requires-clause and so overload resolution will - // prefer them to greedy unconstrained function templates. - template<typename _Iterator> [[__nodiscard__]] inline _GLIBCXX17_CONSTEXPR bool @@ -1704,6 +1736,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const move_iterator<_Iterator>& __y) { return __x.base() == __y.base(); } +#if __cpp_lib_three_way_comparison + template<three_way_comparable _Iterator> + [[__nodiscard__]] + constexpr compare_three_way_result_t<_Iterator> + operator<=>(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return __x.base() <=> __y.base(); } +#else template<typename _Iterator> [[__nodiscard__]] inline _GLIBCXX17_CONSTEXPR bool diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index cc87f11..658d586 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -154,6 +154,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef __gnu_cxx::__alloc_traits<_Pair_alloc_type> _Alloc_traits; +#if __cplusplus >= 201703L + template<typename _Up, typename _Vp = remove_reference_t<_Up>> + static constexpr bool __usable_key + = __or_v<is_same<const _Vp, const _Key>, + __and_<is_scalar<_Vp>, is_scalar<_Key>>>; +#endif + public: // many of these are specified differently in ISO, but the following are // "functionally equivalent" @@ -574,7 +581,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template<typename... _Args> std::pair<iterator, bool> emplace(_Args&&... __args) - { return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); } + { +#if __cplusplus >= 201703L + if constexpr (sizeof...(_Args) == 2) + if constexpr (is_same_v<allocator_type, allocator<value_type>>) + { + auto&& [__a, __v] = pair<_Args&...>(__args...); + if constexpr (__usable_key<decltype(__a)>) + { + const key_type& __k = __a; + iterator __i = lower_bound(__k); + if (__i == end() || key_comp()(__k, (*__i).first)) + { + __i = emplace_hint(__i, std::forward<_Args>(__args)...); + return {__i, true}; + } + return {__i, false}; + } + } +#endif + return _M_t._M_emplace_unique(std::forward<_Args>(__args)...); + } /** * @brief Attempts to build and insert a std::pair into the %map. @@ -814,7 +841,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __enable_if_t<is_constructible<value_type, _Pair>::value, pair<iterator, bool>> insert(_Pair&& __x) - { return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); } + { +#if __cplusplus >= 201703L + using _P2 = remove_reference_t<_Pair>; + if constexpr (__is_pair<_P2>) + if constexpr (is_same_v<allocator_type, allocator<value_type>>) + if constexpr (__usable_key<typename _P2::first_type>) + { + const key_type& __k = __x.first; + iterator __i = lower_bound(__k); + if (__i == end() || key_comp()(__k, (*__i).first)) + { + __i = emplace_hint(__i, std::forward<_Pair>(__x)); + return {__i, true}; + } + return {__i, false}; + } +#endif + return _M_t._M_emplace_unique(std::forward<_Pair>(__x)); + } #endif /// @} diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 6081e0c..5f7b6093 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -777,6 +777,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp1, typename _Tp2> inline constexpr size_t tuple_size_v<const pair<_Tp1, _Tp2>> = 2; + + template<typename _Tp> + inline constexpr bool __is_pair = false; + + template<typename _Tp, typename _Up> + inline constexpr bool __is_pair<pair<_Tp, _Up>> = true; + + template<typename _Tp, typename _Up> + inline constexpr bool __is_pair<const pair<_Tp, _Up>> = true; #endif /// @cond undocumented diff --git a/libstdc++-v3/include/bits/uses_allocator_args.h b/libstdc++-v3/include/bits/uses_allocator_args.h index 8b548ff..e1fd7e7 100644 --- a/libstdc++-v3/include/bits/uses_allocator_args.h +++ b/libstdc++-v3/include/bits/uses_allocator_args.h @@ -56,12 +56,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template<typename _Tp> - inline constexpr bool __is_pair = false; - template<typename _Tp, typename _Up> - inline constexpr bool __is_pair<pair<_Tp, _Up>> = true; - template<typename _Tp, typename _Up> - inline constexpr bool __is_pair<const pair<_Tp, _Up>> = true; template<typename _Tp> concept _Std_pair = __is_pair<_Tp>; diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource index 82d324c..37ac95f 100644 --- a/libstdc++-v3/include/experimental/memory_resource +++ b/libstdc++-v3/include/experimental/memory_resource @@ -40,7 +40,7 @@ #include <atomic> // atomic #include <new> // placement new #include <cstddef> // max_align_t -#include <ext/new_allocator.h> +#include <bits/new_allocator.h> #include <debug/assertions.h> /// @cond @@ -503,7 +503,7 @@ namespace pmr { inline memory_resource* new_delete_resource() noexcept { - using type = resource_adaptor<__gnu_cxx::new_allocator<char>>; + using type = resource_adaptor<std::__new_allocator<char>>; alignas(type) static unsigned char __buf[sizeof(type)]; static type* __r = new(__buf) type; return __r; diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h index 7c48c82..5cb1b97 100644 --- a/libstdc++-v3/include/ext/new_allocator.h +++ b/libstdc++-v3/include/ext/new_allocator.h @@ -29,13 +29,7 @@ #ifndef _NEW_ALLOCATOR_H #define _NEW_ALLOCATOR_H 1 -#include <bits/c++config.h> -#include <new> -#include <bits/functexcept.h> -#include <bits/move.h> -#if __cplusplus >= 201103L -#include <type_traits> -#endif +#include <bits/new_allocator.h> namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { @@ -52,168 +46,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @tparam _Tp Type of allocated object. */ template<typename _Tp> - class new_allocator + class new_allocator : public std::__new_allocator<_Tp> { public: - typedef _Tp value_type; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; #if __cplusplus <= 201703L - typedef _Tp* pointer; - typedef const _Tp* const_pointer; - typedef _Tp& reference; - typedef const _Tp& const_reference; - template<typename _Tp1> struct rebind { typedef new_allocator<_Tp1> other; }; #endif -#if __cplusplus >= 201103L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 2103. propagate_on_container_move_assignment - typedef std::true_type propagate_on_container_move_assignment; -#endif - - _GLIBCXX20_CONSTEXPR new_allocator() _GLIBCXX_USE_NOEXCEPT { } - _GLIBCXX20_CONSTEXPR new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { } template<typename _Tp1> - _GLIBCXX20_CONSTEXPR new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { } - -#if __cplusplus <= 201703L - ~new_allocator() _GLIBCXX_USE_NOEXCEPT { } - - pointer - address(reference __x) const _GLIBCXX_NOEXCEPT - { return std::__addressof(__x); } - - const_pointer - address(const_reference __x) const _GLIBCXX_NOEXCEPT - { return std::__addressof(__x); } -#endif - -#if __has_builtin(__builtin_operator_new) >= 201802L -# define _GLIBCXX_OPERATOR_NEW __builtin_operator_new -# define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete -#else -# define _GLIBCXX_OPERATOR_NEW ::operator new -# define _GLIBCXX_OPERATOR_DELETE ::operator delete -#endif - - // NB: __n is permitted to be 0. The C++ standard says nothing - // about what the return value is when __n == 0. - _GLIBCXX_NODISCARD _Tp* - allocate(size_type __n, const void* = static_cast<const void*>(0)) - { -#if __cplusplus >= 201103L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3308. std::allocator<void>().allocate(n) - static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types"); -#endif - - if (__builtin_expect(__n > this->_M_max_size(), false)) - { - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3190. allocator::allocate sometimes returns too little storage - if (__n > (std::size_t(-1) / sizeof(_Tp))) - std::__throw_bad_array_new_length(); - std::__throw_bad_alloc(); - } - -#if __cpp_aligned_new - if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - { - std::align_val_t __al = std::align_val_t(alignof(_Tp)); - return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp), - __al)); - } -#endif - return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp))); - } - - // __p is not permitted to be a null pointer. - void - deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__))) - { -#if __cpp_sized_deallocation -# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp) -#else -# define _GLIBCXX_SIZED_DEALLOC(p, n) (p) -#endif - -#if __cpp_aligned_new - if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) - { - _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n), - std::align_val_t(alignof(_Tp))); - return; - } -#endif - _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n)); - } - -#undef _GLIBCXX_SIZED_DEALLOC -#undef _GLIBCXX_OPERATOR_DELETE -#undef _GLIBCXX_OPERATOR_NEW - -#if __cplusplus <= 201703L - size_type - max_size() const _GLIBCXX_USE_NOEXCEPT - { return _M_max_size(); } - -#if __cplusplus >= 201103L - template<typename _Up, typename... _Args> - void - construct(_Up* __p, _Args&&... __args) - noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) - { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } - - template<typename _Up> - void - destroy(_Up* __p) - noexcept(std::is_nothrow_destructible<_Up>::value) - { __p->~_Up(); } -#else - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 402. wrong new expression in [some_] allocator::construct - void - construct(pointer __p, const _Tp& __val) - { ::new((void *)__p) _Tp(__val); } - - void - destroy(pointer __p) { __p->~_Tp(); } -#endif -#endif // ! C++20 - - template<typename _Up> - friend _GLIBCXX20_CONSTEXPR bool - operator==(const new_allocator&, const new_allocator<_Up>&) - _GLIBCXX_NOTHROW - { return true; } - -#if __cpp_impl_three_way_comparison < 201907L - template<typename _Up> - friend _GLIBCXX20_CONSTEXPR bool - operator!=(const new_allocator&, const new_allocator<_Up>&) - _GLIBCXX_NOTHROW - { return false; } -#endif - - private: - _GLIBCXX_CONSTEXPR size_type - _M_max_size() const _GLIBCXX_USE_NOEXCEPT - { -#if __PTRDIFF_MAX__ < __SIZE_MAX__ - return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp); -#else - return std::size_t(-1) / sizeof(_Tp); -#endif - } }; _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 936dd50..9b827b4 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -646,9 +646,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __cmpexch_failure_order(__m)); } -#if __cpp_lib_atomic_wait +#if __cpp_lib_atomic_wait void - wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) noexcept + wait(__pointer_type __old, memory_order __m = memory_order_seq_cst) const noexcept { _M_b.wait(__old, __m); } // TODO add const volatile overload @@ -1434,12 +1434,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> inline void - atomic_notify_one(atomic<_Tp>* __a) noexcept + atomic_notify_one(const atomic<_Tp>* __a) noexcept { __a->notify_one(); } template<typename _Tp> inline void - atomic_notify_all(atomic<_Tp>* __a) noexcept + atomic_notify_all(const atomic<_Tp>* __a) noexcept { __a->notify_all(); } #endif // __cpp_lib_atomic_wait diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index 4fcec6a..3930cf4 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -92,7 +92,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION notify_all() noexcept; void - wait(unique_lock<mutex>& __lock) noexcept; + wait(unique_lock<mutex>& __lock); template<typename _Predicate> void diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index eb612f5..23890037 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -296,6 +296,7 @@ #define __cpp_lib_adaptor_iterator_pair_constructor 202106L #define __cpp_lib_byteswap 202110L #define __cpp_lib_invoke_r 202106L +#define __cpp_lib_ios_noreplace 202200L #define __cpp_lib_is_scoped_enum 202011L #if __cpp_lib_concepts # define __cpp_lib_monadic_optional 202110L diff --git a/libstdc++-v3/libsupc++/exception_ptr.h b/libstdc++-v3/libsupc++/exception_ptr.h index f9dffd5..8c700e64 100644 --- a/libstdc++-v3/libsupc++/exception_ptr.h +++ b/libstdc++-v3/libsupc++/exception_ptr.h @@ -39,6 +39,10 @@ #include <typeinfo> #include <new> +#if __cplusplus >= 201103L +# include <bits/move.h> +#endif + #ifdef _GLIBCXX_EH_PTR_RELOPS_COMPAT # define _GLIBCXX_EH_PTR_USED __attribute__((__used__)) #else @@ -175,13 +179,14 @@ namespace std _GLIBCXX_EH_PTR_USED inline - exception_ptr::exception_ptr() _GLIBCXX_NOEXCEPT + exception_ptr::exception_ptr() _GLIBCXX_USE_NOEXCEPT : _M_exception_object(0) { } _GLIBCXX_EH_PTR_USED inline - exception_ptr::exception_ptr(const exception_ptr& __other) _GLIBCXX_NOEXCEPT + exception_ptr::exception_ptr(const exception_ptr& __other) + _GLIBCXX_USE_NOEXCEPT : _M_exception_object(__other._M_exception_object) { if (_M_exception_object) @@ -220,6 +225,7 @@ namespace std /// @cond undocumented template<typename _Ex> + _GLIBCXX_CDTOR_CALLABI inline void __dest_thunk(void* __x) { static_cast<_Ex*>(__x)->~_Ex(); } @@ -228,26 +234,28 @@ namespace std } // namespace __exception_ptr /// Obtain an exception_ptr pointing to a copy of the supplied object. +#if (__cplusplus >= 201103L && __cpp_rtti) || __cpp_exceptions template<typename _Ex> - exception_ptr + exception_ptr make_exception_ptr(_Ex __ex) _GLIBCXX_USE_NOEXCEPT { -#if __cpp_exceptions && __cpp_rtti && !_GLIBCXX_HAVE_CDTOR_CALLABI +#if __cplusplus >= 201103L && __cpp_rtti + using _Ex2 = typename decay<_Ex>::type; void* __e = __cxxabiv1::__cxa_allocate_exception(sizeof(_Ex)); (void) __cxxabiv1::__cxa_init_primary_exception( - __e, const_cast<std::type_info*>(&typeid(__ex)), - __exception_ptr::__dest_thunk<_Ex>); - try + __e, const_cast<std::type_info*>(&typeid(_Ex)), + __exception_ptr::__dest_thunk<_Ex2>); + __try { - ::new (__e) _Ex(__ex); - return exception_ptr(__e); + ::new (__e) _Ex2(__ex); + return exception_ptr(__e); } - catch(...) + __catch(...) { __cxxabiv1::__cxa_free_exception(__e); return current_exception(); } -#elif __cpp_exceptions +#else try { throw __ex; @@ -256,10 +264,17 @@ namespace std { return current_exception(); } -#else // no RTTI and no exceptions - return exception_ptr(); #endif } +#else // no RTTI and no exceptions + // This is always_inline so the linker will never use this useless definition + // instead of a working one compiled with RTTI and/or exceptions enabled. + template<typename _Ex> + __attribute__ ((__always_inline__)) + exception_ptr + make_exception_ptr(_Ex) _GLIBCXX_USE_NOEXCEPT + { return exception_ptr(); } +#endif #undef _GLIBCXX_EH_PTR_USED diff --git a/libstdc++-v3/src/c++11/compatibility-condvar.cc b/libstdc++-v3/src/c++11/compatibility-condvar.cc index 575d780..07c39d4 100644 --- a/libstdc++-v3/src/c++11/compatibility-condvar.cc +++ b/libstdc++-v3/src/c++11/compatibility-condvar.cc @@ -54,4 +54,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std +#if ! _GLIBCXX_INLINE_VERSION +// XXX GLIBCXX_ABI Deprecated +// gcc-12.1 +// std::condition_variable::wait changed to noexcept(false) +#if defined(_GLIBCXX_SYMVER_GNU) && defined(_GLIBCXX_SHARED) \ + && defined(_GLIBCXX_HAVE_AS_SYMVER_DIRECTIVE) \ + && defined(_GLIBCXX_HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT) +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +struct __nothrow_wait_cv : std::condition_variable +{ + void wait(std::unique_lock<std::mutex>&) noexcept; +}; + +__attribute__((used)) +void +__nothrow_wait_cv::wait(std::unique_lock<std::mutex>& lock) noexcept +{ + this->condition_variable::wait(lock); +} +} // namespace __gnu_cxx + +// Export a noexcept wrapper around std::condition_variable::wait +// with the original @GLIBCXX_3.4.11 symbol version. +asm( + ".symver _ZN9__gnu_cxx17__nothrow_wait_cv4waitERSt11unique_lockISt5mutexE," + "_ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE@GLIBCXX_3.4.11" +); +#endif +#endif + #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 diff --git a/libstdc++-v3/src/c++11/condition_variable.cc b/libstdc++-v3/src/c++11/condition_variable.cc index ca7902e..2d7b8a1 100644 --- a/libstdc++-v3/src/c++11/condition_variable.cc +++ b/libstdc++-v3/src/c++11/condition_variable.cc @@ -36,7 +36,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION condition_variable::~condition_variable() noexcept = default; void - condition_variable::wait(unique_lock<mutex>& __lock) noexcept + condition_variable::wait(unique_lock<mutex>& __lock) { _M_cond.wait(*__lock.mutex()); } diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/103630.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/103630.cc new file mode 100644 index 0000000..58fb2ab --- /dev/null +++ b/libstdc++-v3/testsuite/18_support/exception_ptr/103630.cc @@ -0,0 +1,39 @@ +// { dg-do run } + +#include <exception> +#if __cplusplus < 201103L +// std::make_exception_ptr is defined for C++98 as a GNU extension +# include <bits/exception_ptr.h> +#endif + +#include <testsuite_hooks.h> + +struct B +{ + virtual bool derived() const { return false; } +}; + +struct D : B +{ + virtual bool derived() const { return true; } +}; + +int main() +{ + D d; + std::exception_ptr p = std::make_exception_ptr<B&>(d); // PR libstdc++/103630 +#if __cpp_exceptions + try + { + std::rethrow_exception(p); + } + catch (const D& d) + { + VERIFY(d.derived()); // PR libstdc++/103630 + } + catch (const B& b) + { + VERIFY(!b.derived()); + } +#endif +} diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/64241.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/64241.cc index 486b16c..034a0a0 100644 --- a/libstdc++-v3/testsuite/18_support/exception_ptr/64241.cc +++ b/libstdc++-v3/testsuite/18_support/exception_ptr/64241.cc @@ -15,7 +15,7 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// { dg-options "-fno-exceptions -O0" } +// { dg-options "-fno-exceptions -fno-rtti -O0" } // { dg-do run { target c++11 } } #include <exception> diff --git a/libstdc++-v3/testsuite/20_util/allocator/64135.cc b/libstdc++-v3/testsuite/20_util/allocator/64135.cc new file mode 100644 index 0000000..b0a49e9 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator/64135.cc @@ -0,0 +1,45 @@ +// { dg-do compile { target std_allocator_new } } +// { dg-add-options no_pch } + +// PR libstdc++/64135 + +#define new_allocator 1 +#define malloc_allocator 1 +#define bitmap_allocator 1 +#include <memory> + +#if __cplusplus >= 201103L +#define STATIC_ASSERT(X) static_assert((X), #X) +#else +#define PASTE2(X, Y) X##Y +#define PASTE(X, Y) PASTE2(X, Y) +#define STATIC_ASSERT(X) char PASTE(_assertion_, __LINE__) [(X) ? 1 : -1] +#endif + +#undef new_allocator +#undef malloc_allocator +#include <ext/new_allocator.h> +#include <ext/malloc_allocator.h> + +struct N : __gnu_cxx::new_allocator<char> { }; + +struct A : std::allocator<char>, N { }; +struct B : std::allocator<char> { N n; }; + +// Verify that layout was not changed by removing std::allocator inheritance +// from __gnu_cxx::new_allocator: +STATIC_ASSERT( sizeof(A) == 2 ); +STATIC_ASSERT( sizeof(B) == 2 ); + +struct M : __gnu_cxx::malloc_allocator<char> { }; +struct C : N, M { }; + +// Verify that malloc_allocator can be an overlapping subobject with +// __new_allocator: +STATIC_ASSERT( sizeof(M) == 1 ); +STATIC_ASSERT( sizeof(C) == 1 ); + +struct D : std::allocator<char>, M { }; + +// This test uses { target std_allocator_new } so this is true too: +STATIC_ASSERT( sizeof(D) == 1 ); diff --git a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc index fd37374..143adc3 100644 --- a/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc +++ b/libstdc++-v3/testsuite/20_util/scoped_allocator/69293_neg.cc @@ -47,8 +47,4 @@ test01() auto p = sa.allocate(1); sa.construct(p); // this is required to be ill-formed // { dg-error "failed: .* uses_allocator is true" "" { target *-*-* } 0 } - // { dg-error "too many initializers for 'X'" "" { target c++2a } 0 } } - -// Needed because of PR c++/92193 -// { dg-prune-output "no matching function for call to" } diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/char/3.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/char/3.cc new file mode 100644 index 0000000..524c1c5 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/time_get/get/char/3.cc @@ -0,0 +1,356 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <locale> +#include <sstream> +#include <iterator> +#include <testsuite_hooks.h> + +void +test01() +{ + using namespace std; + + locale loc_c = locale::classic(); + + istringstream iss; + iss.imbue(loc_c); + const time_get<char>& tget = use_facet<time_get<char>>(iss.getloc()); + typedef istreambuf_iterator<char> iter; + const iter end; + + tm time; + ios_base::iostate err = ios_base::badbit; + + // PR78714 tests + iss.str("Mon"); + string format = "%a"; + auto ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 1 ); + + iss.str("Tue "); + format = "%a"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == ' ' ); + VERIFY( time.tm_wday == 2 ); + + iss.str("Wednesday"); + format = "%a"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 3 ); + + iss.str("Thu"); + format = "%A"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 4 ); + + iss.str("Fri "); + format = "%A"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == ' ' ); + VERIFY( time.tm_wday == 5 ); + + iss.str("Saturday"); + format = "%A"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 6 ); + + iss.str("Feb"); + format = "%b"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 1 ); + + iss.str("Mar "); + format = "%b"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == ' ' ); + VERIFY( time.tm_mon == 2 ); + + iss.str("April"); + format = "%b"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 3 ); + + iss.str("May"); + format = "%B"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 4 ); + + iss.str("Jun "); + format = "%B"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == ' ' ); + VERIFY( time.tm_mon == 5 ); + + iss.str("July"); + format = "%B"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 6 ); + + iss.str("Aug"); + format = "%h"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 7 ); + + iss.str("May "); + format = "%h"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == ' ' ); + VERIFY( time.tm_mon == 4 ); + + iss.str("October"); + format = "%h"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 9 ); + + // Other tests. + iss.str(" 1."); + format = "%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 1 ); + + iss.str("2."); + format = "%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 2 ); + + iss.str("03."); + format = "%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 3 ); + + iss.str("0."); + format = "%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == '.' ); + + iss.str("32."); + format = "%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == '2' ); + + iss.str(" 4."); + format = "%e."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 4 ); + + iss.str("5."); + format = "%e."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 5 ); + + iss.str("06."); + format = "%e."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 6 ); + + iss.str("0"); + format = "%e"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit|ios_base::eofbit ); + VERIFY( ret == end ); + + iss.str("35"); + format = "%e"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == '5' ); + + iss.str(" \t\t 02"); + format = "%t%m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 1 ); + + iss.str(" \t \t 03"); + format = "%n%m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 2 ); + + iss.str(" \t \t 4"); + format = " %m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 3 ); + + iss.str(" \t \t 5"); + format = "\t%m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 4 ); + + iss.str("12:00AM"); + format = "%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 0 ); + VERIFY( time.tm_min == 0 ); + + iss.str("12:37AM"); + format = "%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 0 ); + VERIFY( time.tm_min == 37 ); + + iss.str("01:25AM"); + format = "%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 1 ); + VERIFY( time.tm_min == 25 ); + + iss.str("12:00PM"); + format = "%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 12 ); + VERIFY( time.tm_min == 0 ); + + iss.str("12:42PM"); + format = "%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 12 ); + VERIFY( time.tm_min == 42 ); + + iss.str("07:23PM"); + format = "%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 19 ); + VERIFY( time.tm_min == 23 ); + + iss.str("17%20"); + format = "%H%%%M"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 17 ); + VERIFY( time.tm_min == 20 ); + + iss.str("24:30"); + format = "%H:%M"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == '4' ); + + // This one behaves differently from strptime, in a single + // pass scaning we can't go back. + iss.str("Novembur"); + format = "%bembur"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == 'u' ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/char/71367.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/char/71367.cc new file mode 100644 index 0000000..b1af4bf --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/time_get/get/char/71367.cc @@ -0,0 +1,67 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <locale> +#include <sstream> +#include <iterator> +#include <testsuite_hooks.h> + +void +test01() +{ + using namespace std; + + locale loc_c = locale::classic(); + + istringstream iss; + iss.imbue(loc_c); + const time_get<char>& tget = use_facet<time_get<char>>(iss.getloc()); + typedef istreambuf_iterator<char> iter; + const iter end; + + tm time; + ios_base::iostate err = ios_base::badbit; + + iss.str("01:38:12 PM"); + string format = "%I:%M:%S %p"; + auto ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 13 ); + VERIFY( time.tm_min == 38 ); + VERIFY( time.tm_sec == 12 ); + + iss.str("11:17:42 PM"); + format = "%r"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 23 ); + VERIFY( time.tm_min == 17 ); + VERIFY( time.tm_sec == 42 ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc new file mode 100644 index 0000000..cbc3144 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/3.cc @@ -0,0 +1,356 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <locale> +#include <sstream> +#include <iterator> +#include <testsuite_hooks.h> + +void +test01() +{ + using namespace std; + + locale loc_c = locale::classic(); + + wistringstream iss; + iss.imbue(loc_c); + const time_get<wchar_t>& tget = use_facet<time_get<wchar_t>>(iss.getloc()); + typedef istreambuf_iterator<wchar_t> iter; + const iter end; + + tm time; + ios_base::iostate err = ios_base::badbit; + + // PR78714 tests + iss.str(L"Mon"); + wstring format = L"%a"; + auto ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 1 ); + + iss.str(L"Tue L"); + format = L"%a"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == L' ' ); + VERIFY( time.tm_wday == 2 ); + + iss.str(L"Wednesday"); + format = L"%a"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 3 ); + + iss.str(L"Thu"); + format = L"%A"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 4 ); + + iss.str(L"Fri L"); + format = L"%A"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == L' ' ); + VERIFY( time.tm_wday == 5 ); + + iss.str(L"Saturday"); + format = L"%A"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_wday == 6 ); + + iss.str(L"Feb"); + format = L"%b"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 1 ); + + iss.str(L"Mar L"); + format = L"%b"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == L' ' ); + VERIFY( time.tm_mon == 2 ); + + iss.str(L"April"); + format = L"%b"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 3 ); + + iss.str(L"May"); + format = L"%B"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 4 ); + + iss.str(L"Jun L"); + format = L"%B"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == L' ' ); + VERIFY( time.tm_mon == 5 ); + + iss.str(L"July"); + format = L"%B"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 6 ); + + iss.str(L"Aug"); + format = L"%h"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 7 ); + + iss.str(L"May L"); + format = L"%h"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret != end && *ret == L' ' ); + VERIFY( time.tm_mon == 4 ); + + iss.str(L"October"); + format = L"%h"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 9 ); + + // Other tests. + iss.str(L" 1."); + format = L"%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 1 ); + + iss.str(L"2."); + format = L"%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 2 ); + + iss.str(L"03."); + format = L"%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 3 ); + + iss.str(L"0."); + format = L"%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == L'.' ); + + iss.str(L"32."); + format = L"%d."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == L'2' ); + + iss.str(L" 4."); + format = L"%e."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 4 ); + + iss.str(L"5."); + format = L"%e."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 5 ); + + iss.str(L"06."); + format = L"%e."; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::goodbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mday == 6 ); + + iss.str(L"0"); + format = L"%e"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit|ios_base::eofbit ); + VERIFY( ret == end ); + + iss.str(L"35"); + format = L"%e"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == L'5' ); + + iss.str(L" \t\t 02"); + format = L"%t%m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 1 ); + + iss.str(L" \t \t 03"); + format = L"%n%m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 2 ); + + iss.str(L" \t \t 4"); + format = L" %m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 3 ); + + iss.str(L" \t \t 5"); + format = L"\t%m"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_mon == 4 ); + + iss.str(L"12:00AM"); + format = L"%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 0 ); + VERIFY( time.tm_min == 0 ); + + iss.str(L"12:37AM"); + format = L"%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 0 ); + VERIFY( time.tm_min == 37 ); + + iss.str(L"01:25AM"); + format = L"%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 1 ); + VERIFY( time.tm_min == 25 ); + + iss.str(L"12:00PM"); + format = L"%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 12 ); + VERIFY( time.tm_min == 0 ); + + iss.str(L"12:42PM"); + format = L"%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 12 ); + VERIFY( time.tm_min == 42 ); + + iss.str(L"07:23PM"); + format = L"%I:%M%p"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 19 ); + VERIFY( time.tm_min == 23 ); + + iss.str(L"17%20"); + format = L"%H%%%M"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 17 ); + VERIFY( time.tm_min == 20 ); + + iss.str(L"24:30"); + format = L"%H:%M"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == L'4' ); + + // This one behaves differently from strptime, in a single + // pass scaning we can't go back. + iss.str(L"Novembur"); + format = L"%bembur"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::failbit ); + VERIFY( ret != end && *ret == L'u' ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/71367.cc b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/71367.cc new file mode 100644 index 0000000..693053e --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/time_get/get/wchar_t/71367.cc @@ -0,0 +1,67 @@ +// { dg-do run { target c++11 } } + +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. + +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include <locale> +#include <sstream> +#include <iterator> +#include <testsuite_hooks.h> + +void +test01() +{ + using namespace std; + + locale loc_c = locale::classic(); + + wistringstream iss; + iss.imbue(loc_c); + const time_get<wchar_t>& tget = use_facet<time_get<wchar_t>>(iss.getloc()); + typedef istreambuf_iterator<wchar_t> iter; + const iter end; + + tm time; + ios_base::iostate err = ios_base::badbit; + + iss.str(L"01:38:12 PM"); + wstring format = L"%I:%M:%S %p"; + auto ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 13 ); + VERIFY( time.tm_min == 38 ); + VERIFY( time.tm_sec == 12 ); + + iss.str(L"11:17:42 PM"); + format = L"%r"; + ret = tget.get(iter(iss), end, iss, err, &time, + format.data(), format.data()+format.size()); + VERIFY( err == ios_base::eofbit ); + VERIFY( ret == end ); + VERIFY( time.tm_hour == 23 ); + VERIFY( time.tm_min == 17 ); + VERIFY( time.tm_sec == 42 ); +} + +int +main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/12791.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/12791.cc index 07b655c..958a8f1 100644 --- a/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/12791.cc +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_date/char/12791.cc @@ -39,14 +39,14 @@ void test01() const ios_base::iostate good = ios_base::goodbit; ios_base::iostate errorstate = good; - iss.str("60/04/71"); + iss.str("62/04/71"); iterator_type is_it01(iss); tm time01; errorstate = good; iterator_type ret01 = tim_get.get_date(is_it01, end, iss, errorstate, &time01); VERIFY( errorstate == ios_base::failbit ); - VERIFY( *ret01 == '6' ); + VERIFY( *ret01 == '2' ); iss.str("04/38/71"); iterator_type is_it02(iss); diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/12791.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/12791.cc index a33d695..0cf8f67 100644 --- a/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/12791.cc +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_date/wchar_t/12791.cc @@ -40,14 +40,14 @@ void test01() const ios_base::iostate good = ios_base::goodbit; ios_base::iostate errorstate = good; - iss.str(L"60/04/71"); + iss.str(L"62/04/71"); iterator_type is_it01(iss); tm time01; errorstate = good; iterator_type ret01 = tim_get.get_date(is_it01, end, iss, errorstate, &time01); VERIFY( errorstate == ios_base::failbit ); - VERIFY( *ret01 == L'6' ); + VERIFY( *ret01 == L'2' ); iss.str(L"04/38/71"); iterator_type is_it02(iss); diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/2.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/2.cc index 79f921d..a847748 100644 --- a/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/2.cc +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/2.cc @@ -48,7 +48,7 @@ void test02() // inspection of named locales, en_HK iss.imbue(loc_hk); - iss.str("12:00:00 PST"); + iss.str("12:00:00 PM PST"); // Hong Kong in California! Well, they have Paris in Vegas... this // is all a little disney-esque anyway. Besides, you can get decent // Dim Sum in San Francisco. diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/5.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/5.cc index c777796..a9bb79c 100644 --- a/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/5.cc +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_time/char/5.cc @@ -52,7 +52,7 @@ void test01() VERIFY( err == (failbit | eofbit) ); VERIFY( tm0.tm_sec == 0 ); VERIFY( tm0.tm_min == 0 ); - VERIFY( tm0.tm_hour == 0 ); + VERIFY( tm0.tm_hour == 1 ); const string str1 = "12:00:00 "; iter_type end1 = tg.get_time(str1.begin(), str1.end(), iss, err, &tm1); diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/2.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/2.cc index 6c3f5c2..b5d61e1 100644 --- a/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/2.cc +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/2.cc @@ -48,7 +48,7 @@ void test02() // inspection of named locales, en_HK iss.imbue(loc_hk); - iss.str(L"12:00:00 PST"); + iss.str(L"12:00:00 PM PST"); // Hong Kong in California! Well, they have Paris in Vegas... this // is all a little disney-esque anyway. Besides, you can get decent // Dim Sum in San Francisco. diff --git a/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/5.cc b/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/5.cc index 8fda7fb..db25046 100644 --- a/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/5.cc +++ b/libstdc++-v3/testsuite/22_locale/time_get/get_time/wchar_t/5.cc @@ -52,7 +52,7 @@ void test01() VERIFY( err == (failbit | eofbit) ); VERIFY( tm0.tm_sec == 0 ); VERIFY( tm0.tm_min == 0 ); - VERIFY( tm0.tm_hour == 0 ); + VERIFY( tm0.tm_hour == 1 ); const wstring str1 = L"12:00:00 "; iter_type end1 = tg.get_time(str1.begin(), str1.end(), iss, err, &tm1); diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc new file mode 100644 index 0000000..937b4d9 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/emplace/92300.cc @@ -0,0 +1,36 @@ +// { dg-do run { target c++17 } } + +#include <map> +#include <cstdlib> + +bool oom = false; + +void* operator new(std::size_t n) +{ + if (oom) + throw std::bad_alloc(); + return std::malloc(n); +} + +void operator delete(void* p) +{ + std::free(p); +} + +void operator delete(void* p, std::size_t) +{ + std::free(p); +} + +int main() +{ + std::map<int, int> m; + int i = 0; + (void) m[i]; + oom = true; + m.emplace(i, 1); + m.emplace(i, 2L); + const int c = 3; + m.emplace(i, c); + m.emplace((long)i, 4); +} diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc new file mode 100644 index 0000000..80abdaf --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/92300.cc @@ -0,0 +1,38 @@ +// { dg-do run { target c++17 } } + +#include <map> +#include <cstdlib> + +bool oom = false; + +void* operator new(std::size_t n) +{ + if (oom) + throw std::bad_alloc(); + return std::malloc(n); +} + +void operator delete(void* p) +{ + std::free(p); +} + +void operator delete(void* p, std::size_t) +{ + std::free(p); +} + +int main() +{ + using std::pair; + std::map<int, int> m; + int i = 0; + (void) m[i]; + oom = true; + m.insert({i, 1}); // insert(value_type&&) + m.insert(pair<int, int>(i, 2)); // insert(Pair&&) + m.insert(pair<int&, int>(i, 3)); // insert(Pair&&) + m.insert(pair<int, long>(i, 4L)); // insert(Pair&&) + m.insert(pair<const int, long>(i, 5L)); // insert(Pair&&) + m.insert(pair<const int&, long>(i, 6L)); // insert(Pair&&) +} diff --git a/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/noreplace.cc b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/noreplace.cc new file mode 100644 index 0000000..e39f592 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/char/noreplace.cc @@ -0,0 +1,29 @@ +// { dg-do run } + +#include <ios> + +#if __cplusplus >= 202200L +#ifndef __cpp_lib_ios_noreplace +# error "Feature-test macro for ios::noreplace missing in <ios>" +#elif __cpp_lib_ios_noreplace < 202200L +# error "Feature-test macro for ios::noreplace has wrong value in <ios>" +#endif +#endif + +#include <fstream> +#include <testsuite_hooks.h> + +int main() +{ +#if __cpp_lib_ios_noreplace + std::ios::openmode noreplace = std::ios::noreplace; +#else + std::ios::openmode noreplace = std::ios::__noreplace; +#endif + + std::ofstream of("noreplace"); + VERIFY( of.is_open() ); + of.close(); + of.open("noreplace", noreplace); + VERIFY( ! of.is_open() ); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc new file mode 100644 index 0000000..77f1186 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_ofstream/open/wchar_t/noreplace.cc @@ -0,0 +1,29 @@ +// { dg-do run } + +#include <version> + +#if __cplusplus >= 202200L +#ifndef __cpp_lib_ios_noreplace +# error "Feature-test macro for ios::noreplace missing in <version>" +#elif __cpp_lib_ios_noreplace < 202200L +# error "Feature-test macro for ios::noreplace has wrong value in <version>" +#endif +#endif + +#include <fstream> +#include <testsuite_hooks.h> + +int main() +{ +#if __cpp_lib_ios_noreplace + std::wios::openmode noreplace = std::wios::noreplace; +#else + std::wios::openmode noreplace = std::wios::__noreplace; +#endif + + std::wofstream of("noreplace"); + VERIFY( of.is_open() ); + of.close(); + of.open("noreplace", noreplace); + VERIFY( ! of.is_open() ); +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/102994.cc b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/102994.cc new file mode 100644 index 0000000..9d92ff9 --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/wait_notify/102994.cc @@ -0,0 +1,19 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-require-gthreads "" } + +#include <atomic> + +void +test1(const std::atomic<char*>& a, char* p) +{ + a.wait(p); +} + +void +test2(const std::atomic<int>* a, int v) +{ + std::atomic_wait(a, v); + std::atomic_notify_one(a); + std::atomic_notify_all(a); +} diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/members/103382.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/members/103382.cc new file mode 100644 index 0000000..67396eb --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/condition_variable/members/103382.cc @@ -0,0 +1,66 @@ +// { dg-options "-pthread" } +// { dg-do run { target { *-*-linux* *-*-gnu* } } } +// { dg-require-effective-target c++11 } +// { dg-require-effective-target pthread } +// { dg-require-gthreads "" } + +#include <condition_variable> +#include <chrono> +#include <mutex> +#include <thread> + +// PR libstdc++/103382 + +template<typename F> +void +test_cancel(F wait) +{ + std::mutex m; + std::condition_variable cv; + bool waiting = false; + + std::thread t([&] { + std::unique_lock<std::mutex> lock(m); + waiting = true; + wait(cv, lock); // __forced_unwind exception should not terminate process. + }); + + // Ensure the condition variable is waiting before we cancel. + // This shouldn't be necessary because pthread_mutex_lock is not + // a cancellation point, but no harm in making sure we test what + // we intend to test: that cancel during a wait doesn't abort. + while (true) + { + std::unique_lock<std::mutex> lock(m); + if (waiting) + break; + } + + pthread_cancel(t.native_handle()); + t.join(); +} + +int main() +{ + test_cancel( + [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { + cv.wait(l); + }); + + test_cancel( + [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { + cv.wait(l, []{ return false; }); + }); + + using mins = std::chrono::minutes; + + test_cancel( + [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { + cv.wait_for(l, mins(1)); + }); + + test_cancel( + [](std::condition_variable& cv, std::unique_lock<std::mutex>& l) { + cv.wait_until(l, std::chrono::system_clock::now() + mins(1)); + }); +} |