diff options
author | Thomas Schwinge <tschwinge@baylibre.com> | 2024-04-10 10:55:56 +0200 |
---|---|---|
committer | Thomas Schwinge <tschwinge@baylibre.com> | 2024-04-10 10:55:56 +0200 |
commit | 1af2c40d7595c91f8c8f3573c1bec30556e35bb6 (patch) | |
tree | 38b5d5ec8fbb0f53621f676e35611cc092b8da42 /gcc | |
parent | 17ee9c68cbc9ba7a13b77ea458fbbc6275c38d02 (diff) | |
parent | 830d4659604e4d0f6e908d1cdb5bf1638a60bb21 (diff) | |
download | gcc-1af2c40d7595c91f8c8f3573c1bec30556e35bb6.zip gcc-1af2c40d7595c91f8c8f3573c1bec30556e35bb6.tar.gz gcc-1af2c40d7595c91f8c8f3573c1bec30556e35bb6.tar.bz2 |
Merge commit 'f89186f962421f6d972035fc4b4c20490e7b1c5b^' into HEAD
Diffstat (limited to 'gcc')
658 files changed, 27079 insertions, 14868 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 60e2d87..4997309 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,765 @@ +2024-02-06 H.J. Lu <hjl.tools@gmail.com> + + PR target/113689 + * config/i386/i386.cc (x86_64_select_profile_regnum): Return + R10_REG after sorry. + +2024-02-06 Andrew Carlotti <andrew.carlotti@arm.com> + + * config/aarch64/aarch64.cc (aarch64_mangle_decl_assembler_name): + Move before new caller, and add ".default" suffix. + (get_suffixed_assembler_name): New. + (make_resolver_func): Use get_suffixed_assembler_name. + (aarch64_generate_version_dispatcher_body): Redo name mangling. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR target/113763 + * config/aarch64/aarch64.cc (aarch64_output_sme_zero_za): Change tiles + element from std::pair<unsigned int, char> to an unnamed struct. + Adjust uses of tile range variable. + +2024-02-06 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv-vsetvl.cc (pre_vsetvl::emit_vsetvl): Fix inifinite compilation. + (pre_vsetvl::remove_vsetvl_pre_insns): Ditto. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/110676 + * gimple-fold.cc (gimple_fold_builtin_strlen): For -fsanitize=address + reset maxlen to sizetype maximum. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113736 + * gimple-lower-bitint.cc (bitint_large_huge::limb_access): Use + var's address space for MEM_REF or VIEW_CONVERT_EXPRs. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113759 + * tree-ssa-math-opts.cc (convert_mult_to_widen): If actual_precision + or from_unsignedN differs from properties of typeN, update typeN + to build_nonstandard_integer_type. If TREE_TYPE (rhsN) is not + uselessly convertible to typeN, convert it using fold_convert or + build_and_insert_cast depending on if rhsN is INTEGER_CST or not. + (convert_plusminus_to_widen): Likewise. + +2024-02-06 Tejas Belagod <tejas.belagod@arm.com> + + PR target/112577 + * config/aarch64/aarch64.cc (aarch64_class_max_nregs): Handle 64-bit + vector structure modes correctly. + +2024-02-05 Christoph Müllner <christoph.muellner@vrull.eu> + + * config/riscv/thead.cc (th_print_operand_address): Fix compiler + warning. + +2024-02-05 H.J. Lu <hjl.tools@gmail.com> + + PR target/113689 + * config/i386/i386.cc (x86_64_select_profile_regnum): New. + (x86_function_profiler): Call x86_64_select_profile_regnum to + get a scratch register for large model profiling. + +2024-02-05 Richard Ball <richard.ball@arm.com> + + * config/arm/arm.cc (arm_output_mi_thunk): Emit + insn for bti_c when bti is enabled. + +2024-02-05 Xi Ruoyao <xry111@xry111.site> + + * config/mips/mips-msa.md (neg<mode:MSA>2): Add missing mode for + neg. + +2024-02-05 Xi Ruoyao <xry111@xry111.site> + + * config/mips/mips-msa.md (elmsgnbit): New define_mode_attr. + (neg<mode>2): Change the mode iterator from MSA to IMSA because + in FP arithmetic we cannot use (0 - x) for -x. + (neg<mode>2): New define_insn to implement FP vector negation, + using a bnegi instruction to negate the sign bit. + +2024-02-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113707 + * tree-ssa-sccvn.cc (rpo_elim::eliminate_avail): After + checking the avail set treat out-of-region defines as + available. + +2024-02-05 Richard Biener <rguenther@suse.de> + + * tree-vect-data-refs.cc (vect_create_data_ref_ptr): Use + the default mode when building a pointer. + +2024-02-05 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113737 + * gimple-lower-bitint.cc (gimple_lower_bitint): If GIMPLE_SWITCH + has just a single label, remove it and make single successor edge + EDGE_FALLTHRU. + +2024-02-05 Jakub Jelinek <jakub@redhat.com> + + PR target/113059 + * config/i386/i386-features.cc (rest_of_handle_insert_vzeroupper): + Remove REG_DEAD/REG_UNUSED notes at the end of the pass before + df_analyze call. + +2024-02-05 Richard Biener <rguenther@suse.de> + + PR target/113255 + * config/i386/i386-expand.cc + (expand_set_or_cpymem_prologue_epilogue_by_misaligned_moves): + Use a new pseudo for the skipped number of bytes. + +2024-02-05 Monk Chiang <monk.chiang@sifive.com> + + * config/riscv/riscv-cores.def: Add sifive-p450, sifive-p670. + * doc/invoke.texi (RISC-V Options): Add sifive-p450, + sifive-p670. + +2024-02-05 Monk Chiang <monk.chiang@sifive.com> + + * config/riscv/riscv.md: Include sifive-p400.md. + * config/riscv/sifive-p400.md: New file. + * config/riscv/riscv-cores.def (RISCV_TUNE): Add parameter. + * config/riscv/riscv-opts.h (enum riscv_microarchitecture_type): + Add sifive_p400. + * config/riscv/riscv.cc (sifive_p400_tune_info): New. + * config/riscv/riscv.h (TARGET_SFB_ALU): Update. + * doc/invoke.texi (RISC-V Options): Add sifive-p400-series + +2024-02-04 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.md (*eqne_zero_masked_bits): + Add missing ":SI" to the match_operator. + +2024-02-04 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.md (SHI): New mode iterator. + (2 split patterns related to constsynth): + Change to also accept HImode operands. + +2024-02-04 Jeff Law <jlaw@ventanamicro.com> + + * config/riscv/riscv.cc (riscv_rtx_costs): Handle SUBREG and REG + similarly. + +2024-02-04 Xi Ruoyao <xry111@xry111.site> + + * config/loongarch/lsx.md (neg<mode:FLSX>2): Remove the + incorrect expand. + * config/loongarch/simd.md (simdfmt_as_i): New define_mode_attr. + (elmsgnbit): Likewise. + (neg<mode:FVEC>2): New define_insn. + * config/loongarch/lasx.md (negv4df2, negv8sf2): Remove as they + are now instantiated in simd.md. + +2024-02-04 Xi Ruoyao <xry111@xry111.site> + + * config/loongarch/loongarch.cc (loongarch_symbol_insns): Do not + use LSX_SUPPORTED_MODE_P or LASX_SUPPORTED_MODE_P if mode is + MAX_MACHINE_MODE. + +2024-02-04 Li Wei <liwei@loongson.cn> + + * config/loongarch/loongarch.cc (loongarch_expand_vselect): Adjust. + (loongarch_expand_vselect_vconcat): Ditto. + (loongarch_try_expand_lsx_vshuf_const): New, use vshuf to implement + all 128-bit constant permutation situations. + (loongarch_expand_lsx_shuffle): Adjust and rename function name. + (loongarch_is_imm_set_shuffle): Renamed function name. + (loongarch_expand_vec_perm_even_odd): Function forward declaration. + (loongarch_expand_vec_perm_even_odd_1): Add implement for 128-bit + extract-even and extract-odd permutations. + (loongarch_is_odd_extraction): Delete. + (loongarch_is_even_extraction): Ditto. + (loongarch_expand_vec_perm_const): Adjust. + +2024-02-03 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113722 + * wide-int.cc (wi::bswap_large): Rename third argument from + len to xlen and adjust use in safe_uhwi. Add len variable, set + it to BLOCKS_NEEDED (precision) and use it for clearing of val + and as canonize argument. Clear val using memset instead of + a loop. + +2024-02-03 Jakub Jelinek <jakub@redhat.com> + + * ggc-common.cc (gt_pch_save): Allow addr to be equal to + mmi.preferred_base + mmi.size - sizeof (void *). + +2024-02-03 Xi Ruoyao <xry111@xry111.site> + + * config/loongarch/loongarch-def.h (abi_minimal_isa): Declare. + * config/loongarch/loongarch-opts.cc (abi_minimal_isa): Remove + the ODR-violating locale declaration. + +2024-02-02 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/113588 + PR tree-optimization/113467 + * tree-vect-data-refs.cc + (vect_analyze_data_ref_dependence): Choose correct dest and fix checks. + (vect_analyze_early_break_dependences): Update comments. + +2024-02-02 John David Anglin <danglin@gcc.gnu.org> + + PR target/59778 + * config/pa/pa.cc (enum pa_builtins): Add PA_BUILTIN_GET_FPSR + and PA_BUILTIN_SET_FPSR builtins. + * (pa_builtins_icode): Declare. + * (def_builtin, pa_fpu_init_builtins): New. + * (pa_init_builtins): Initialize FPU builtins. + * (pa_builtin_decl, pa_expand_builtin_1): New. + * (pa_expand_builtin): Handle PA_BUILTIN_GET_FPSR and + PA_BUILTIN_SET_FPSR builtins. + * (pa_atomic_assign_expand_fenv): New. + * config/pa/pa.md (UNSPECV_GET_FPSR, UNSPECV_SET_FPSR): New + UNSPECV constants. + (get_fpsr, put_fpsr): New expanders. + (get_fpsr_32, get_fpsr_64, set_fpsr_32, set_fpsr_64): New + insn patterns. + +2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + PR target/113697 + * config/riscv/riscv-v.cc (expand_reduction): Pass VLMAX avl to scalar move. + +2024-02-02 Jonathan Wakely <jwakely@redhat.com> + + * doc/extend.texi (Common Type Attributes): Fix typo in + description of hardbool. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113692 + * gimple-lower-bitint.cc (bitint_large_huge::lower_stmt): Handle casts + from large/huge BITINT_TYPEs to POINTER_TYPE/REFERENCE_TYPE as + final_cast_p. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113699 + * gimple-lower-bitint.cc (bitint_large_huge::lower_asm): Handle + uninitialized large/huge _BitInt SSA_NAME inputs. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113705 + * tree-ssa-math-opts.cc (is_widening_mult_rhs_p): Use wide_int_from + around wi::to_wide in order to compare value in prec precision. + +2024-02-02 Lehua Ding <lehua.ding@rivai.ai> + + Revert: + 2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv.cc (riscv_legitimize_move): Fix poly_int dest generation. + +2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv.cc (riscv_legitimize_move): Fix poly_int dest generation. + +2024-02-02 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv.cc (riscv_get_arg_info): Cleanup comments. + (riscv_pass_by_reference): Ditto. + (riscv_fntype_abi): Ditto. + +2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv-vsetvl.cc (vsetvl_pre_insn_p): New function. + (pre_vsetvl::cleaup): Remove vsetvl_pre. + (pre_vsetvl::remove_vsetvl_pre_insns): New function. + +2024-02-02 Jiahao Xu <xujiahao@loongson.cn> + + * config/loongarch/larchintrin.h + (__frecipe_s): Update function return type. + (__frecipe_d): Ditto. + (__frsqrte_s): Ditto. + (__frsqrte_d): Ditto. + +2024-02-02 Li Wei <liwei@loongson.cn> + + * config/loongarch/loongarch.cc (loongarch_multiply_add_p): New. + (loongarch_vector_costs::add_stmt_cost): Adjust. + +2024-02-02 Xi Ruoyao <xry111@xry111.site> + + * config/loongarch/loongarch.md (unspec): Add + UNSPEC_LA_PCREL_64_PART1 and UNSPEC_LA_PCREL_64_PART2. + (la_pcrel64_two_parts): New define_insn. + * config/loongarch/loongarch.cc (loongarch_tls_symbol): Fix a + typo in the comment. + (loongarch_call_tls_get_addr): If -mcmodel=extreme + -mexplicit-relocs={always,auto}, use la_pcrel64_two_parts for + addressing the TLS symbol and __tls_get_addr. Emit an REG_EQUAL + note to allow CSE addressing __tls_get_addr. + (loongarch_legitimize_tls_address): If -mcmodel=extreme + -mexplicit-relocs={always,auto}, address TLS IE symbols with + la_pcrel64_two_parts. + (loongarch_split_symbol): If -mcmodel=extreme + -mexplicit-relocs={always,auto}, address symbols with + la_pcrel64_two_parts. + (loongarch_output_mi_thunk): Clean up unreachable code. If + -mcmodel=extreme -mexplicit-relocs={always,auto}, address the MI + thunks with la_pcrel64_two_parts. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * config/loongarch/loongarch.cc (loongarch_call_tls_get_addr): + Add support for call36. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * config/loongarch/loongarch.cc (loongarch_explicit_relocs_p): + When the code model of the symbol is extreme and -mexplicit-relocs=auto, + the macro instruction loading symbol address is not applicable. + (loongarch_call_tls_get_addr): Adjust code. + (loongarch_legitimize_tls_address): Likewise. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * config/loongarch/loongarch-protos.h (loongarch_symbol_extreme_p): + Add function declaration. + * config/loongarch/loongarch.cc (loongarch_symbolic_constant_p): + For SYMBOL_PCREL64, non-zero addend of "la.local $rd,$rt,sym+addend" + is not allowed + (loongarch_load_tls): Added macro support in extreme mode. + (loongarch_call_tls_get_addr): Likewise. + (loongarch_legitimize_tls_address): Likewise. + (loongarch_force_address): Likewise. + (loongarch_legitimize_move): Likewise. + (loongarch_output_mi_thunk): Likewise. + (loongarch_option_override_internal): Remove the code that detects + explicit relocs status. + (loongarch_handle_model_attribute): Likewise. + * config/loongarch/loongarch.md (movdi_symbolic_off64): New template. + * config/loongarch/predicates.md (symbolic_off64_operand): New predicate. + (symbolic_off64_or_reg_operand): Likewise. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * config/loongarch/loongarch.cc (loongarch_load_tls): + Load all types of tls symbols through one function. + (loongarch_got_load_tls_gd): Delete. + (loongarch_got_load_tls_ld): Delete. + (loongarch_got_load_tls_ie): Delete. + (loongarch_got_load_tls_le): Delete. + (loongarch_call_tls_get_addr): Modify the called function name. + (loongarch_legitimize_tls_address): Likewise. + * config/loongarch/loongarch.md (@got_load_tls_gd<mode>): Delete. + (@load_tls<mode>): New template. + (@got_load_tls_ld<mode>): Delete. + (@got_load_tls_le<mode>): Delete. + (@got_load_tls_ie<mode>): Delete. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * config/loongarch/loongarch.cc (mem_shadd_or_shadd_rtx_p): New function. + (loongarch_legitimize_address): Add logical transformation code. + +2024-02-01 Marek Polacek <polacek@redhat.com> + + * doc/invoke.texi: Update -Wdangling-reference documentation. + +2024-02-01 Uros Bizjak <ubizjak@gmail.com> + + PR target/113701 + * config/i386/i386.md (*cmp<dwi>_doubleword): + Do not force SUBREG pieces to pseudos. + +2024-02-01 John David Anglin <danglin@gcc.gnu.org> + + * config/pa/pa.md (atomic_storedi_1): Fix bug in + alternative 1. + +2024-02-01 Georg-Johann Lay <avr@gjlay.de> + + * config/avr/avr.cc: Tabify. + +2024-02-01 Richard Ball <richard.ball@arm.com> + + PR tree-optimization/111268 + * tree-vect-slp.cc (vectorizable_slp_permutation_1): + Add variable-length check for vector input arguments + to a function. + +2024-02-01 Thomas Schwinge <tschwinge@baylibre.com> + + * config/gcn/gcn.cc (gcn_hsa_declare_function_name): Don't + hard-code number of SGPR/VGPR/AVGPR registers. + * config/gcn/gcn.h: Add a 'STATIC_ASSERT's for number of + SGPR/VGPR/AVGPR registers. + +2024-02-01 Monk Chiang <monk.chiang@sifive.com> + + * config/riscv/riscv.md: Add "fcvt_i2f", "fcvt_f2i" type + attribute, and include sifive-p600.md. + * config/riscv/generic-ooo.md: Update type attribute. + * config/riscv/generic.md: Update type attribute. + * config/riscv/sifive-7.md: Update type attribute. + * config/riscv/sifive-p600.md: New file. + * config/riscv/riscv-cores.def (RISCV_TUNE): Add parameter. + * config/riscv/riscv-opts.h (enum riscv_microarchitecture_type): + Add sifive_p600. + * config/riscv/riscv.cc (sifive_p600_tune_info): New. + * config/riscv/riscv.h (TARGET_SFB_ALU): Update. + * doc/invoke.texi (RISC-V Options): Add sifive-p600-series + +2024-02-01 Monk Chiang <monk.chiang@sifive.com> + + * common/config/riscv/riscv-common.cc: Add Za64rs, Za128rs, + Ziccif, Ziccrse, Ziccamoa, Zicclsm, Zic64b items. + * config/riscv/riscv.opt: New macro for 7 new unprivileged + extensions. + * doc/invoke.texi (RISC-V Options): Add Za64rs, Za128rs, + Ziccif, Ziccrse, Ziccamoa, Zicclsm, Zic64b extensions. + +2024-02-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * config/sol2.h (LIBASAN_EARLY_SPEC): Add -z now unless + -static-libasan. Add missing whitespace. + +2024-02-01 Thomas Schwinge <tschwinge@baylibre.com> + + * config/gcn/gcn.md (FIRST_SGPR_REG, LAST_SGPR_REG) + (FIRST_VGPR_REG, LAST_VGPR_REG, FIRST_AVGPR_REG, LAST_AVGPR_REG): + Don't 'define_constants'. + +2024-02-01 Thomas Schwinge <tschwinge@baylibre.com> + + * config/gcn/gcn.h (SGPR_OR_VGPR_REGNO_P): Remove. + +2024-02-01 Thomas Schwinge <tschwinge@baylibre.com> + + * config/gcn/gcn.md (sync_compare_and_swap<mode>_lds_insn) + [TARGET_RDNA3]: Adjust. + +2024-02-01 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113693 + * tree-ssa-sccvn.cc (rpo_elim::eliminate_avail): Honor avail + data when available. + +2024-02-01 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/113531 + * gimple-low.cc (lower_stmt): Remove .ASAN_MARK calls + on variables which were promoted to TREE_STATIC. + +2024-02-01 Roger Sayle <roger@nextmovesoftware.com> + Richard Biener <rguenther@suse.de> + + PR target/113560 + * tree-ssa-math-opts.cc (is_widening_mult_rhs_p): Use range + information via tree_non_zero_bits to check if this operand + is suitably extended for a widening (or highpart) multiplication. + (convert_mult_to_widen): Insert explicit casts if the RHS or LHS + isn't already of the claimed type. + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + Revert: + 2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + * config/riscv/generic-ooo.md (generic_ooo_sfb_alu): Add reservation + (generic_ooo_branch): ditto + * config/riscv/generic.md (generic_sfb_alu): ditto + (generic_fmul_half): ditto + * config/riscv/riscv.md: Remove cbo, pushpop, and rdfrm types + * config/riscv/sifive-7.md (sifive_7_hfma):Add reservation + (sifive_7_popcount): ditto + * config/riscv/vector.md: change rdfrm to fmove + * config/riscv/zc.md: change pushpop to load/store + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + Revert: + 2024-02-01 Edwin Lu <ewlu@rivosinc.com> + Robin Dapp <rdapp.gcc@gmail.com> + + * config/riscv/generic-ooo.md (generic_ooo): Move reservation + (generic_ooo_vec_load): ditto + (generic_ooo_vec_store): ditto + (generic_ooo_vec_loadstore_seg): ditto + (generic_ooo_vec_alu): ditto + (generic_ooo_vec_fcmp): ditto + (generic_ooo_vec_imul): ditto + (generic_ooo_vec_fadd): ditto + (generic_ooo_vec_fmul): ditto + (generic_ooo_crypto): ditto + (generic_ooo_perm): ditto + (generic_ooo_vec_reduction): ditto + (generic_ooo_vec_ordered_reduction): ditto + (generic_ooo_vec_idiv): ditto + (generic_ooo_vec_float_divsqrt): ditto + (generic_ooo_vec_mask): ditto + (generic_ooo_vec_vesetvl): ditto + (generic_ooo_vec_setrm): ditto + (generic_ooo_vec_readlen): ditto + * config/riscv/riscv.md: include generic-vector-ooo + * config/riscv/generic-vector-ooo.md: New file. to here + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + Revert: + 2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + * config/riscv/riscv.cc (riscv_sched_variable_issue): enable assert + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + * config/riscv/riscv.cc (riscv_sched_variable_issue): enable assert + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + Robin Dapp <rdapp.gcc@gmail.com> + + * config/riscv/generic-ooo.md (generic_ooo): Move reservation + (generic_ooo_vec_load): ditto + (generic_ooo_vec_store): ditto + (generic_ooo_vec_loadstore_seg): ditto + (generic_ooo_vec_alu): ditto + (generic_ooo_vec_fcmp): ditto + (generic_ooo_vec_imul): ditto + (generic_ooo_vec_fadd): ditto + (generic_ooo_vec_fmul): ditto + (generic_ooo_crypto): ditto + (generic_ooo_perm): ditto + (generic_ooo_vec_reduction): ditto + (generic_ooo_vec_ordered_reduction): ditto + (generic_ooo_vec_idiv): ditto + (generic_ooo_vec_float_divsqrt): ditto + (generic_ooo_vec_mask): ditto + (generic_ooo_vec_vesetvl): ditto + (generic_ooo_vec_setrm): ditto + (generic_ooo_vec_readlen): ditto + * config/riscv/riscv.md: include generic-vector-ooo + * config/riscv/generic-vector-ooo.md: New file. to here + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + * config/riscv/generic-ooo.md (generic_ooo_sfb_alu): Add reservation + (generic_ooo_branch): ditto + * config/riscv/generic.md (generic_sfb_alu): ditto + (generic_fmul_half): ditto + * config/riscv/riscv.md: Remove cbo, pushpop, and rdfrm types + * config/riscv/sifive-7.md (sifive_7_hfma):Add reservation + (sifive_7_popcount): ditto + * config/riscv/vector.md: change rdfrm to fmove + * config/riscv/zc.md: change pushpop to load/store + +2024-02-01 Andrew Pinski <quic_apinski@quicinc.com> + + PR target/113657 + * config/aarch64/aarch64-simd.md (split for movv8di): + For strict aligned mode, use DImode instead of TImode. + +2024-01-31 Robin Dapp <rdapp@ventanamicro.com> + + PR middle-end/113607 + * match.pd: Make sure else values match when folding a + vec_cond into a conditional operation. + +2024-01-31 Marek Polacek <polacek@redhat.com> + + * doc/invoke.texi: Mention that -fconcepts-ts was deprecated in GCC 14. + +2024-01-31 Tamar Christina <tamar.christina@arm.com> + Matthew Malcomson <matthew.malcomson@arm.com> + + PR sanitizer/112644 + * asan.h (asan_intercepted_p): Incercept memset, memmove, memcpy and + memcmp. + * builtins.cc (expand_builtin): Include HWASAN when checking for + builtin inlining. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR middle-end/110176 + * match.pd (zext (bool) <= (int) 4294967295u): Make sure + to match INTEGER_CST only without outstanding conversion. + +2024-01-31 Alex Coplan <alex.coplan@arm.com> + + PR target/111677 + * config/aarch64/aarch64.cc (aarch64_reg_save_mode): Use + V16QImode for the full 16-byte FPR saves in the vector PCS case. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/111444 + * tree-ssa-sccvn.cc (vn_reference_lookup_3): Do not use + vn_reference_lookup_2 when optimistically skipping may-defs. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113630 + * tree-ssa-pre.cc (compute_avail): Avoid registering a + reference with a representation with not matching base + access size. + +2024-01-31 Jakub Jelinek <jakub@redhat.com> + + PR rtl-optimization/113656 + * simplify-rtx.cc (simplify_context::simplify_unary_operation_1) + <case FLOAT_TRUNCATE>: Fix up last argument to simplify_gen_unary. + +2024-01-31 Jakub Jelinek <jakub@redhat.com> + + PR debug/113637 + * dwarf2out.cc (loc_list_from_tree_1): Assume integral types + with BLKmode are larger than DWARF2_ADDR_SIZE. + +2024-01-31 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113639 + * gimple-lower-bitint.cc (bitint_large_huge::handle_operand_addr): + For VIEW_CONVERT_EXPR set rhs1 to its operand. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113670 + * tree-vect-data-refs.cc (vect_check_gather_scatter): + Make sure we can take the address of the reference base. + +2024-01-31 Georg-Johann Lay <avr@gjlay.de> + + * config/avr/avr-mcus.def: Add AVR64DU28, AVR64DU32, ATA5787, + ATA5835, ATtiny64AUTO, ATA5700M322. + * doc/avr-mmcu.texi: Rebuild. + +2024-01-31 Alexandre Oliva <oliva@adacore.com> + + PR debug/113394 + * ipa-strub.cc (build_ref_type_for): Drop nonaliased. Adjust + caller. + +2024-01-31 Alexandre Oliva <oliva@adacore.com> + + PR middle-end/112917 + PR middle-end/113100 + * builtins.cc (expand_builtin_stack_address): Use + STACK_ADDRESS_OFFSET. + * doc/extend.texi (__builtin_stack_address): Adjust. + * config/sparc/sparc.h (STACK_ADDRESS_OFFSET): Define. + * doc/tm.texi.in (STACK_ADDRESS_OFFSET): Document. + * doc/tm.texi: Rebuilt. + +2024-01-31 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + PR target/113495 + * config/riscv/riscv-vsetvl.cc (extract_single_source): Remove. + (pre_vsetvl::compute_vsetvl_def_data): Fix compile time issue. + (pre_vsetvl::compute_transparent): New function. + (pre_vsetvl::compute_lcm_local_properties): Fix compile time time issue. + +2024-01-30 Fangrui Song <maskray@google.com> + + PR target/105576 + * config/i386/constraints.md: Define constraint "Ws". + * doc/md.texi: Document it. + +2024-01-30 Marek Polacek <polacek@redhat.com> + + PR c++/110358 + PR c++/109640 + * doc/invoke.texi: Update -Wdangling-reference description. + +2024-01-30 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/constraints.md (R, T, U): + Change define_constraint to define_memory_constraint. + * config/xtensa/predicates.md (move_operand): Don't check that a + constant pool operand size is a multiple of UNITS_PER_WORD. + * config/xtensa/xtensa.cc + (xtensa_lra_p, TARGET_LRA_P): Remove. + (xtensa_emit_move_sequence): Remove "if (reload_in_progress)" + clause as it can no longer be true. + (fixup_subreg_mem): Drop function. + (xtensa_output_integer_literal_parts): Consider 16-bit wide + constants. + (xtensa_legitimate_constant_p): Add short-circuit path for + integer load instructions. Don't check that mode size is + at least UNITS_PER_WORD. + * config/xtensa/xtensa.md (movsf): Use can_create_pseudo_p() + rather reload_in_progress and reload_completed. + (doloop_end): Drop operand 2. + (movhi_internal): Add alternative loading constant from a + literal pool. + (define_split for DI register_operand): Don't limit to + !TARGET_AUTO_LITPOOLS. + * config/xtensa/xtensa.opt (mlra): Change to no effect. + +2024-01-30 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv.cc (riscv_v_vls_mode_aggregate_gpr_count): New function to + calculate the gpr count required by vls mode. + (riscv_v_vls_to_gpr_mode): New function convert vls mode to gpr mode. + (riscv_pass_vls_aggregate_in_gpr): New function to return the rtx of gpr + for vls mode. + (riscv_get_arg_info): Add vls mode handling. + (riscv_pass_by_reference): Return false if arg info has no zero gpr count. + +2024-01-30 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113659 + * tree-vect-loop-manip.cc (slpeel_tree_duplicate_loop_to_edge_cfg): + Handle main exit without virtual use. + +2024-01-30 Christoph Müllner <christoph.muellner@vrull.eu> + + * config/riscv/riscv.md: Move UNSPEC_XTHEADFMV* to unspec enum. + +2024-01-30 Iain Sandoe <iain@sandoe.co.uk> + + PR libgcc/113403 + * config/darwin.h (DARWIN_SHARED_WEAK_ADDS, DARWIN_WEAK_CRTS): New. + (REAL_LIBGCC_SPEC): Move weak CRT handling to separate spec. + * config/i386/darwin.h (DARWIN_HEAP_T_LIB): New. + * config/i386/darwin32-biarch.h (DARWIN_HEAP_T_LIB): New. + * config/i386/darwin64-biarch.h (DARWIN_HEAP_T_LIB): New. + * config/rs6000/darwin.h (DARWIN_HEAP_T_LIB): New. + +2024-01-30 Richard Sandiford <richard.sandiford@arm.com> + + PR target/113623 + * config/aarch64/aarch64-early-ra.cc (early_ra::preprocess_insns): + Mark all registers that occur in addresses as needing a GPR. + +2024-01-30 Richard Sandiford <richard.sandiford@arm.com> + + PR target/113636 + * config/aarch64/aarch64-early-ra.cc (early_ra::replace_regs): Take + the containing insn as an extra parameter. Reset debug instructions + if they reference a register that is no longer used by real insns. + (early_ra::apply_allocation): Update calls accordingly. + +2024-01-30 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113603 + * tree-ssa-strlen.cc (strlen_pass::handle_store): After + count_nonzero_bytes call refetch si using get_strinfo in case it + has been unshared in the meantime. + +2024-01-30 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/101195 + * except.cc (expand_builtin_eh_return_data_regno): If which doesn't + fit into unsigned HOST_WIDE_INT, return constm1_rtx. + +2024-01-30 Jin Ma <jinma@linux.alibaba.com> + + * config/riscv/thead.cc (th_print_operand_address): Change %ld + to %lld. + 2024-01-29 Manos Anagnostakis <manos.anagnostakis@vrull.eu> Manolis Tsamis <manolis.tsamis@vrull.eu> Philipp Tomsich <philipp.tomsich@vrull.eu> diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index d984aca..fb89643 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20240130 +20240207 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 338a782..f666c73 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,39 @@ +2024-01-31 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/113253 + * region-model.cc (region_model::on_stmt_pre): Add gcc_unreachable + for debug statements. + * state-purge.cc + (state_purge_per_ssa_name::state_purge_per_ssa_name): Skip any + debug stmts in the FOR_EACH_IMM_USE_FAST list. + * supergraph.cc (supergraph::supergraph): Don't add debug stmts + to the supernodes. + +2024-01-31 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/113509 + * checker-event.cc (state_change_event::get_desc): Don't assume + "var" is non-NULL. + +2024-01-30 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/113654 + * region-model.cc (is_round_up): New. + (is_multiple_p): New. + (is_dubious_capacity): New. + (region_model::check_region_size): Move usage of size_visitor into + is_dubious_capacity. + +2024-01-30 David Malcolm <dmalcolm@redhat.com> + + * region-model.cc + (dubious_allocation_size::dubious_allocation_size): Add + "capacity_sval" param. Drop unused ctor. + (dubious_allocation_size::maybe_add_sarif_properties): New. + (dubious_allocation_size::m_capacity_sval): New field. + (region_model::check_region_size): Pass capacity svalue to + dubious_allocation_size ctor. + 2024-01-25 David Malcolm <dmalcolm@redhat.com> PR analyzer/112969 diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc index 3ff3aea..b64c58e 100644 --- a/gcc/analyzer/checker-event.cc +++ b/gcc/analyzer/checker-event.cc @@ -443,25 +443,48 @@ state_change_event::get_desc (bool can_colorize) const meaning.dump_to_pp (&meaning_pp); /* Append debug version. */ - if (m_origin) - return make_label_text - (can_colorize, - "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)", - custom_desc.get (), - var, - m_from->get_name (), - m_to->get_name (), - origin, - pp_formatted_text (&meaning_pp)); + if (var) + { + if (m_origin) + return make_label_text + (can_colorize, + "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)", + custom_desc.get (), + var, + m_from->get_name (), + m_to->get_name (), + origin, + pp_formatted_text (&meaning_pp)); + else + return make_label_text + (can_colorize, + "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)", + custom_desc.get (), + var, + m_from->get_name (), + m_to->get_name (), + pp_formatted_text (&meaning_pp)); + } else - return make_label_text - (can_colorize, - "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)", - custom_desc.get (), - var, - m_from->get_name (), - m_to->get_name (), - pp_formatted_text (&meaning_pp)); + { + if (m_origin) + return make_label_text + (can_colorize, + "%s (state: %qs -> %qs, origin: %qE, meaning: %s)", + custom_desc.get (), + m_from->get_name (), + m_to->get_name (), + origin, + pp_formatted_text (&meaning_pp)); + else + return make_label_text + (can_colorize, + "%s (state: %qs -> %qs, NULL origin, meaning: %s)", + custom_desc.get (), + m_from->get_name (), + m_to->get_name (), + pp_formatted_text (&meaning_pp)); + } } else return custom_desc; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index dbb2149..a26be70 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1307,6 +1307,11 @@ region_model::on_stmt_pre (const gimple *stmt, /* No-op for now. */ break; + case GIMPLE_DEBUG: + /* We should have stripped these out when building the supergraph. */ + gcc_unreachable (); + break; + case GIMPLE_ASSIGN: { const gassign *assign = as_a <const gassign *> (stmt); @@ -3113,16 +3118,15 @@ class dubious_allocation_size { public: dubious_allocation_size (const region *lhs, const region *rhs, + const svalue *capacity_sval, tree expr, const gimple *stmt) - : m_lhs (lhs), m_rhs (rhs), m_expr (NULL_TREE), m_stmt (stmt), - m_has_allocation_event (false) - {} - - dubious_allocation_size (const region *lhs, const region *rhs, - tree expr, const gimple *stmt) - : m_lhs (lhs), m_rhs (rhs), m_expr (expr), m_stmt (stmt), + : m_lhs (lhs), m_rhs (rhs), + m_capacity_sval (capacity_sval), m_expr (expr), + m_stmt (stmt), m_has_allocation_event (false) - {} + { + gcc_assert (m_capacity_sval); + } const char *get_kind () const final override { @@ -3196,9 +3200,21 @@ public: interest->add_region_creation (m_rhs); } + void maybe_add_sarif_properties (sarif_object &result_obj) + const final override + { + sarif_property_bag &props = result_obj.get_or_create_properties (); +#define PROPERTY_PREFIX "gcc/analyzer/dubious_allocation_size/" + props.set (PROPERTY_PREFIX "lhs", m_lhs->to_json ()); + props.set (PROPERTY_PREFIX "rhs", m_rhs->to_json ()); + props.set (PROPERTY_PREFIX "capacity_sval", m_capacity_sval->to_json ()); +#undef PROPERTY_PREFIX + } + private: const region *m_lhs; const region *m_rhs; + const svalue *m_capacity_sval; const tree m_expr; const gimple *m_stmt; bool m_has_allocation_event; @@ -3338,6 +3354,76 @@ private: svalue_set result_set; /* Used as a mapping of svalue*->bool. */ }; +/* Return true if SIZE_CST is a power of 2, and we have + CAPACITY_SVAL == ((X | (Y - 1) ) + 1), since it is then a multiple + of SIZE_CST, as used by Linux kernel's round_up macro. */ + +static bool +is_round_up (tree size_cst, + const svalue *capacity_sval) +{ + if (!integer_pow2p (size_cst)) + return false; + const binop_svalue *binop_sval = capacity_sval->dyn_cast_binop_svalue (); + if (!binop_sval) + return false; + if (binop_sval->get_op () != PLUS_EXPR) + return false; + tree rhs_cst = binop_sval->get_arg1 ()->maybe_get_constant (); + if (!rhs_cst) + return false; + if (!integer_onep (rhs_cst)) + return false; + + /* We have CAPACITY_SVAL == (LHS + 1) for some LHS expression. */ + + const binop_svalue *lhs_binop_sval + = binop_sval->get_arg0 ()->dyn_cast_binop_svalue (); + if (!lhs_binop_sval) + return false; + if (lhs_binop_sval->get_op () != BIT_IOR_EXPR) + return false; + + tree inner_rhs_cst = lhs_binop_sval->get_arg1 ()->maybe_get_constant (); + if (!inner_rhs_cst) + return false; + + if (wi::to_widest (inner_rhs_cst) + 1 != wi::to_widest (size_cst)) + return false; + return true; +} + +/* Return true if CAPACITY_SVAL is known to be a multiple of SIZE_CST. */ + +static bool +is_multiple_p (tree size_cst, + const svalue *capacity_sval) +{ + if (const svalue *sval = capacity_sval->maybe_undo_cast ()) + return is_multiple_p (size_cst, sval); + + if (is_round_up (size_cst, capacity_sval)) + return true; + + return false; +} + +/* Return true if we should emit a dubious_allocation_size warning + on assigning a region of capacity CAPACITY_SVAL bytes to a pointer + of type with size SIZE_CST, where CM expresses known constraints. */ + +static bool +is_dubious_capacity (tree size_cst, + const svalue *capacity_sval, + constraint_manager *cm) +{ + if (is_multiple_p (size_cst, capacity_sval)) + return false; + size_visitor v (size_cst, capacity_sval, cm); + return v.is_dubious_capacity (); +} + + /* Return true if a struct or union either uses the inheritance pattern, where the first field is a base struct, or the flexible array member pattern, where the last field is an array without a specified size. */ @@ -3437,7 +3523,7 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, && !capacity_compatible_with_type (cst_cap, pointee_size_tree, is_struct)) ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg, rhs_reg, - cst_cap, + capacity, cst_cap, ctxt->get_stmt ())); } break; @@ -3445,13 +3531,14 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval, { if (!is_struct) { - size_visitor v (pointee_size_tree, capacity, m_constraints); - if (v.is_dubious_capacity ()) + if (is_dubious_capacity (pointee_size_tree, + capacity, + m_constraints)) { tree expr = get_representative_tree (capacity); ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg, rhs_reg, - expr, + capacity, expr, ctxt->get_stmt ())); } } diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc index 284a03f..93959fb 100644 --- a/gcc/analyzer/state-purge.cc +++ b/gcc/analyzer/state-purge.cc @@ -329,6 +329,15 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map, map.log ("used by stmt: %s", pp_formatted_text (&pp)); } + if (is_gimple_debug (use_stmt)) + { + /* We skipped debug stmts when building the supergraph, + so ignore them now. */ + if (map.get_logger ()) + map.log ("skipping debug stmt"); + continue; + } + const supernode *snode = map.get_sg ().get_supernode_for_stmt (use_stmt); diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index d41a7e6..b822752 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -182,6 +182,10 @@ supergraph::supergraph (logger *logger) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); + /* Discard debug stmts here, so we don't have to check for + them anywhere within the analyzer. */ + if (is_gimple_debug (stmt)) + continue; node_for_stmts->m_stmts.safe_push (stmt); m_stmt_to_node_t.put (stmt, node_for_stmts); m_stmt_uids.make_uid_unique (stmt); @@ -185,8 +185,13 @@ extern hash_set<tree> *asan_handled_variables; inline bool asan_intercepted_p (enum built_in_function fcode) { + /* This list should be kept up-to-date with upstream's version at + compiler-rt/lib/hwasan/hwasan_platform_interceptors.h. */ if (hwasan_sanitize_p ()) - return false; + return fcode == BUILT_IN_MEMCMP + || fcode == BUILT_IN_MEMCPY + || fcode == BUILT_IN_MEMMOVE + || fcode == BUILT_IN_MEMSET; return fcode == BUILT_IN_INDEX || fcode == BUILT_IN_MEMCHR diff --git a/gcc/builtins.cc b/gcc/builtins.cc index a0bd82c..4c04ae0 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -5450,7 +5450,7 @@ expand_builtin_stack_address () rtx ret = convert_to_mode (ptr_mode, copy_to_reg (stack_pointer_rtx), STACK_UNSIGNED); -#ifdef SPARC_STACK_BOUNDARY_HACK +#ifdef STACK_ADDRESS_OFFSET /* Unbias the stack pointer, bringing it to the boundary between the stack area claimed by the active function calling this builtin, and stack ranges that could get clobbered if it called another @@ -5477,8 +5477,7 @@ expand_builtin_stack_address () (caller) function's active area as well, whereas those pushed or allocated temporarily for a call are regarded as part of the callee's stack range, rather than the caller's. */ - if (SPARC_STACK_BOUNDARY_HACK) - ret = plus_constant (ptr_mode, ret, STACK_POINTER_OFFSET); + ret = plus_constant (ptr_mode, ret, STACK_ADDRESS_OFFSET); #endif return force_reg (ptr_mode, ret); @@ -7792,7 +7791,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, default: break; } - if (sanitize_flags_p (SANITIZE_ADDRESS) && asan_intercepted_p (fcode)) + if (sanitize_flags_p (SANITIZE_ADDRESS | SANITIZE_HWADDRESS) + && asan_intercepted_p (fcode)) return expand_call (exp, target, ignore); /* When not optimizing, generate calls to library functions for a certain diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index fd91628..6741eb5 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,15 @@ +2024-02-01 Lewis Hyatt <lhyatt@gmail.com> + + PR preprocessor/105608 + * c-pch.cc (c_common_read_pch): Adjust line map so that libcpp + assigns a location to restored macros which is the same location + that triggered the PCH include. + +2024-01-31 Marek Polacek <polacek@redhat.com> + + * c-opts.cc (c_common_post_options): Add an inform saying that + -fconcepts-ts is deprecated and will be removed in GCC 15. + 2024-01-27 Lewis Hyatt <lhyatt@gmail.com> PR preprocessor/105608 diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index b38a122..b845aff 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1139,6 +1139,11 @@ c_common_post_options (const char **pfilename) if (cxx_dialect >= cxx20 || flag_concepts_ts) flag_concepts = 1; + /* -fconcepts-ts will be removed in GCC 15. */ + if (flag_concepts_ts) + inform (input_location, "%<-fconcepts-ts%> is deprecated and will be " + "removed in GCC 15; please convert your code to C++20 concepts"); + /* -fimmediate-escalation has no effect when immediate functions are not supported. */ if (flag_immediate_escalation && cxx_dialect < cxx20) diff --git a/gcc/c-family/c-pch.cc b/gcc/c-family/c-pch.cc index 79b4f88..9bcfdc8 100644 --- a/gcc/c-family/c-pch.cc +++ b/gcc/c-family/c-pch.cc @@ -318,6 +318,7 @@ c_common_read_pch (cpp_reader *pfile, const char *name, struct save_macro_data *smd; expanded_location saved_loc; bool saved_trace_includes; + int cpp_result; timevar_push (TV_PCH_RESTORE); @@ -343,20 +344,26 @@ c_common_read_pch (cpp_reader *pfile, const char *name, cpp_set_line_map (pfile, line_table); rebuild_location_adhoc_htab (line_table); line_table->trace_includes = saved_trace_includes; - linemap_add (line_table, LC_ENTER, 0, saved_loc.file, saved_loc.line); + + /* Set the current location to the line containing the #include (or the + #pragma GCC pch_preprocess) for the purpose of assigning locations to any + macros that are about to be restored. */ + linemap_add (line_table, LC_ENTER, 0, saved_loc.file, + saved_loc.line > 1 ? saved_loc.line - 1 : saved_loc.line); timevar_push (TV_PCH_CPP_RESTORE); - if (cpp_read_state (pfile, name, f, smd) != 0) - { - fclose (f); - timevar_pop (TV_PCH_CPP_RESTORE); - goto end; - } - timevar_pop (TV_PCH_CPP_RESTORE); + cpp_result = cpp_read_state (pfile, name, f, smd); + /* Set the current location to the line following the #include, where we + were prior to processing the PCH. */ + linemap_line_start (line_table, saved_loc.line, 0); + timevar_pop (TV_PCH_CPP_RESTORE); fclose (f); + if (cpp_result != 0) + goto end; + /* Give the front end a chance to take action after a PCH file has been loaded. */ if (lang_post_pch_load) diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index b1c887b..002bf41 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,35 @@ +2024-02-05 Jakub Jelinek <jakub@redhat.com> + + PR c/113740 + * c-decl.cc (finish_struct): Only use build_bitint_type if + bit-field has width larger or equal to minimum _BitInt + precision. + +2024-01-31 Joseph Myers <josmyers@redhat.com> + + PR c/112571 + * c-decl.cc (start_enum): Clear ENUM_FIXED_UNDERLYING_TYPE_P when + defining without a fixed underlying type an enumeration previously + declared with a fixed underlying type. + +2024-01-31 Martin Uecker <uecker@tugraz.at> + + PR c/113438 + * c-typeck.cc (composite_type_internal): Set TYPE_STUB_DECL. + +2024-01-31 Joseph Myers <josmyers@redhat.com> + + PR c/111059 + PR c/111911 + * c-tree.h (c_objc_common_truthvalue_conversion): Add third + argument. + * c-convert.cc (c_convert): For conversions to boolean, pass third + argument to c_objc_common_truthvalue_conversion rather than + converting here. + * c-typeck.cc (build_c_cast): Ensure arguments with integer + operands are marked as such for conversion to boolean. + (c_objc_common_truthvalue_conversion): Add third argument TYPE. + 2024-01-21 Martin Uecker <uecker@tugraz.at> PR c/113492 diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc index 3e52926..7c1064c 100644 --- a/gcc/c/c-convert.cc +++ b/gcc/c/c-convert.cc @@ -150,8 +150,7 @@ c_convert (tree type, tree expr, bool init_const) case BOOLEAN_TYPE: convert_to_boolean: - return fold_convert_loc - (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); + return c_objc_common_truthvalue_conversion (input_location, expr, type); case POINTER_TYPE: /* The type nullptr_t may be converted to a pointer type. The result is diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 8d18a3e..fe20bc2 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9555,7 +9555,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, if (width != TYPE_PRECISION (type)) { if (TREE_CODE (type) == BITINT_TYPE - && (width > 1 || TYPE_UNSIGNED (type))) + && width >= (TYPE_UNSIGNED (type) ? 1 : 2)) TREE_TYPE (field) = build_bitint_type (width, TYPE_UNSIGNED (type)); else @@ -9905,8 +9905,11 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, if (ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) && fixed_underlying_type == NULL_TREE) - error_at (loc, "%<enum%> declared with but defined without " - "fixed underlying type"); + { + error_at (loc, "%<enum%> declared with but defined without " + "fixed underlying type"); + ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = false; + } the_enum->enum_next_value = integer_zero_node; the_enum->enum_type = enumtype; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index cf29534..1fba9c8 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -755,7 +755,8 @@ bool c_type_variably_modified_p (tree t) extern bool char_type_p (tree); -extern tree c_objc_common_truthvalue_conversion (location_t, tree); +extern tree c_objc_common_truthvalue_conversion (location_t, tree, + tree = integer_type_node); extern tree require_complete_type (location_t, tree); extern bool same_translation_unit_p (const_tree, const_tree); extern int comptypes (tree, tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 66c6abc..3b519c4 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -585,6 +585,11 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) /* Setup the struct/union type. Because we inherit all variably modified components, we can ignore the size expression. */ tree expr = NULL_TREE; + + /* Set TYPE_STUB_DECL for debugging symbols. */ + TYPE_STUB_DECL (n) = pushdecl (build_decl (input_location, TYPE_DECL, + NULL_TREE, n)); + n = finish_struct(input_location, n, fields, attributes, NULL, &expr); n = qualify_type (n, t1); @@ -6363,6 +6368,22 @@ build_c_cast (location_t loc, tree type, tree expr) " from %qT to %qT", otype, type); ovalue = value; + /* If converting to boolean a value with integer operands that + is not itself represented as an INTEGER_CST, the call below + to note_integer_operands may insert a C_MAYBE_CONST_EXPR, but + build_binary_op as called by c_common_truthvalue_conversion + may also insert a C_MAYBE_CONST_EXPR to indicate that a + subexpression has been fully folded. To avoid nested + C_MAYBE_CONST_EXPR, ensure that + c_objc_common_truthvalue_conversion receives an argument + properly marked as having integer operands in that case. */ + if (int_operands + && TREE_CODE (value) != INTEGER_CST + && (TREE_CODE (type) == BOOLEAN_TYPE + || (TREE_CODE (type) == ENUMERAL_TYPE + && ENUM_UNDERLYING_TYPE (type) != NULL_TREE + && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) == BOOLEAN_TYPE))) + value = note_integer_operands (value); value = convert (type, value); /* Ignore any integer overflow caused by the cast. */ @@ -13509,11 +13530,11 @@ build_binary_op (location_t location, enum tree_code code, } -/* Convert EXPR to be a truth-value, validating its type for this +/* Convert EXPR to be a truth-value (type TYPE), validating its type for this purpose. LOCATION is the source location for the expression. */ tree -c_objc_common_truthvalue_conversion (location_t location, tree expr) +c_objc_common_truthvalue_conversion (location_t location, tree expr, tree type) { bool int_const, int_operands; @@ -13556,14 +13577,17 @@ c_objc_common_truthvalue_conversion (location_t location, tree expr) if (int_operands && TREE_CODE (expr) != INTEGER_CST) { expr = remove_c_maybe_const_expr (expr); - expr = build2 (NE_EXPR, integer_type_node, expr, + expr = build2 (NE_EXPR, type, expr, convert (TREE_TYPE (expr), integer_zero_node)); expr = note_integer_operands (expr); } else - /* ??? Should we also give an error for vectors rather than leaving - those to give errors later? */ - expr = c_common_truthvalue_conversion (location, expr); + { + /* ??? Should we also give an error for vectors rather than leaving + those to give errors later? */ + expr = c_common_truthvalue_conversion (location, expr); + expr = fold_convert_loc (location, type, expr); + } if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const) { diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 6ac0422..631ce83 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -247,6 +247,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zicond", ISA_SPEC_CLASS_NONE, 1, 0}, + {"za64rs", ISA_SPEC_CLASS_NONE, 1, 0}, + {"za128rs", ISA_SPEC_CLASS_NONE, 1, 0}, {"zawrs", ISA_SPEC_CLASS_NONE, 1, 0}, {"zba", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -276,6 +278,11 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zicboz",ISA_SPEC_CLASS_NONE, 1, 0}, {"zicbom",ISA_SPEC_CLASS_NONE, 1, 0}, {"zicbop",ISA_SPEC_CLASS_NONE, 1, 0}, + {"zic64b", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ziccamoa", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ziccif", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zicclsm", ISA_SPEC_CLASS_NONE, 1, 0}, + {"ziccrse", ISA_SPEC_CLASS_NONE, 1, 0}, {"zicntr", ISA_SPEC_CLASS_NONE, 2, 0}, {"zihpm", ISA_SPEC_CLASS_NONE, 2, 0}, @@ -1494,6 +1501,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zifencei", &gcc_options::x_riscv_zi_subext, MASK_ZIFENCEI}, {"zicond", &gcc_options::x_riscv_zi_subext, MASK_ZICOND}, + {"za64rs", &gcc_options::x_riscv_za_subext, MASK_ZA64RS}, + {"za128rs", &gcc_options::x_riscv_za_subext, MASK_ZA128RS}, {"zawrs", &gcc_options::x_riscv_za_subext, MASK_ZAWRS}, {"zba", &gcc_options::x_riscv_zb_subext, MASK_ZBA}, @@ -1523,6 +1532,11 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zicboz", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOZ}, {"zicbom", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOM}, {"zicbop", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOP}, + {"zic64b", &gcc_options::x_riscv_zicmo_subext, MASK_ZIC64B}, + {"ziccamoa", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCAMOA}, + {"ziccif", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCIF}, + {"zicclsm", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCLSM}, + {"ziccrse", &gcc_options::x_riscv_zicmo_subext, MASK_ZICCRSE}, {"zve32x", &gcc_options::x_target_flags, MASK_VECTOR}, {"zve32f", &gcc_options::x_target_flags, MASK_VECTOR}, diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index f036f6c..f8bb973 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -8221,14 +8221,17 @@ || (memory_operand (operands[0], V8DImode) && register_operand (operands[1], V8DImode))) { + /* V8DI only guarantees 8-byte alignment, whereas TImode requires 16. */ + auto mode = STRICT_ALIGNMENT ? DImode : TImode; + int increment = GET_MODE_SIZE (mode); std::pair<rtx, rtx> last_pair = {}; - for (int offset = 0; offset < 64; offset += 16) + for (int offset = 0; offset < 64; offset += increment) { std::pair<rtx, rtx> pair = { - simplify_gen_subreg (TImode, operands[0], V8DImode, offset), - simplify_gen_subreg (TImode, operands[1], V8DImode, offset) + simplify_gen_subreg (mode, operands[0], V8DImode, offset), + simplify_gen_subreg (mode, operands[1], V8DImode, offset) }; - if (register_operand (pair.first, TImode) + if (register_operand (pair.first, mode) && reg_overlap_mentioned_p (pair.first, pair.second)) last_pair = pair; else diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index a37d47b..32eae49 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -2361,7 +2361,7 @@ aarch64_reg_save_mode (unsigned int regno) case ARM_PCS_SIMD: /* The vector PCS saves the low 128 bits (which is the full register on non-SVE targets). */ - return TFmode; + return V16QImode; case ARM_PCS_SVE: /* Use vectors of DImode for registers that need frame @@ -12961,6 +12961,8 @@ aarch64_class_max_nregs (reg_class_t regclass, machine_mode mode) && constant_multiple_p (GET_MODE_SIZE (mode), aarch64_vl_bytes (mode, vec_flags), &nregs)) return nregs; + if (vec_flags == (VEC_ADVSIMD | VEC_STRUCT | VEC_PARTIAL)) + return GET_MODE_SIZE (mode).to_constant () / 8; return (vec_flags & VEC_ADVSIMD ? CEIL (lowest_size, UNITS_PER_VREG) : CEIL (lowest_size, UNITS_PER_WORD)); @@ -13130,7 +13132,7 @@ aarch64_output_sme_zero_za (rtx mask) if (mask_val == 0xff) return "zero\t{ za }"; - static constexpr std::pair<unsigned int, char> tiles[] = { + static constexpr struct { unsigned char mask; char letter; } tiles[] = { { 0xff, 'b' }, { 0x55, 'h' }, { 0x11, 's' }, @@ -13144,14 +13146,14 @@ aarch64_output_sme_zero_za (rtx mask) const char *prefix = "{ "; for (auto &tile : tiles) { - auto tile_mask = tile.first; + unsigned int tile_mask = tile.mask; unsigned int tile_index = 0; while (tile_mask < 0x100) { if ((mask_val & tile_mask) == tile_mask) { i += snprintf (buffer + i, sizeof (buffer) - i, "%sza%d.%c", - prefix, tile_index, tile.second); + prefix, tile_index, tile.letter); prefix = ", "; mask_val &= ~tile_mask; } @@ -19870,6 +19872,62 @@ build_ifunc_arg_type () return pointer_type; } +/* Implement TARGET_MANGLE_DECL_ASSEMBLER_NAME, to add function multiversioning + suffixes. */ + +tree +aarch64_mangle_decl_assembler_name (tree decl, tree id) +{ + /* For function version, add the target suffix to the assembler name. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_FUNCTION_VERSIONED (decl)) + { + aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl); + + std::string name = IDENTIFIER_POINTER (id); + + /* For the default version, append ".default". */ + if (feature_mask == 0ULL) + { + name += ".default"; + return get_identifier (name.c_str()); + } + + name += "._"; + + for (int i = 0; i < FEAT_MAX; i++) + { + if (feature_mask & aarch64_fmv_feature_data[i].feature_mask) + { + name += "M"; + name += aarch64_fmv_feature_data[i].name; + } + } + + if (DECL_ASSEMBLER_NAME_SET_P (decl)) + SET_DECL_RTL (decl, NULL); + + id = get_identifier (name.c_str()); + } + return id; +} + +/* Return an identifier for the base assembler name of a versioned function. + This is computed by taking the default version's assembler name, and + stripping off the ".default" suffix if it's already been appended. */ + +static tree +get_suffixed_assembler_name (tree default_decl, const char *suffix) +{ + std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl)); + + auto size = name.size (); + if (size >= 8 && name.compare (size - 8, 8, ".default") == 0) + name.resize (size - 8); + name += suffix; + return get_identifier (name.c_str()); +} + /* Make the resolver function decl to dispatch the versions of a multi-versioned function, DEFAULT_DECL. IFUNC_ALIAS_DECL is ifunc alias that will point to the created resolver. Create an @@ -19883,8 +19941,9 @@ make_resolver_func (const tree default_decl, { tree decl, type, t; - /* Create resolver function name based on default_decl. */ - tree decl_name = clone_function_name (default_decl, "resolver"); + /* Create resolver function name based on default_decl. We need to remove an + existing ".default" suffix if this has already been appended. */ + tree decl_name = get_suffixed_assembler_name (default_decl, ".resolver"); const char *resolver_name = IDENTIFIER_POINTER (decl_name); /* The resolver function should have signature @@ -20231,6 +20290,28 @@ aarch64_generate_version_dispatcher_body (void *node_p) dispatch_function_versions (resolver_decl, &fn_ver_vec, &empty_bb); cgraph_edge::rebuild_edges (); pop_cfun (); + + /* Fix up symbol names. First we need to obtain the base name, which may + have already been mangled. */ + tree base_name = get_suffixed_assembler_name (default_ver_decl, ""); + + /* We need to redo the version mangling on the non-default versions for the + target_clones case. Redoing the mangling for the target_version case is + redundant but does no harm. We need to skip the default version, because + expand_clones will append ".default" later; fortunately that suffix is the + one we want anyway. */ + for (versn_info = node_version_info->next->next; versn_info; + versn_info = versn_info->next) + { + tree version_decl = versn_info->this_node->decl; + tree name = aarch64_mangle_decl_assembler_name (version_decl, + base_name); + symtab->change_decl_assembler_name (version_decl, name); + } + + /* We also need to use the base name for the ifunc declaration. */ + symtab->change_decl_assembler_name (node->decl, base_name); + return resolver_decl; } @@ -20343,42 +20424,6 @@ aarch64_common_function_versions (tree fn1, tree fn2) return (aarch64_compare_version_priority (fn1, fn2) != 0); } -/* Implement TARGET_MANGLE_DECL_ASSEMBLER_NAME, to add function multiversioning - suffixes. */ - -tree -aarch64_mangle_decl_assembler_name (tree decl, tree id) -{ - /* For function version, add the target suffix to the assembler name. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_FUNCTION_VERSIONED (decl)) - { - aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl); - - /* No suffix for the default version. */ - if (feature_mask == 0ULL) - return id; - - std::string name = IDENTIFIER_POINTER (id); - name += "._"; - - for (int i = 0; i < FEAT_MAX; i++) - { - if (feature_mask & aarch64_fmv_feature_data[i].feature_mask) - { - name += "M"; - name += aarch64_fmv_feature_data[i].name; - } - } - - if (DECL_ASSEMBLER_NAME_SET_P (decl)) - SET_DECL_RTL (decl, NULL); - - id = get_identifier (name.c_str()); - } - return id; -} - /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. Use an opt-out rather than an opt-in list. */ diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index e5a9444..c44047c 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -29257,6 +29257,8 @@ arm_output_mi_thunk (FILE *file, tree thunk, HOST_WIDE_INT delta, const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk)); assemble_start_function (thunk, fnname); + if (aarch_bti_enabled ()) + emit_insn (aarch_gen_bti_c ()); if (TARGET_32BIT) arm32_output_mi_thunk (file, thunk, delta, vcall_offset, function); else diff --git a/gcc/config/avr/avr-mcus.def b/gcc/config/avr/avr-mcus.def index 5ffab4d..7ddfba0 100644 --- a/gcc/config/avr/avr-mcus.def +++ b/gcc/config/avr/avr-mcus.def @@ -165,13 +165,16 @@ AVR_MCU ("at90pwm3b", ARCH_AVR4, AVR_ISA_NONE, "__AVR_AT90PWM3B__", AVR_MCU ("at90pwm81", ARCH_AVR4, AVR_ISA_NONE, "__AVR_AT90PWM81__", 0x0100, 0x0, 0x2000, 0) /* Enhanced, > 8K, <= 64K. */ AVR_MCU ("avr5", ARCH_AVR5, AVR_ISA_NONE, NULL, 0x0060, 0x0, 0x4000, 0) -AVR_MCU ("ata5702m322", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5702M322__", 0x0200, 0x0, 0x10000, 0) +AVR_MCU ("ata5700m322", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5700M322__", 0x0200, 0x8000, 0x10000, 0) +AVR_MCU ("ata5702m322", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5702M322__", 0x0200, 0x8000, 0x10000, 0) AVR_MCU ("ata5782", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5782__", 0x0200, 0x8000, 0xd000, 0) +AVR_MCU ("ata5787", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5787__", 0x0200, 0x8000, 0xd200, 0) AVR_MCU ("ata5790", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5790__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata5790n", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5790N__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata5791", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5791__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata5795", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5795__", 0x0100, 0x0, 0x2000, 0) AVR_MCU ("ata5831", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5831__", 0x0200, 0x8000, 0xd000, 0) +AVR_MCU ("ata5835", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA5835__", 0x0200, 0x8000, 0xd200, 0) AVR_MCU ("ata6613c", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA6613C__", 0x0100, 0x0, 0x4000, 0) AVR_MCU ("ata6614q", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA6614Q__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("ata8210", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATA8210__", 0x0200, 0x8000, 0xd000, 0) @@ -318,6 +321,8 @@ AVR_MCU ("avr64dd14", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD14__", AVR_MCU ("avr64dd20", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD20__", 0x6000, 0x0, 0x10000, 0) AVR_MCU ("avr64dd28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD28__", 0x6000, 0x0, 0x10000, 0) AVR_MCU ("avr64dd32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DD32__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64du28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DU28__", 0x6000, 0x0, 0x10000, 0) +AVR_MCU ("avr64du32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64DU32__", 0x6000, 0x0, 0x10000, 0) AVR_MCU ("avr64ea28", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA28__", 0x6800, 0x0, 0x10000, 0) AVR_MCU ("avr64ea32", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA32__", 0x6800, 0x0, 0x10000, 0) AVR_MCU ("avr64ea48", ARCH_AVRXMEGA2, AVR_ISA_FLMAP, "__AVR_AVR64EA48__", 0x6800, 0x0, 0x10000, 0) @@ -339,6 +344,7 @@ AVR_MCU ("attiny214", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny214__", AVR_MCU ("attiny412", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny412__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny414", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny414__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny416", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny416__", 0x3f00, 0x0, 0x1000, 0x8000) +AVR_MCU ("attiny416auto", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny416AUTO__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny417", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny417__", 0x3f00, 0x0, 0x1000, 0x8000) AVR_MCU ("attiny814", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny814__", 0x3e00, 0x0, 0x2000, 0x8000) AVR_MCU ("attiny816", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny816__", 0x3e00, 0x0, 0x2000, 0x8000) diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index d77e1aad..d21b286 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -147,12 +147,12 @@ static avr_addr_t avr_addr; /* Prototypes for local helper functions. */ -static const char* out_movqi_r_mr (rtx_insn *, rtx[], int*); -static const char* out_movhi_r_mr (rtx_insn *, rtx[], int*); -static const char* out_movsi_r_mr (rtx_insn *, rtx[], int*); -static const char* out_movqi_mr_r (rtx_insn *, rtx[], int*); -static const char* out_movhi_mr_r (rtx_insn *, rtx[], int*); -static const char* out_movsi_mr_r (rtx_insn *, rtx[], int*); +static const char *out_movqi_r_mr (rtx_insn *, rtx[], int *); +static const char *out_movhi_r_mr (rtx_insn *, rtx[], int *); +static const char *out_movsi_r_mr (rtx_insn *, rtx[], int *); +static const char *out_movqi_mr_r (rtx_insn *, rtx[], int *); +static const char *out_movhi_mr_r (rtx_insn *, rtx[], int *); +static const char *out_movsi_mr_r (rtx_insn *, rtx[], int *); static int get_sequence_length (rtx_insn *insns); static int sequent_regs_live (void); @@ -160,14 +160,14 @@ static const char *ptrreg_to_str (int); static const char *cond_string (enum rtx_code); static int avr_num_arg_regs (machine_mode, const_tree); static int avr_operand_rtx_cost (rtx, machine_mode, enum rtx_code, - int, bool); -static void output_reload_in_const (rtx*, rtx, int*, bool); -static struct machine_function * avr_init_machine_status (void); + int, bool); +static void output_reload_in_const (rtx *, rtx, int *, bool); +static struct machine_function *avr_init_machine_status (void); /* Prototypes for hook implementors if needed before their implementation. */ -static bool avr_rtx_costs (rtx, machine_mode, int, int, int*, bool); +static bool avr_rtx_costs (rtx, machine_mode, int, int, int *, bool); /* Allocate registers from r25 to r8 for parameters for function calls. */ @@ -239,7 +239,7 @@ bool avr_has_rodata_p = false; /* Transform UP into lowercase and write the result to LO. You must provide enough space for LO. Return LO. */ -static char* +static char * avr_tolower (char *lo, const char *up) { char *lo0 = lo; @@ -272,7 +272,7 @@ avr_popcount_each_byte (rtx xval, int n_bytes, int pop_mask) unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode); if ((pop_mask & (1 << popcount_hwi (val8))) == 0) - return false; + return false; } return true; @@ -317,7 +317,7 @@ public: this->name = name; } - virtual unsigned int execute (function*) + virtual unsigned int execute (function *) { df_note_add_problem (); df_analyze (); @@ -349,9 +349,9 @@ public: this->name = name; } - void avr_rest_of_handle_casesi (function*); + void avr_rest_of_handle_casesi (function *); - virtual bool gate (function*) { return optimize > 0; } + virtual bool gate (function *) { return optimize > 0; } virtual unsigned int execute (function *func) { @@ -384,9 +384,9 @@ public: this->name = name; } - void avr_rest_of_handle_ifelse (function*); + void avr_rest_of_handle_ifelse (function *); - virtual bool gate (function*) { return optimize > 0; } + virtual bool gate (function *) { return optimize > 0; } virtual unsigned int execute (function *func) { @@ -398,19 +398,19 @@ public: } // anon namespace -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_recompute_notes (gcc::context *ctxt) { return new avr_pass_recompute_notes (ctxt, "avr-notes-free-cfg"); } -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_casesi (gcc::context *ctxt) { return new avr_pass_casesi (ctxt, "avr-casesi"); } -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_ifelse (gcc::context *ctxt) { return new avr_pass_ifelse (ctxt, "avr-ifelse"); @@ -419,11 +419,11 @@ make_avr_pass_ifelse (gcc::context *ctxt) /* Make one parallel insn with all the patterns from insns i[0]..i[5]. */ -static rtx_insn* +static rtx_insn * avr_parallel_insn_from_insns (rtx_insn *i[5]) { rtvec vec = gen_rtvec (5, PATTERN (i[0]), PATTERN (i[1]), PATTERN (i[2]), - PATTERN (i[3]), PATTERN (i[4])); + PATTERN (i[3]), PATTERN (i[4])); start_sequence(); emit (gen_rtx_PARALLEL (VOIDmode, vec)); rtx_insn *insn = get_insns(); @@ -449,21 +449,21 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) the test, harvest respective insns to INSNS[0..4]. */ if (!(JUMP_P (insns[4] = insn) - // casesi is the only insn that comes up with UNSPEC_INDEX_JMP, - // hence the following test ensures that we are actually dealing - // with code from casesi. - && (set_4 = single_set (insns[4])) - && UNSPEC == GET_CODE (SET_SRC (set_4)) - && UNSPEC_INDEX_JMP == XINT (SET_SRC (set_4), 1) - - && (insns[3] = prev_real_insn (insns[4])) - && (insns[2] = prev_real_insn (insns[3])) - && (insns[1] = prev_real_insn (insns[2])) - - // Insn prior to casesi. - && (insns[0] = prev_real_insn (insns[1])) - && (set_0 = single_set (insns[0])) - && extend_operator (SET_SRC (set_0), SImode))) + // casesi is the only insn that comes up with UNSPEC_INDEX_JMP, + // hence the following test ensures that we are actually dealing + // with code from casesi. + && (set_4 = single_set (insns[4])) + && UNSPEC == GET_CODE (SET_SRC (set_4)) + && UNSPEC_INDEX_JMP == XINT (SET_SRC (set_4), 1) + + && (insns[3] = prev_real_insn (insns[4])) + && (insns[2] = prev_real_insn (insns[3])) + && (insns[1] = prev_real_insn (insns[2])) + + // Insn prior to casesi. + && (insns[0] = prev_real_insn (insns[1])) + && (set_0 = single_set (insns[0])) + && extend_operator (SET_SRC (set_0), SImode))) { return false; } @@ -471,9 +471,9 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) if (dump_file) { fprintf (dump_file, ";; Sequence from casesi in " - "[bb %d]:\n\n", bb->index); + "[bb %d]:\n\n", bb->index); for (int i = 0; i < 5; i++) - print_rtl_single (dump_file, insns[i]); + print_rtl_single (dump_file, insns[i]); } /* We have to deal with quite some operands. Extracting them by hand @@ -491,13 +491,13 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) if (INSN_CODE (xinsn) < 0) { if (dump_file) - fprintf (dump_file, ";; Sequence not recognized, giving up.\n\n"); + fprintf (dump_file, ";; Sequence not recognized, giving up.\n\n"); return false; } gcc_assert (CODE_FOR_casesi_qi_sequence == INSN_CODE (xinsn) - || CODE_FOR_casesi_hi_sequence == INSN_CODE (xinsn)); + || CODE_FOR_casesi_hi_sequence == INSN_CODE (xinsn)); extract_insn (xinsn); @@ -510,7 +510,7 @@ avr_is_casesi_sequence (basic_block bb, rtx_insn *insn, rtx_insn *insns[5]) { fprintf (dump_file, ";; Operands extracted:\n"); for (int i = 0; i < recog_data.n_operands; i++) - avr_fdump (dump_file, ";; $%d = %r\n", i, recog_data.operand[i]); + avr_fdump (dump_file, ";; $%d = %r\n", i, recog_data.operand[i]); fprintf (dump_file, "\n"); } @@ -539,7 +539,7 @@ avr_casei_sequence_check_operands (rtx *xop) if (!AVR_HAVE_EIJMP_EICALL // $6 is: (plus:HI (subreg:SI ($5) 0) - // (label_ref ($3))) + // (label_ref ($3))) && PLUS == GET_CODE (xop[6]) && LABEL_REF == GET_CODE (XEXP (xop[6], 1)) && rtx_equal_p (xop[3], XEXP (XEXP (xop[6], 1), 0)) @@ -574,7 +574,7 @@ avr_casei_sequence_check_operands (rtx *xop) $4: Label if out-of-bounds. $5: $0 + $1. $6: 3-byte PC: subreg:HI ($5) + label_ref ($3) - 2-byte PC: subreg:HI ($5) + 2-byte PC: subreg:HI ($5) $7: HI reg index into table (Z or pseudo) $8: R24 or const0_rtx (to be clobbered) $9: Extension to SImode of an 8-bit or 16-bit integer register $10. @@ -617,15 +617,15 @@ avr_optimize_casesi (rtx_insn *insns[5], rtx *xop) // ok } else if (ZERO_EXTEND == code - && low_idx >= 0 - && (unsigned) hig_idx <= umax) + && low_idx >= 0 + && (unsigned) hig_idx <= umax) { // ok } else { if (dump_file) - fprintf (dump_file, ";; Case ranges too big, giving up.\n\n"); + fprintf (dump_file, ";; Case ranges too big, giving up.\n\n"); return; } @@ -684,21 +684,21 @@ avr_optimize_casesi (rtx_insn *insns[5], rtx *xop) fprintf (dump_file, ";; New insns: "); for (rtx_insn *insn = seq1; ; insn = NEXT_INSN (insn)) - { - fprintf (dump_file, "%d, ", INSN_UID (insn)); - if (insn == last1) - break; - } + { + fprintf (dump_file, "%d, ", INSN_UID (insn)); + if (insn == last1) + break; + } for (rtx_insn *insn = seq2; ; insn = NEXT_INSN (insn)) - { - fprintf (dump_file, "%d%s", INSN_UID (insn), - insn == last2 ? ".\n\n" : ", "); - if (insn == last2) - break; - } + { + fprintf (dump_file, "%d%s", INSN_UID (insn), + insn == last2 ? ".\n\n" : ", "); + if (insn == last2) + break; + } fprintf (dump_file, ";; Deleting insns: %d, %d, %d.\n\n", - INSN_UID (insns[1]), INSN_UID (insns[2]), INSN_UID (insns[3])); + INSN_UID (insns[1]), INSN_UID (insns[2]), INSN_UID (insns[3])); } // Pseudodelete the SImode and subreg of SImode insns. We don't care @@ -721,12 +721,12 @@ avr_pass_casesi::avr_rest_of_handle_casesi (function *func) rtx_insn *insn, *insns[5]; FOR_BB_INSNS (bb, insn) - { - if (avr_is_casesi_sequence (bb, insn, insns)) - { - avr_optimize_casesi (insns, recog_data.operand); - } - } + { + if (avr_is_casesi_sequence (bb, insn, insns)) + { + avr_optimize_casesi (insns, recog_data.operand); + } + } } } @@ -862,7 +862,7 @@ avr_redundant_compare (enum rtx_code cond1, rtx xval1, Hence, run a mini pass right before split2 which introduces REG_CC. */ void -avr_pass_ifelse::avr_rest_of_handle_ifelse (function*) +avr_pass_ifelse::avr_rest_of_handle_ifelse (function *) { rtx_insn *next_insn; @@ -1045,28 +1045,28 @@ avr_set_core_architecture (void) for (const avr_mcu_t *mcu = avr_mcu_types; ; mcu++) { if (mcu->name == NULL) - { - /* Reached the end of `avr_mcu_types'. This should actually never - happen as options are provided by device-specs. It could be a - typo in a device-specs or calling the compiler proper directly - with -mmcu=<device>. */ - - error ("unknown core architecture %qs specified with %qs", - avr_mmcu, "-mmcu="); - avr_inform_core_architectures (); - break; - } + { + /* Reached the end of `avr_mcu_types'. This should actually never + happen as options are provided by device-specs. It could be a + typo in a device-specs or calling the compiler proper directly + with -mmcu=<device>. */ + + error ("unknown core architecture %qs specified with %qs", + avr_mmcu, "-mmcu="); + avr_inform_core_architectures (); + break; + } else if (strcmp (mcu->name, avr_mmcu) == 0 - // Is this a proper architecture ? + // Is this a proper architecture ? && mcu->macro == NULL) - { - avr_arch = &avr_arch_types[mcu->arch_id]; + { + avr_arch = &avr_arch_types[mcu->arch_id]; avr_arch_index = mcu->arch_id; - if (avr_n_flash < 0) - avr_n_flash = 1 + (mcu->flash_size - 1) / 0x10000; + if (avr_n_flash < 0) + avr_n_flash = 1 + (mcu->flash_size - 1) / 0x10000; - return true; - } + return true; + } } return false; @@ -1278,7 +1278,7 @@ bool avr_mem_flash_p (rtx x) { return (MEM_P (x) - && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))); + && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))); } @@ -1289,7 +1289,7 @@ bool avr_mem_memx_p (rtx x) { return (MEM_P (x) - && ADDR_SPACE_MEMX == MEM_ADDR_SPACE (x)); + && ADDR_SPACE_MEMX == MEM_ADDR_SPACE (x)); } @@ -1302,9 +1302,9 @@ avr_lookup_function_attribute1 (const_tree func, const char *name) if (FUNCTION_DECL == TREE_CODE (func)) { if (NULL_TREE != lookup_attribute (name, DECL_ATTRIBUTES (func))) - { - return true; - } + { + return true; + } func = TREE_TYPE (func); } @@ -1408,12 +1408,12 @@ avr_set_current_function (tree decl) if (cfun->machine->is_OS_task && (cfun->machine->is_signal || cfun->machine->is_interrupt)) error_at (loc, "function attributes %qs and %qs are mutually exclusive", - "OS_task", isr); + "OS_task", isr); if (cfun->machine->is_OS_main && (cfun->machine->is_signal || cfun->machine->is_interrupt)) error_at (loc, "function attributes %qs and %qs are mutually exclusive", - "OS_main", isr); + "OS_main", isr); if (cfun->machine->is_interrupt || cfun->machine->is_signal) { @@ -1422,36 +1422,36 @@ avr_set_current_function (tree decl) const char *name; name = DECL_ASSEMBLER_NAME_SET_P (decl) - ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) - : IDENTIFIER_POINTER (DECL_NAME (decl)); + ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)) + : IDENTIFIER_POINTER (DECL_NAME (decl)); /* Skip a leading '*' that might still prefix the assembler name, - e.g. in non-LTO runs. */ + e.g. in non-LTO runs. */ name = default_strip_name_encoding (name); /* Interrupt handlers must be void __vector (void) functions. */ if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE) - error_at (loc, "%qs function cannot have arguments", isr); + error_at (loc, "%qs function cannot have arguments", isr); if (TREE_CODE (ret) != VOID_TYPE) - error_at (loc, "%qs function cannot return a value", isr); + error_at (loc, "%qs function cannot return a value", isr); #if defined WITH_AVRLIBC /* Silently ignore 'signal' if 'interrupt' is present. AVR-LibC startet - using this when it switched from SIGNAL and INTERRUPT to ISR. */ + using this when it switched from SIGNAL and INTERRUPT to ISR. */ if (cfun->machine->is_interrupt) - cfun->machine->is_signal = 0; + cfun->machine->is_signal = 0; /* If the function has the 'signal' or 'interrupt' attribute, ensure - that the name of the function is "__vector_NN" so as to catch - when the user misspells the vector name. */ + that the name of the function is "__vector_NN" so as to catch + when the user misspells the vector name. */ if (!startswith (name, "__vector")) - warning_at (loc, OPT_Wmisspelled_isr, "%qs appears to be a misspelled " - "%qs handler, missing %<__vector%> prefix", name, isr); + warning_at (loc, OPT_Wmisspelled_isr, "%qs appears to be a misspelled " + "%qs handler, missing %<__vector%> prefix", name, isr); #endif // AVR-LibC naming conventions } @@ -1464,8 +1464,8 @@ avr_set_current_function (tree decl) || strcmp ("SIGNAL", name) == 0) { warning_at (loc, OPT_Wmisspelled_isr, "%qs is a reserved identifier" - " in AVR-LibC. Consider %<#include <avr/interrupt.h>%>" - " before using the %qs macro", name, name); + " in AVR-LibC. Consider %<#include <avr/interrupt.h>%>" + " before using the %qs macro", name, name); } #endif // AVR-LibC naming conventions @@ -1484,15 +1484,15 @@ avr_accumulate_outgoing_args (void) return TARGET_ACCUMULATE_OUTGOING_ARGS; /* FIXME: For setjmp and in avr_builtin_setjmp_frame_value we don't know - what offset is correct. In some cases it is relative to - virtual_outgoing_args_rtx and in others it is relative to - virtual_stack_vars_rtx. For example code see - gcc.c-torture/execute/built-in-setjmp.c - gcc.c-torture/execute/builtins/sprintf-chk.c */ + what offset is correct. In some cases it is relative to + virtual_outgoing_args_rtx and in others it is relative to + virtual_stack_vars_rtx. For example code see + gcc.c-torture/execute/built-in-setjmp.c + gcc.c-torture/execute/builtins/sprintf-chk.c */ return (TARGET_ACCUMULATE_OUTGOING_ARGS - && !(cfun->calls_setjmp - || cfun->has_nonlocal_label)); + && !(cfun->calls_setjmp + || cfun->has_nonlocal_label)); } @@ -1541,23 +1541,23 @@ avr_regs_to_save (HARD_REG_SET *set) for (int reg = 0; reg < 32; reg++) { /* Do not push/pop __tmp_reg__, __zero_reg__, as well as - any global register variables. */ + any global register variables. */ if (fixed_regs[reg]) - continue; + continue; if ((int_or_sig_p && !crtl->is_leaf && call_used_or_fixed_reg_p (reg)) - || (df_regs_ever_live_p (reg) - && (int_or_sig_p || !call_used_or_fixed_reg_p (reg)) - /* Don't record frame pointer registers here. They are treated - indivitually in prologue. */ - && !(frame_pointer_needed - && (reg == REG_Y || reg == REG_Y + 1)))) - { - if (set) - SET_HARD_REG_BIT (*set, reg); - count++; - } + || (df_regs_ever_live_p (reg) + && (int_or_sig_p || !call_used_or_fixed_reg_p (reg)) + /* Don't record frame pointer registers here. They are treated + indivitually in prologue. */ + && !(frame_pointer_needed + && (reg == REG_Y || reg == REG_Y + 1)))) + { + if (set) + SET_HARD_REG_BIT (*set, reg); + count++; + } } return count; } @@ -1578,7 +1578,7 @@ static bool avr_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) { return ((frame_pointer_needed && to == FRAME_POINTER_REGNUM) - || !frame_pointer_needed); + || !frame_pointer_needed); } @@ -1610,7 +1610,7 @@ avr_initial_elimination_offset (int from, int to) // by gasisr prologues. offset += avr_regs_to_save (NULL); return (get_frame_size () + avr_outgoing_args_size() - + avr_pc_size + 1 + offset); + + avr_pc_size + 1 + offset); } } @@ -1681,7 +1681,7 @@ avr_return_addr_rtx (int count, rtx tem) { r = gen_rtx_SYMBOL_REF (Pmode, ".L__stack_usage+2"); warning (0, "%<builtin_return_address%> contains only 2 bytes" - " of address"); + " of address"); } else r = gen_rtx_SYMBOL_REF (Pmode, ".L__stack_usage+1"); @@ -1700,13 +1700,13 @@ int avr_simple_epilogue (void) { return (! frame_pointer_needed - && get_frame_size () == 0 - && avr_outgoing_args_size() == 0 - && avr_regs_to_save (NULL) == 0 - && ! cfun->machine->is_interrupt - && ! cfun->machine->is_signal - && ! cfun->machine->is_naked - && ! TREE_THIS_VOLATILE (current_function_decl)); + && get_frame_size () == 0 + && avr_outgoing_args_size() == 0 + && avr_regs_to_save (NULL) == 0 + && ! cfun->machine->is_interrupt + && ! cfun->machine->is_signal + && ! cfun->machine->is_naked + && ! TREE_THIS_VOLATILE (current_function_decl)); } /* This function checks sequence of live registers. */ @@ -1720,45 +1720,45 @@ sequent_regs_live (void) for (int reg = 0; reg <= LAST_CALLEE_SAVED_REG; ++reg) { if (fixed_regs[reg]) - { - /* Don't recognize sequences that contain global register - variables. */ + { + /* Don't recognize sequences that contain global register + variables. */ - if (live_seq != 0) - return 0; - else - continue; - } + if (live_seq != 0) + return 0; + else + continue; + } if (!call_used_or_fixed_reg_p (reg)) - { - if (df_regs_ever_live_p (reg)) - { - ++live_seq; - ++cur_seq; - } - else - cur_seq = 0; - } + { + if (df_regs_ever_live_p (reg)) + { + ++live_seq; + ++cur_seq; + } + else + cur_seq = 0; + } } if (!frame_pointer_needed) { if (df_regs_ever_live_p (REG_Y)) - { - ++live_seq; - ++cur_seq; - } + { + ++live_seq; + ++cur_seq; + } else - cur_seq = 0; + cur_seq = 0; if (df_regs_ever_live_p (REG_Y + 1)) - { - ++live_seq; - ++cur_seq; - } + { + ++live_seq; + ++cur_seq; + } else - cur_seq = 0; + cur_seq = 0; } else { @@ -1772,14 +1772,14 @@ namespace { static const pass_data avr_pass_data_pre_proep = { RTL_PASS, // type - "", // name (will be patched) + "", // name (will be patched) OPTGROUP_NONE, // optinfo_flags TV_DF_SCAN, // tv_id - 0, // properties_required - 0, // properties_provided - 0, // properties_destroyed - 0, // todo_flags_start - 0 // todo_flags_finish + 0, // properties_required + 0, // properties_provided + 0, // properties_destroyed + 0, // todo_flags_start + 0 // todo_flags_finish }; @@ -1792,22 +1792,22 @@ public: this->name = name; } - void compute_maybe_gasisr (function*); + void compute_maybe_gasisr (function *); virtual unsigned int execute (function *fun) { if (avr_gasisr_prologues - // Whether this function is an ISR worth scanning at all. - && !fun->machine->is_no_gccisr - && (fun->machine->is_interrupt - || fun->machine->is_signal) - && !cfun->machine->is_naked - // Paranoia: Non-local gotos and labels that might escape. - && !cfun->calls_setjmp - && !cfun->has_nonlocal_label - && !cfun->has_forced_label_in_static) + // Whether this function is an ISR worth scanning at all. + && !fun->machine->is_no_gccisr + && (fun->machine->is_interrupt + || fun->machine->is_signal) + && !cfun->machine->is_naked + // Paranoia: Non-local gotos and labels that might escape. + && !cfun->calls_setjmp + && !cfun->has_nonlocal_label + && !cfun->has_forced_label_in_static) { - compute_maybe_gasisr (fun); + compute_maybe_gasisr (fun); } return 0; @@ -1817,7 +1817,7 @@ public: } // anon namespace -rtl_opt_pass* +rtl_opt_pass * make_avr_pass_pre_proep (gcc::context *ctxt) { return new avr_pass_pre_proep (ctxt, "avr-pre-proep"); @@ -1839,20 +1839,20 @@ avr_pass_pre_proep::compute_maybe_gasisr (function *fun) // out are open coded (tail) calls. if (CALL_P (insn)) - return; + return; // __tablejump2__ clobbers something and is targeted by JMP so // that GAS won't see its usage. if (AVR_HAVE_JMP_CALL - && JUMP_TABLE_DATA_P (insn)) - return; + && JUMP_TABLE_DATA_P (insn)) + return; // Non-local gotos not seen in *FUN. if (JUMP_P (insn) - && find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) - return; + && find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) + return; } fun->machine->gasisr.maybe = 1; @@ -1893,30 +1893,30 @@ avr_hregs_split_reg (HARD_REG_SET *set) for (int regno = 0; regno < 32; regno++) if (TEST_HARD_REG_BIT (*set, regno)) { - // Don't remove a register from *SET which might indicate that - // some RAMP* register might need ISR prologue / epilogue treatment. - - if (AVR_HAVE_RAMPX - && (REG_X == regno || REG_X + 1 == regno) - && TEST_HARD_REG_BIT (*set, REG_X) - && TEST_HARD_REG_BIT (*set, REG_X + 1)) - continue; - - if (AVR_HAVE_RAMPY - && !frame_pointer_needed - && (REG_Y == regno || REG_Y + 1 == regno) - && TEST_HARD_REG_BIT (*set, REG_Y) - && TEST_HARD_REG_BIT (*set, REG_Y + 1)) - continue; - - if (AVR_HAVE_RAMPZ - && (REG_Z == regno || REG_Z + 1 == regno) - && TEST_HARD_REG_BIT (*set, REG_Z) - && TEST_HARD_REG_BIT (*set, REG_Z + 1)) - continue; - - CLEAR_HARD_REG_BIT (*set, regno); - return regno; + // Don't remove a register from *SET which might indicate that + // some RAMP* register might need ISR prologue / epilogue treatment. + + if (AVR_HAVE_RAMPX + && (REG_X == regno || REG_X + 1 == regno) + && TEST_HARD_REG_BIT (*set, REG_X) + && TEST_HARD_REG_BIT (*set, REG_X + 1)) + continue; + + if (AVR_HAVE_RAMPY + && !frame_pointer_needed + && (REG_Y == regno || REG_Y + 1 == regno) + && TEST_HARD_REG_BIT (*set, REG_Y) + && TEST_HARD_REG_BIT (*set, REG_Y + 1)) + continue; + + if (AVR_HAVE_RAMPZ + && (REG_Z == regno || REG_Z + 1 == regno) + && TEST_HARD_REG_BIT (*set, REG_Z) + && TEST_HARD_REG_BIT (*set, REG_Z + 1)) + continue; + + CLEAR_HARD_REG_BIT (*set, regno); + return regno; } return -1; @@ -1967,7 +1967,7 @@ emit_push_sfr (rtx sfr, bool frame_related_p, bool clr_p, int treg) /* OUT IO(SFR), __zero_reg__ */ insn = emit_move_insn (sfr, const0_rtx); if (frame_related_p) - RTX_FRAME_RELATED_P (insn) = 1; + RTX_FRAME_RELATED_P (insn) = 1; } } @@ -1982,262 +1982,262 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) = (HOST_WIDE_INT) GET_MODE_MASK (AVR_HAVE_8BIT_SP ? QImode : Pmode); bool minimize = (TARGET_CALL_PROLOGUES - && size < size_max - && live_seq - && !isr_p - && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main - && !AVR_TINY); + && size < size_max + && live_seq + && !isr_p + && !cfun->machine->is_OS_task + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (frame_pointer_needed - || avr_outgoing_args_size() > 8 - || (AVR_2_BYTE_PC && live_seq > 6) - || live_seq > 7)) + || avr_outgoing_args_size() > 8 + || (AVR_2_BYTE_PC && live_seq > 6) + || live_seq > 7)) { rtx pattern; int first_reg, reg, offset; emit_move_insn (gen_rtx_REG (HImode, REG_X), - gen_int_mode (size, HImode)); + gen_int_mode (size, HImode)); pattern = gen_call_prologue_saves (gen_int_mode (live_seq, HImode), - gen_int_mode (live_seq+size, HImode)); + gen_int_mode (live_seq+size, HImode)); insn = emit_insn (pattern); RTX_FRAME_RELATED_P (insn) = 1; /* Describe the effect of the unspec_volatile call to prologue_saves. - Note that this formulation assumes that add_reg_note pushes the - notes to the front. Thus we build them in the reverse order of - how we want dwarf2out to process them. */ + Note that this formulation assumes that add_reg_note pushes the + notes to the front. Thus we build them in the reverse order of + how we want dwarf2out to process them. */ /* The function does always set frame_pointer_rtx, but whether that - is going to be permanent in the function is frame_pointer_needed. */ + is going to be permanent in the function is frame_pointer_needed. */ add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET ((frame_pointer_needed + gen_rtx_SET ((frame_pointer_needed ? frame_pointer_rtx : stack_pointer_rtx), - plus_constant (Pmode, stack_pointer_rtx, - -(size + live_seq)))); + plus_constant (Pmode, stack_pointer_rtx, + -(size + live_seq)))); /* Note that live_seq always contains r28+r29, but the other - registers to be saved are all below 18. */ + registers to be saved are all below 18. */ first_reg = (LAST_CALLEE_SAVED_REG + 1) - (live_seq - 2); for (reg = 29, offset = -live_seq + 1; - reg >= first_reg; - reg = (reg == 28 ? LAST_CALLEE_SAVED_REG : reg - 1), ++offset) - { - rtx m, r; + reg >= first_reg; + reg = (reg == 28 ? LAST_CALLEE_SAVED_REG : reg - 1), ++offset) + { + rtx m, r; - m = gen_rtx_MEM (QImode, plus_constant (Pmode, stack_pointer_rtx, - offset)); - r = gen_rtx_REG (QImode, reg); - add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (m, r)); - } + m = gen_rtx_MEM (QImode, plus_constant (Pmode, stack_pointer_rtx, + offset)); + r = gen_rtx_REG (QImode, reg); + add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (m, r)); + } cfun->machine->stack_usage += size + live_seq; } else /* !minimize */ { for (int reg = 0; reg < 32; ++reg) - if (TEST_HARD_REG_BIT (set, reg)) - emit_push_byte (reg, true); + if (TEST_HARD_REG_BIT (set, reg)) + emit_push_byte (reg, true); if (frame_pointer_needed - && (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))) - { - /* Push frame pointer. Always be consistent about the - ordering of pushes -- epilogue_restores expects the - register pair to be pushed low byte first. */ + && (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))) + { + /* Push frame pointer. Always be consistent about the + ordering of pushes -- epilogue_restores expects the + register pair to be pushed low byte first. */ - emit_push_byte (REG_Y, true); - emit_push_byte (REG_Y + 1, true); - } + emit_push_byte (REG_Y, true); + emit_push_byte (REG_Y + 1, true); + } if (frame_pointer_needed - && size == 0) - { - insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - } + && size == 0) + { + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } if (size != 0) - { - /* Creating a frame can be done by direct manipulation of the - stack or via the frame pointer. These two methods are: - fp = sp - fp -= size - sp = fp - or - sp -= size - fp = sp (*) - the optimum method depends on function type, stack and - frame size. To avoid a complex logic, both methods are - tested and shortest is selected. - - There is also the case where SIZE != 0 and no frame pointer is - needed; this can occur if ACCUMULATE_OUTGOING_ARGS is on. - In that case, insn (*) is not needed in that case. - We use the X register as scratch. This is save because in X - is call-clobbered. - In an interrupt routine, the case of SIZE != 0 together with - !frame_pointer_needed can only occur if the function is not a - leaf function and thus X has already been saved. */ - - int irq_state = -1; - HOST_WIDE_INT size_cfa = size, neg_size; - rtx_insn *fp_plus_insns; - rtx fp, my_fp; - - gcc_assert (frame_pointer_needed - || !isr_p - || !crtl->is_leaf); - - fp = my_fp = (frame_pointer_needed - ? frame_pointer_rtx - : gen_rtx_REG (Pmode, REG_X)); - - if (AVR_HAVE_8BIT_SP) - { - /* The high byte (r29) does not change: - Prefer SUBI (1 cycle) over SBIW (2 cycles, same size). */ - - my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; - } - - /* Cut down size and avoid size = 0 so that we don't run - into ICE like PR52488 in the remainder. */ - - if (size > size_max) - { - /* Don't error so that insane code from newlib still compiles - and does not break building newlib. As PR51345 is implemented - now, there are multilib variants with -msp8. - - If user wants sanity checks he can use -Wstack-usage= - or similar options. - - For CFA we emit the original, non-saturated size so that - the generic machinery is aware of the real stack usage and - will print the above diagnostic as expected. */ - - size = size_max; - } - - size = trunc_int_for_mode (size, GET_MODE (my_fp)); - neg_size = trunc_int_for_mode (-size, GET_MODE (my_fp)); - - /************ Method 1: Adjust frame pointer ************/ - - start_sequence (); - - /* Normally, the dwarf2out frame-related-expr interpreter does - not expect to have the CFA change once the frame pointer is - set up. Thus, we avoid marking the move insn below and - instead indicate that the entire operation is complete after - the frame pointer subtraction is done. */ - - insn = emit_move_insn (fp, stack_pointer_rtx); - if (frame_pointer_needed) - { - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (fp, stack_pointer_rtx)); - } - - insn = emit_move_insn (my_fp, plus_constant (GET_MODE (my_fp), - my_fp, neg_size)); - - if (frame_pointer_needed) - { - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (fp, plus_constant (Pmode, fp, + { + /* Creating a frame can be done by direct manipulation of the + stack or via the frame pointer. These two methods are: + fp = sp + fp -= size + sp = fp + or + sp -= size + fp = sp (*) + the optimum method depends on function type, stack and + frame size. To avoid a complex logic, both methods are + tested and shortest is selected. + + There is also the case where SIZE != 0 and no frame pointer is + needed; this can occur if ACCUMULATE_OUTGOING_ARGS is on. + In that case, insn (*) is not needed in that case. + We use the X register as scratch. This is save because in X + is call-clobbered. + In an interrupt routine, the case of SIZE != 0 together with + !frame_pointer_needed can only occur if the function is not a + leaf function and thus X has already been saved. */ + + int irq_state = -1; + HOST_WIDE_INT size_cfa = size, neg_size; + rtx_insn *fp_plus_insns; + rtx fp, my_fp; + + gcc_assert (frame_pointer_needed + || !isr_p + || !crtl->is_leaf); + + fp = my_fp = (frame_pointer_needed + ? frame_pointer_rtx + : gen_rtx_REG (Pmode, REG_X)); + + if (AVR_HAVE_8BIT_SP) + { + /* The high byte (r29) does not change: + Prefer SUBI (1 cycle) over SBIW (2 cycles, same size). */ + + my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; + } + + /* Cut down size and avoid size = 0 so that we don't run + into ICE like PR52488 in the remainder. */ + + if (size > size_max) + { + /* Don't error so that insane code from newlib still compiles + and does not break building newlib. As PR51345 is implemented + now, there are multilib variants with -msp8. + + If user wants sanity checks he can use -Wstack-usage= + or similar options. + + For CFA we emit the original, non-saturated size so that + the generic machinery is aware of the real stack usage and + will print the above diagnostic as expected. */ + + size = size_max; + } + + size = trunc_int_for_mode (size, GET_MODE (my_fp)); + neg_size = trunc_int_for_mode (-size, GET_MODE (my_fp)); + + /************ Method 1: Adjust frame pointer ************/ + + start_sequence (); + + /* Normally, the dwarf2out frame-related-expr interpreter does + not expect to have the CFA change once the frame pointer is + set up. Thus, we avoid marking the move insn below and + instead indicate that the entire operation is complete after + the frame pointer subtraction is done. */ + + insn = emit_move_insn (fp, stack_pointer_rtx); + if (frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (fp, stack_pointer_rtx)); + } + + insn = emit_move_insn (my_fp, plus_constant (GET_MODE (my_fp), + my_fp, neg_size)); + + if (frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (fp, plus_constant (Pmode, fp, -size_cfa))); - } - - /* Copy to stack pointer. Note that since we've already - changed the CFA to the frame pointer this operation - need not be annotated if frame pointer is needed. - Always move through unspec, see PR50063. - For meaning of irq_state see movhi_sp_r insn. */ - - if (cfun->machine->is_interrupt) - irq_state = 1; - - if (TARGET_NO_INTERRUPTS - || cfun->machine->is_signal - || cfun->machine->is_OS_main) - irq_state = 0; - - if (AVR_HAVE_8BIT_SP) - irq_state = 2; - - insn = emit_insn (gen_movhi_sp_r (stack_pointer_rtx, - fp, GEN_INT (irq_state))); - if (!frame_pointer_needed) - { - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (stack_pointer_rtx, - plus_constant (Pmode, - stack_pointer_rtx, - -size_cfa))); - } - - fp_plus_insns = get_insns (); - end_sequence (); - - /************ Method 2: Adjust Stack pointer ************/ - - /* Stack adjustment by means of RCALL . and/or PUSH __TMP_REG__ - can only handle specific offsets. */ - - int n_rcall = size / (AVR_3_BYTE_PC ? 3 : 2); - - if (avr_sp_immediate_operand (gen_int_mode (-size, HImode), HImode) - // Don't use more than 3 RCALLs. - && n_rcall <= 3) - { - rtx_insn *sp_plus_insns; - - start_sequence (); - - insn = emit_move_insn (stack_pointer_rtx, - plus_constant (Pmode, stack_pointer_rtx, - -size)); - RTX_FRAME_RELATED_P (insn) = 1; - add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (stack_pointer_rtx, - plus_constant (Pmode, - stack_pointer_rtx, - -size_cfa))); - if (frame_pointer_needed) - { - insn = emit_move_insn (fp, stack_pointer_rtx); - RTX_FRAME_RELATED_P (insn) = 1; - } - - sp_plus_insns = get_insns (); - end_sequence (); - - /************ Use shortest method ************/ - - emit_insn (get_sequence_length (sp_plus_insns) - < get_sequence_length (fp_plus_insns) - ? sp_plus_insns - : fp_plus_insns); - } - else - { - emit_insn (fp_plus_insns); - } - - cfun->machine->stack_usage += size_cfa; - } /* !minimize && size != 0 */ + } + + /* Copy to stack pointer. Note that since we've already + changed the CFA to the frame pointer this operation + need not be annotated if frame pointer is needed. + Always move through unspec, see PR50063. + For meaning of irq_state see movhi_sp_r insn. */ + + if (cfun->machine->is_interrupt) + irq_state = 1; + + if (TARGET_NO_INTERRUPTS + || cfun->machine->is_signal + || cfun->machine->is_OS_main) + irq_state = 0; + + if (AVR_HAVE_8BIT_SP) + irq_state = 2; + + insn = emit_insn (gen_movhi_sp_r (stack_pointer_rtx, + fp, GEN_INT (irq_state))); + if (!frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, + stack_pointer_rtx, + -size_cfa))); + } + + fp_plus_insns = get_insns (); + end_sequence (); + + /************ Method 2: Adjust Stack pointer ************/ + + /* Stack adjustment by means of RCALL . and/or PUSH __TMP_REG__ + can only handle specific offsets. */ + + int n_rcall = size / (AVR_3_BYTE_PC ? 3 : 2); + + if (avr_sp_immediate_operand (gen_int_mode (-size, HImode), HImode) + // Don't use more than 3 RCALLs. + && n_rcall <= 3) + { + rtx_insn *sp_plus_insns; + + start_sequence (); + + insn = emit_move_insn (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, + -size)); + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (stack_pointer_rtx, + plus_constant (Pmode, + stack_pointer_rtx, + -size_cfa))); + if (frame_pointer_needed) + { + insn = emit_move_insn (fp, stack_pointer_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + + sp_plus_insns = get_insns (); + end_sequence (); + + /************ Use shortest method ************/ + + emit_insn (get_sequence_length (sp_plus_insns) + < get_sequence_length (fp_plus_insns) + ? sp_plus_insns + : fp_plus_insns); + } + else + { + emit_insn (fp_plus_insns); + } + + cfun->machine->stack_usage += size_cfa; + } /* !minimize && size != 0 */ } /* !minimize */ } @@ -2267,79 +2267,79 @@ avr_expand_prologue (void) int treg = AVR_TMP_REGNO; /* Enable interrupts. */ if (cfun->machine->is_interrupt) - emit_insn (gen_enable_interrupt ()); + emit_insn (gen_enable_interrupt ()); if (cfun->machine->gasisr.maybe) - { - /* Let GAS PR21472 emit prologue preamble for us which handles SREG, - ZERO_REG and TMP_REG and one additional, optional register for - us in an optimal way. This even scans through inline asm. */ - - cfun->machine->gasisr.yes = 1; - - // The optional reg or TMP_REG if we don't need one. If we need one, - // remove that reg from SET so that it's not puhed / popped twice. - // We also use it below instead of TMP_REG in some places. - - treg = avr_hregs_split_reg (&set); - if (treg < 0) - treg = AVR_TMP_REGNO; - cfun->machine->gasisr.regno = treg; - - // The worst case of pushes. The exact number can be inferred - // at assembly time by magic expression __gcc_isr.n_pushed. - cfun->machine->stack_usage += 3 + (treg != AVR_TMP_REGNO); - - // Emit a Prologue chunk. Epilogue chunk(s) might follow. - // The final Done chunk is emit by final postscan. - emit_insn (gen_gasisr (GEN_INT (GASISR_Prologue), GEN_INT (treg))); - } + { + /* Let GAS PR21472 emit prologue preamble for us which handles SREG, + ZERO_REG and TMP_REG and one additional, optional register for + us in an optimal way. This even scans through inline asm. */ + + cfun->machine->gasisr.yes = 1; + + // The optional reg or TMP_REG if we don't need one. If we need one, + // remove that reg from SET so that it's not puhed / popped twice. + // We also use it below instead of TMP_REG in some places. + + treg = avr_hregs_split_reg (&set); + if (treg < 0) + treg = AVR_TMP_REGNO; + cfun->machine->gasisr.regno = treg; + + // The worst case of pushes. The exact number can be inferred + // at assembly time by magic expression __gcc_isr.n_pushed. + cfun->machine->stack_usage += 3 + (treg != AVR_TMP_REGNO); + + // Emit a Prologue chunk. Epilogue chunk(s) might follow. + // The final Done chunk is emit by final postscan. + emit_insn (gen_gasisr (GEN_INT (GASISR_Prologue), GEN_INT (treg))); + } else // !TARGET_GASISR_PROLOGUES: Classic, dumb prologue preamble. - { - /* Push zero reg. */ - emit_push_byte (AVR_ZERO_REGNO, true); + { + /* Push zero reg. */ + emit_push_byte (AVR_ZERO_REGNO, true); - /* Push tmp reg. */ - emit_push_byte (AVR_TMP_REGNO, true); + /* Push tmp reg. */ + emit_push_byte (AVR_TMP_REGNO, true); - /* Push SREG. */ - /* ??? There's no dwarf2 column reserved for SREG. */ - emit_push_sfr (sreg_rtx, false, false /* clr */, AVR_TMP_REGNO); + /* Push SREG. */ + /* ??? There's no dwarf2 column reserved for SREG. */ + emit_push_sfr (sreg_rtx, false, false /* clr */, AVR_TMP_REGNO); - /* Clear zero reg. */ - emit_move_insn (zero_reg_rtx, const0_rtx); + /* Clear zero reg. */ + emit_move_insn (zero_reg_rtx, const0_rtx); - /* Prevent any attempt to delete the setting of ZERO_REG! */ - emit_use (zero_reg_rtx); - } + /* Prevent any attempt to delete the setting of ZERO_REG! */ + emit_use (zero_reg_rtx); + } /* Push and clear RAMPD/X/Y/Z if present and low-part register is used. - ??? There are no dwarf2 columns reserved for RAMPD/X/Y/Z. */ + ??? There are no dwarf2 columns reserved for RAMPD/X/Y/Z. */ if (AVR_HAVE_RAMPD) - emit_push_sfr (rampd_rtx, false /* frame */, true /* clr */, treg); + emit_push_sfr (rampd_rtx, false /* frame */, true /* clr */, treg); if (AVR_HAVE_RAMPX - && TEST_HARD_REG_BIT (set, REG_X) - && TEST_HARD_REG_BIT (set, REG_X + 1)) - { - emit_push_sfr (rampx_rtx, false /* frame */, true /* clr */, treg); - } + && TEST_HARD_REG_BIT (set, REG_X) + && TEST_HARD_REG_BIT (set, REG_X + 1)) + { + emit_push_sfr (rampx_rtx, false /* frame */, true /* clr */, treg); + } if (AVR_HAVE_RAMPY - && (frame_pointer_needed - || (TEST_HARD_REG_BIT (set, REG_Y) - && TEST_HARD_REG_BIT (set, REG_Y + 1)))) - { - emit_push_sfr (rampy_rtx, false /* frame */, true /* clr */, treg); - } + && (frame_pointer_needed + || (TEST_HARD_REG_BIT (set, REG_Y) + && TEST_HARD_REG_BIT (set, REG_Y + 1)))) + { + emit_push_sfr (rampy_rtx, false /* frame */, true /* clr */, treg); + } if (AVR_HAVE_RAMPZ - && TEST_HARD_REG_BIT (set, REG_Z) - && TEST_HARD_REG_BIT (set, REG_Z + 1)) - { - emit_push_sfr (rampz_rtx, false /* frame */, AVR_HAVE_RAMPD, treg); - } + && TEST_HARD_REG_BIT (set, REG_Z) + && TEST_HARD_REG_BIT (set, REG_Z + 1)) + { + emit_push_sfr (rampz_rtx, false /* frame */, AVR_HAVE_RAMPD, treg); + } } /* is_interrupt is_signal */ avr_prologue_setup_frame (size, set); @@ -2363,23 +2363,23 @@ avr_asm_function_end_prologue (FILE *file) else { if (cfun->machine->is_interrupt) - { - fputs ("/* prologue: Interrupt */\n", file); - } + { + fputs ("/* prologue: Interrupt */\n", file); + } else if (cfun->machine->is_signal) - { - fputs ("/* prologue: Signal */\n", file); - } + { + fputs ("/* prologue: Signal */\n", file); + } else - fputs ("/* prologue: function */\n", file); + fputs ("/* prologue: function */\n", file); } if (ACCUMULATE_OUTGOING_ARGS) fprintf (file, "/* outgoing args size = %d */\n", - avr_outgoing_args_size()); + avr_outgoing_args_size()); fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n", - (HOST_WIDE_INT) get_frame_size()); + (HOST_WIDE_INT) get_frame_size()); if (!cfun->machine->gasisr.yes) { @@ -2452,29 +2452,29 @@ avr_expand_epilogue (bool sibcall_p) live_seq = sequent_regs_live (); minimize = (TARGET_CALL_PROLOGUES - && live_seq - && !isr_p - && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main - && !AVR_TINY); + && live_seq + && !isr_p + && !cfun->machine->is_OS_task + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (live_seq > 4 - || frame_pointer_needed - || size)) + || frame_pointer_needed + || size)) { /* Get rid of frame. */ if (!frame_pointer_needed) - { - emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); - } + { + emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + } if (size) - { - emit_move_insn (frame_pointer_rtx, - plus_constant (Pmode, frame_pointer_rtx, size)); - } + { + emit_move_insn (frame_pointer_rtx, + plus_constant (Pmode, frame_pointer_rtx, size)); + } emit_insn (gen_epilogue_restores (gen_int_mode (live_seq, HImode))); return; @@ -2490,26 +2490,26 @@ avr_expand_epilogue (bool sibcall_p) HOST_WIDE_INT size_max; gcc_assert (frame_pointer_needed - || !isr_p - || !crtl->is_leaf); + || !isr_p + || !crtl->is_leaf); fp = my_fp = (frame_pointer_needed - ? frame_pointer_rtx - : gen_rtx_REG (Pmode, REG_X)); + ? frame_pointer_rtx + : gen_rtx_REG (Pmode, REG_X)); if (AVR_HAVE_8BIT_SP) - { - /* The high byte (r29) does not change: - Prefer SUBI (1 cycle) over SBIW (2 cycles). */ + { + /* The high byte (r29) does not change: + Prefer SUBI (1 cycle) over SBIW (2 cycles). */ - my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; - } + my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; + } /* For rationale see comment in prologue generation. */ size_max = (HOST_WIDE_INT) GET_MODE_MASK (GET_MODE (my_fp)); if (size > size_max) - size = size_max; + size = size_max; size = trunc_int_for_mode (size, GET_MODE (my_fp)); /********** Method 1: Adjust fp register **********/ @@ -2517,20 +2517,20 @@ avr_expand_epilogue (bool sibcall_p) start_sequence (); if (!frame_pointer_needed) - emit_move_insn (fp, stack_pointer_rtx); + emit_move_insn (fp, stack_pointer_rtx); emit_move_insn (my_fp, plus_constant (GET_MODE (my_fp), my_fp, size)); /* Copy to stack pointer. */ if (TARGET_NO_INTERRUPTS) - irq_state = 0; + irq_state = 0; if (AVR_HAVE_8BIT_SP) - irq_state = 2; + irq_state = 2; emit_insn (gen_movhi_sp_r (stack_pointer_rtx, fp, - GEN_INT (irq_state))); + GEN_INT (irq_state))); fp_plus_insns = get_insns (); end_sequence (); @@ -2538,33 +2538,33 @@ avr_expand_epilogue (bool sibcall_p) /********** Method 2: Adjust Stack pointer **********/ if (avr_sp_immediate_operand (gen_int_mode (size, HImode), HImode)) - { - rtx_insn *sp_plus_insns; + { + rtx_insn *sp_plus_insns; - start_sequence (); + start_sequence (); - emit_move_insn (stack_pointer_rtx, - plus_constant (Pmode, stack_pointer_rtx, size)); + emit_move_insn (stack_pointer_rtx, + plus_constant (Pmode, stack_pointer_rtx, size)); - sp_plus_insns = get_insns (); - end_sequence (); + sp_plus_insns = get_insns (); + end_sequence (); - /************ Use shortest method ************/ + /************ Use shortest method ************/ - emit_insn (get_sequence_length (sp_plus_insns) - < get_sequence_length (fp_plus_insns) - ? sp_plus_insns - : fp_plus_insns); - } + emit_insn (get_sequence_length (sp_plus_insns) + < get_sequence_length (fp_plus_insns) + ? sp_plus_insns + : fp_plus_insns); + } else - emit_insn (fp_plus_insns); + emit_insn (fp_plus_insns); } /* size != 0 */ if (frame_pointer_needed && !(cfun->machine->is_OS_task || cfun->machine->is_OS_main)) { /* Restore previous frame_pointer. See avr_expand_prologue for - rationale for not using pophi. */ + rationale for not using pophi. */ emit_pop_byte (REG_Y + 1); emit_pop_byte (REG_Y); @@ -2588,58 +2588,58 @@ avr_expand_epilogue (bool sibcall_p) if (isr_p) { /* Restore RAMPZ/Y/X/D using tmp_reg as scratch. - The conditions to restore them must be tha same as in prologue. */ + The conditions to restore them must be tha same as in prologue. */ if (AVR_HAVE_RAMPZ - && TEST_HARD_REG_BIT (set, REG_Z) - && TEST_HARD_REG_BIT (set, REG_Z + 1)) - { - emit_pop_byte (treg); - emit_move_insn (rampz_rtx, all_regs_rtx[treg]); - } + && TEST_HARD_REG_BIT (set, REG_Z) + && TEST_HARD_REG_BIT (set, REG_Z + 1)) + { + emit_pop_byte (treg); + emit_move_insn (rampz_rtx, all_regs_rtx[treg]); + } if (AVR_HAVE_RAMPY - && (frame_pointer_needed - || (TEST_HARD_REG_BIT (set, REG_Y) - && TEST_HARD_REG_BIT (set, REG_Y + 1)))) - { - emit_pop_byte (treg); - emit_move_insn (rampy_rtx, all_regs_rtx[treg]); - } + && (frame_pointer_needed + || (TEST_HARD_REG_BIT (set, REG_Y) + && TEST_HARD_REG_BIT (set, REG_Y + 1)))) + { + emit_pop_byte (treg); + emit_move_insn (rampy_rtx, all_regs_rtx[treg]); + } if (AVR_HAVE_RAMPX - && TEST_HARD_REG_BIT (set, REG_X) - && TEST_HARD_REG_BIT (set, REG_X + 1)) - { - emit_pop_byte (treg); - emit_move_insn (rampx_rtx, all_regs_rtx[treg]); - } + && TEST_HARD_REG_BIT (set, REG_X) + && TEST_HARD_REG_BIT (set, REG_X + 1)) + { + emit_pop_byte (treg); + emit_move_insn (rampx_rtx, all_regs_rtx[treg]); + } if (AVR_HAVE_RAMPD) - { - emit_pop_byte (treg); - emit_move_insn (rampd_rtx, all_regs_rtx[treg]); - } + { + emit_pop_byte (treg); + emit_move_insn (rampd_rtx, all_regs_rtx[treg]); + } if (cfun->machine->gasisr.yes) - { - // Emit an Epilogue chunk. - emit_insn (gen_gasisr (GEN_INT (GASISR_Epilogue), - GEN_INT (cfun->machine->gasisr.regno))); - } + { + // Emit an Epilogue chunk. + emit_insn (gen_gasisr (GEN_INT (GASISR_Epilogue), + GEN_INT (cfun->machine->gasisr.regno))); + } else // !TARGET_GASISR_PROLOGUES - { - /* Restore SREG using tmp_reg as scratch. */ + { + /* Restore SREG using tmp_reg as scratch. */ - emit_pop_byte (AVR_TMP_REGNO); - emit_move_insn (sreg_rtx, tmp_reg_rtx); + emit_pop_byte (AVR_TMP_REGNO); + emit_move_insn (sreg_rtx, tmp_reg_rtx); - /* Restore tmp REG. */ - emit_pop_byte (AVR_TMP_REGNO); + /* Restore tmp REG. */ + emit_pop_byte (AVR_TMP_REGNO); - /* Restore zero REG. */ - emit_pop_byte (AVR_ZERO_REGNO); - } + /* Restore zero REG. */ + emit_pop_byte (AVR_ZERO_REGNO); + } } if (!sibcall_p) @@ -2718,13 +2718,13 @@ avr_address_tiny_absdata_p (rtx x, machine_mode mode) static inline bool avr_reg_ok_for_addr_p (rtx reg, addr_space_t as, - RTX_CODE outer_code, bool strict) + RTX_CODE outer_code, bool strict) { return (REG_P (reg) - && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, - as, outer_code, UNKNOWN) - || (!strict - && REGNO (reg) >= FIRST_PSEUDO_REGISTER))); + && (avr_regno_mode_code_ok_for_base_p (REGNO (reg), QImode, + as, outer_code, UNKNOWN) + || (!strict + && REGNO (reg) >= FIRST_PSEUDO_REGISTER))); } @@ -2740,51 +2740,51 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) { case REG: ok = avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC, - MEM, strict); + MEM, strict); if (strict - && GET_MODE_SIZE (mode) > 4 - && REG_X == REGNO (x)) - { - ok = false; - } + && GET_MODE_SIZE (mode) > 4 + && REG_X == REGNO (x)) + { + ok = false; + } break; case POST_INC: case PRE_DEC: ok = avr_reg_ok_for_addr_p (XEXP (x, 0), ADDR_SPACE_GENERIC, - GET_CODE (x), strict); + GET_CODE (x), strict); break; case PLUS: { - rtx reg = XEXP (x, 0); - rtx op1 = XEXP (x, 1); - - if (REG_P (reg) - && CONST_INT_P (op1) - && INTVAL (op1) >= 0) - { - bool fit = IN_RANGE (INTVAL (op1), 0, MAX_LD_OFFSET (mode)); - - if (fit) - { - ok = (! strict - || avr_reg_ok_for_addr_p (reg, ADDR_SPACE_GENERIC, - PLUS, strict)); - - if (reg == frame_pointer_rtx - || reg == arg_pointer_rtx) - { - ok = true; - } - } - else if (frame_pointer_needed - && reg == frame_pointer_rtx) - { - ok = true; - } - } + rtx reg = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + + if (REG_P (reg) + && CONST_INT_P (op1) + && INTVAL (op1) >= 0) + { + bool fit = IN_RANGE (INTVAL (op1), 0, MAX_LD_OFFSET (mode)); + + if (fit) + { + ok = (! strict + || avr_reg_ok_for_addr_p (reg, ADDR_SPACE_GENERIC, + PLUS, strict)); + + if (reg == frame_pointer_rtx + || reg == arg_pointer_rtx) + { + ok = true; + } + } + else if (frame_pointer_needed + && reg == frame_pointer_rtx) + { + ok = true; + } + } } break; @@ -2796,7 +2796,7 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) && CONSTANT_ADDRESS_P (x)) { /* avrtiny's load / store instructions only cover addresses 0..0xbf: - IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */ + IN / OUT range is 0..0x3f and LDS / STS can access 0x40..0xbf. */ ok = avr_address_tiny_absdata_p (x, mode); } @@ -2804,19 +2804,19 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) if (avr_log.legitimate_address_p) { avr_edump ("\n%?: ret=%d, mode=%m strict=%d " - "reload_completed=%d reload_in_progress=%d %s:", - ok, mode, strict, reload_completed, reload_in_progress, - reg_renumber ? "(reg_renumber)" : ""); + "reload_completed=%d reload_in_progress=%d %s:", + ok, mode, strict, reload_completed, reload_in_progress, + reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1)) - && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) - && reg_renumber) - { - avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), - true_regnum (XEXP (x, 0))); - } + && REG_P (XEXP (x, 0)) + && CONST_INT_P (XEXP (x, 1)) + && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) + && reg_renumber) + { + avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), + true_regnum (XEXP (x, 0))); + } avr_edump ("\n%r\n", x); } @@ -2840,27 +2840,27 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) if (AVR_TINY) { if (CONSTANT_ADDRESS_P (x) - && ! avr_address_tiny_absdata_p (x, mode)) - { - x = force_reg (Pmode, x); - } + && ! avr_address_tiny_absdata_p (x, mode)) + { + x = force_reg (Pmode, x); + } } if (GET_CODE (oldx) == PLUS && REG_P (XEXP (oldx, 0))) { if (REG_P (XEXP (oldx, 1))) - x = force_reg (GET_MODE (oldx), oldx); + x = force_reg (GET_MODE (oldx), oldx); else if (CONST_INT_P (XEXP (oldx, 1))) - { - int offs = INTVAL (XEXP (oldx, 1)); - if (frame_pointer_rtx != XEXP (oldx, 0) - && offs > MAX_LD_OFFSET (mode)) - { - big_offset_p = true; - x = force_reg (GET_MODE (oldx), oldx); - } - } + { + int offs = INTVAL (XEXP (oldx, 1)); + if (frame_pointer_rtx != XEXP (oldx, 0) + && offs > MAX_LD_OFFSET (mode)) + { + big_offset_p = true; + x = force_reg (GET_MODE (oldx), oldx); + } + } } if (avr_log.legitimize_address) @@ -2868,7 +2868,7 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) avr_edump ("\n%?: mode=%m\n %r\n", mode, oldx); if (x != oldx) - avr_edump (" %s --> %r\n", big_offset_p ? "(big offset)" : "", x); + avr_edump (" %s --> %r\n", big_offset_p ? "(big offset)" : "", x); } return x; @@ -2882,9 +2882,9 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) rtx avr_legitimize_reload_address (rtx *px, machine_mode mode, - int opnum, int type, int addr_type, - int ind_levels ATTRIBUTE_UNUSED, - rtx (*mk_memloc)(rtx,int)) + int opnum, int type, int addr_type, + int ind_levels ATTRIBUTE_UNUSED, + rtx (*mk_memloc)(rtx,int)) { rtx x = *px; @@ -2892,15 +2892,15 @@ avr_legitimize_reload_address (rtx *px, machine_mode mode, avr_edump ("\n%?:%m %r\n", mode, x); if (1 && (GET_CODE (x) == POST_INC - || GET_CODE (x) == PRE_DEC)) + || GET_CODE (x) == PRE_DEC)) { push_reload (XEXP (x, 0), XEXP (x, 0), &XEXP (x, 0), &XEXP (x, 0), - POINTER_REGS, GET_MODE (x), GET_MODE (x), 0, 0, - opnum, RELOAD_OTHER); + POINTER_REGS, GET_MODE (x), GET_MODE (x), 0, 0, + opnum, RELOAD_OTHER); if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.1 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, XEXP (x, 0), XEXP (x, 0)); + avr_edump (" RCLASS.1 = %R\n IN = %r\n OUT = %r\n", + POINTER_REGS, XEXP (x, 0), XEXP (x, 0)); return x; } @@ -2914,44 +2914,44 @@ avr_legitimize_reload_address (rtx *px, machine_mode mode, bool fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode); if (fit) - { - if (reg_equiv_address (REGNO (XEXP (x, 0))) != 0) - { - int regno = REGNO (XEXP (x, 0)); - rtx mem = mk_memloc (x, regno); - - push_reload (XEXP (mem, 0), NULL_RTX, &XEXP (mem, 0), NULL, - POINTER_REGS, Pmode, VOIDmode, 0, 0, - 1, (enum reload_type) addr_type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, XEXP (mem, 0), NULL_RTX); - - push_reload (mem, NULL_RTX, &XEXP (x, 0), NULL, - BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type) type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", - BASE_POINTER_REGS, mem, NULL_RTX); - - return x; - } - } + { + if (reg_equiv_address (REGNO (XEXP (x, 0))) != 0) + { + int regno = REGNO (XEXP (x, 0)); + rtx mem = mk_memloc (x, regno); + + push_reload (XEXP (mem, 0), NULL_RTX, &XEXP (mem, 0), NULL, + POINTER_REGS, Pmode, VOIDmode, 0, 0, + 1, (enum reload_type) addr_type); + + if (avr_log.legitimize_reload_address) + avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", + POINTER_REGS, XEXP (mem, 0), NULL_RTX); + + push_reload (mem, NULL_RTX, &XEXP (x, 0), NULL, + BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, + opnum, (enum reload_type) type); + + if (avr_log.legitimize_reload_address) + avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", + BASE_POINTER_REGS, mem, NULL_RTX); + + return x; + } + } else if (! (frame_pointer_needed - && XEXP (x, 0) == frame_pointer_rtx)) - { - push_reload (x, NULL_RTX, px, NULL, - POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type) type); + && XEXP (x, 0) == frame_pointer_rtx)) + { + push_reload (x, NULL_RTX, px, NULL, + POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, + opnum, (enum reload_type) type); - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.3 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, x, NULL_RTX); + if (avr_log.legitimize_reload_address) + avr_edump (" RCLASS.3 = %R\n IN = %r\n OUT = %r\n", + POINTER_REGS, x, NULL_RTX); - return x; - } + return x; + } } return NULL_RTX; @@ -2971,17 +2971,17 @@ avr_legitimize_reload_address (rtx *px, machine_mode mode, Don't output anything. */ -static const char* -avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words) +static const char * +avr_asm_len (const char *tpl, rtx *operands, int *plen, int n_words) { if (plen == NULL) output_asm_insn (tpl, operands); else { if (n_words < 0) - *plen = -n_words; + *plen = -n_words; else - *plen += n_words; + *plen += n_words; } return ""; @@ -2990,7 +2990,7 @@ avr_asm_len (const char* tpl, rtx* operands, int* plen, int n_words) /* Return a pointer register name as a string. */ -static const char* +static const char * ptrreg_to_str (int regno) { switch (regno) @@ -3000,7 +3000,7 @@ ptrreg_to_str (int regno) case REG_Z: return "Z"; default: output_operand_lossage ("address operand requires constraint for" - " X, Y, or Z register"); + " X, Y, or Z register"); } return NULL; } @@ -3008,7 +3008,7 @@ ptrreg_to_str (int regno) /* Return the condition name as a string. Used in conditional jump constructing */ -static const char* +static const char * cond_string (enum rtx_code code) { bool cc_overflow_unusable = false; @@ -3021,14 +3021,14 @@ cond_string (enum rtx_code code) return "eq"; case GE: if (cc_overflow_unusable) - return "pl"; + return "pl"; else - return "ge"; + return "ge"; case LT: if (cc_overflow_unusable) - return "mi"; + return "mi"; else - return "lt"; + return "lt"; case GEU: return "sh"; case LTU: @@ -3086,40 +3086,40 @@ avr_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr) default: if (CONSTANT_ADDRESS_P (addr) - && text_segment_operand (addr, VOIDmode)) - { - rtx x = addr; - if (GET_CODE (x) == CONST) - x = XEXP (x, 0); - if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1))) - { - /* Assembler gs() will implant word address. Make offset - a byte offset inside gs() for assembler. This is - needed because the more logical (constant+gs(sym)) is not - accepted by gas. For 128K and smaller devices this is ok. - For large devices it will create a trampoline to offset - from symbol which may not be what the user really wanted. */ - - fprintf (file, "gs("); - output_addr_const (file, XEXP (x, 0)); - fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC ")", - 2 * INTVAL (XEXP (x, 1))); - if (AVR_3_BYTE_PC) - if (warning (0, "pointer offset from symbol maybe incorrect")) - { - output_addr_const (stderr, addr); - fprintf (stderr, "\n"); - } - } - else - { - fprintf (file, "gs("); - output_addr_const (file, addr); - fprintf (file, ")"); - } - } + && text_segment_operand (addr, VOIDmode)) + { + rtx x = addr; + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1))) + { + /* Assembler gs() will implant word address. Make offset + a byte offset inside gs() for assembler. This is + needed because the more logical (constant+gs(sym)) is not + accepted by gas. For 128K and smaller devices this is ok. + For large devices it will create a trampoline to offset + from symbol which may not be what the user really wanted. */ + + fprintf (file, "gs("); + output_addr_const (file, XEXP (x, 0)); + fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC ")", + 2 * INTVAL (XEXP (x, 1))); + if (AVR_3_BYTE_PC) + if (warning (0, "pointer offset from symbol maybe incorrect")) + { + output_addr_const (stderr, addr); + fprintf (stderr, "\n"); + } + } + else + { + fprintf (file, "gs("); + output_addr_const (file, addr); + fprintf (file, ")"); + } + } else - output_addr_const (file, addr); + output_addr_const (file, addr); } } @@ -3152,37 +3152,37 @@ avr_print_operand (FILE *file, rtx x, int code) if (code == '~') { if (!AVR_HAVE_JMP_CALL) - fputc ('r', file); + fputc ('r', file); } else if (code == '!') { if (AVR_HAVE_EIJMP_EICALL) - fputc ('e', file); + fputc ('e', file); } else if (code == 't' - || code == 'T') + || code == 'T') { static int t_regno = -1; static int t_nbits = -1; if (REG_P (x) && t_regno < 0 && code == 'T') - { - t_regno = REGNO (x); - t_nbits = GET_MODE_BITSIZE (GET_MODE (x)); - } + { + t_regno = REGNO (x); + t_nbits = GET_MODE_BITSIZE (GET_MODE (x)); + } else if (CONST_INT_P (x) && t_regno >= 0 - && IN_RANGE (INTVAL (x), 0, t_nbits - 1)) - { - int bpos = INTVAL (x); + && IN_RANGE (INTVAL (x), 0, t_nbits - 1)) + { + int bpos = INTVAL (x); - fprintf (file, "%s", reg_names[t_regno + bpos / 8]); - if (code == 'T') - fprintf (file, ",%d", bpos % 8); + fprintf (file, "%s", reg_names[t_regno + bpos / 8]); + if (code == 'T') + fprintf (file, ",%d", bpos % 8); - t_regno = -1; - } + t_regno = -1; + } else - fatal_insn ("operands to %T/%t must be reg + const_int:", x); + fatal_insn ("operands to %T/%t must be reg + const_int:", x); } else if (code == 'E' || code == 'F') { @@ -3197,101 +3197,101 @@ avr_print_operand (FILE *file, rtx x, int code) else if (REG_P (x)) { if (x == zero_reg_rtx) - fprintf (file, "__zero_reg__"); + fprintf (file, "__zero_reg__"); else if (code == 'r' && REGNO (x) < 32) - fprintf (file, "%d", (int) REGNO (x)); + fprintf (file, "%d", (int) REGNO (x)); else - fprintf (file, "%s", reg_names[REGNO (x) + abcd]); + fprintf (file, "%s", reg_names[REGNO (x) + abcd]); } else if (CONST_INT_P (x)) { HOST_WIDE_INT ival = INTVAL (x); if ('i' != code) - fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival + abcd); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival + abcd); else if (low_io_address_operand (x, VOIDmode) - || high_io_address_operand (x, VOIDmode)) - { - if (AVR_HAVE_RAMPZ && ival == avr_addr.rampz) - fprintf (file, "__RAMPZ__"); - else if (AVR_HAVE_RAMPY && ival == avr_addr.rampy) - fprintf (file, "__RAMPY__"); - else if (AVR_HAVE_RAMPX && ival == avr_addr.rampx) - fprintf (file, "__RAMPX__"); - else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd) - fprintf (file, "__RAMPD__"); - else if ((AVR_XMEGA || AVR_TINY) && ival == avr_addr.ccp) - fprintf (file, "__CCP__"); - else if (ival == avr_addr.sreg) fprintf (file, "__SREG__"); - else if (ival == avr_addr.sp_l) fprintf (file, "__SP_L__"); - else if (ival == avr_addr.sp_h) fprintf (file, "__SP_H__"); - else - { - fprintf (file, HOST_WIDE_INT_PRINT_HEX, - ival - avr_arch->sfr_offset); - } - } + || high_io_address_operand (x, VOIDmode)) + { + if (AVR_HAVE_RAMPZ && ival == avr_addr.rampz) + fprintf (file, "__RAMPZ__"); + else if (AVR_HAVE_RAMPY && ival == avr_addr.rampy) + fprintf (file, "__RAMPY__"); + else if (AVR_HAVE_RAMPX && ival == avr_addr.rampx) + fprintf (file, "__RAMPX__"); + else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd) + fprintf (file, "__RAMPD__"); + else if ((AVR_XMEGA || AVR_TINY) && ival == avr_addr.ccp) + fprintf (file, "__CCP__"); + else if (ival == avr_addr.sreg) fprintf (file, "__SREG__"); + else if (ival == avr_addr.sp_l) fprintf (file, "__SP_L__"); + else if (ival == avr_addr.sp_h) fprintf (file, "__SP_H__"); + else + { + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + ival - avr_arch->sfr_offset); + } + } else - fatal_insn ("bad address, not an I/O address:", x); + fatal_insn ("bad address, not an I/O address:", x); } else if (MEM_P (x)) { rtx addr = XEXP (x, 0); if (code == 'm') - { - if (!CONSTANT_P (addr)) - fatal_insn ("bad address, not a constant:", addr); - /* Assembler template with m-code is data - not progmem section */ - if (text_segment_operand (addr, VOIDmode)) - if (warning (0, "accessing data memory with" - " program memory address")) - { - output_addr_const (stderr, addr); - fprintf(stderr,"\n"); - } - output_addr_const (file, addr); - } + { + if (!CONSTANT_P (addr)) + fatal_insn ("bad address, not a constant:", addr); + /* Assembler template with m-code is data - not progmem section */ + if (text_segment_operand (addr, VOIDmode)) + if (warning (0, "accessing data memory with" + " program memory address")) + { + output_addr_const (stderr, addr); + fprintf(stderr,"\n"); + } + output_addr_const (file, addr); + } else if (code == 'i') - { - avr_print_operand (file, addr, 'i'); - } + { + avr_print_operand (file, addr, 'i'); + } else if (code == 'o') - { - if (GET_CODE (addr) != PLUS) - fatal_insn ("bad address, not (reg+disp):", addr); + { + if (GET_CODE (addr) != PLUS) + fatal_insn ("bad address, not (reg+disp):", addr); - avr_print_operand (file, XEXP (addr, 1), 0); - } + avr_print_operand (file, XEXP (addr, 1), 0); + } else if (code == 'b') - { - if (GET_CODE (addr) != PLUS) - fatal_insn ("bad address, not (reg+disp):", addr); + { + if (GET_CODE (addr) != PLUS) + fatal_insn ("bad address, not (reg+disp):", addr); - avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); - } + avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); + } else if (code == 'p' || code == 'r') - { - if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) - fatal_insn ("bad address, not post_inc or pre_dec:", addr); - - if (code == 'p') - /* X, Y, Z */ - avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); - else - avr_print_operand (file, XEXP (addr, 0), 0); /* r26, r28, r30 */ - } + { + if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) + fatal_insn ("bad address, not post_inc or pre_dec:", addr); + + if (code == 'p') + /* X, Y, Z */ + avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); + else + avr_print_operand (file, XEXP (addr, 0), 0); /* r26, r28, r30 */ + } else if (GET_CODE (addr) == PLUS) - { - avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); - if (REGNO (XEXP (addr, 0)) == REG_X) - fatal_insn ("internal compiler error. Bad address:" - ,addr); - fputc ('+', file); - avr_print_operand (file, XEXP (addr, 1), code); - } + { + avr_print_operand_address (file, VOIDmode, XEXP (addr, 0)); + if (REGNO (XEXP (addr, 0)) == REG_X) + fatal_insn ("internal compiler error. Bad address:" + ,addr); + fputc ('+', file); + avr_print_operand (file, XEXP (addr, 1), code); + } else - avr_print_operand_address (file, VOIDmode, addr); + avr_print_operand_address (file, VOIDmode, addr); } else if (code == 'i') { @@ -3305,12 +3305,12 @@ avr_print_operand (FILE *file, rtx x, int code) { /* Constant progmem address - like used in jmp or call */ if (text_segment_operand (x, VOIDmode) == 0) - if (warning (0, "accessing program memory" - " with data memory address")) - { - output_addr_const (stderr, x); - fprintf(stderr,"\n"); - } + if (warning (0, "accessing program memory" + " with data memory address")) + { + output_addr_const (stderr, x); + fprintf(stderr,"\n"); + } /* Use normal symbol for direct address no linker trampoline needed */ output_addr_const (file, x); } @@ -3318,15 +3318,15 @@ avr_print_operand (FILE *file, rtx x, int code) { HOST_WIDE_INT ival = INTVAL (avr_to_int_mode (x)); if (code != 0) - output_operand_lossage ("Unsupported code '%c' for fixed-point:", - code); + output_operand_lossage ("Unsupported code '%c' for fixed-point:", + code); fprintf (file, HOST_WIDE_INT_PRINT_DEC, ival); } else if (CONST_DOUBLE_P (x)) { long val; if (GET_MODE (x) != SFmode) - fatal_insn ("internal compiler error. Unknown mode:", x); + fatal_insn ("internal compiler error. Unknown mode:", x); REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), val); fprintf (file, "0x%lx", val); } @@ -3350,9 +3350,9 @@ avr_print_operand (FILE *file, rtx x, int code) static bool avr_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size, - unsigned int align ATTRIBUTE_UNUSED, - enum by_pieces_operation op, - bool speed_p) + unsigned int align ATTRIBUTE_UNUSED, + enum by_pieces_operation op, + bool speed_p) { if (op != MOVE_BY_PIECES || (speed_p && size > MOVE_MAX_PIECES)) @@ -3370,7 +3370,7 @@ int avr_jump_mode (rtx x, rtx_insn *insn) { int dest_addr = INSN_ADDRESSES (INSN_UID (GET_CODE (x) == LABEL_REF - ? XEXP (x, 0) : x)); + ? XEXP (x, 0) : x)); int cur_addr = INSN_ADDRESSES (INSN_UID (insn)); int jump_distance = cur_addr - dest_addr; @@ -3389,7 +3389,7 @@ avr_jump_mode (rtx x, rtx_insn *insn) LEN is a number returned by avr_jump_mode function. If REVERSE nonzero then condition code in X must be reversed. */ -const char* +const char * ret_cond_branch (rtx x, int len, int reverse) { RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x); @@ -3419,13 +3419,13 @@ ret_cond_branch (rtx x, int len, int reverse) "jmp %0")); case GTU: return (len == 1 ? ("breq .+2" CR_TAB - "brsh %0") : - len == 2 ? ("breq .+4" CR_TAB - "brlo .+2" CR_TAB - "rjmp %0") : - ("breq .+6" CR_TAB - "brlo .+4" CR_TAB - "jmp %0")); + "brsh %0") : + len == 2 ? ("breq .+4" CR_TAB + "brlo .+2" CR_TAB + "rjmp %0") : + ("breq .+6" CR_TAB + "brlo .+4" CR_TAB + "jmp %0")); case LE: if (cc_overflow_unusable) return (len == 1 ? ("breq %0" CR_TAB @@ -3447,12 +3447,12 @@ ret_cond_branch (rtx x, int len, int reverse) "jmp %0")); case LEU: return (len == 1 ? ("breq %0" CR_TAB - "brlo %0") : - len == 2 ? ("breq .+2" CR_TAB - "brsh .+2" CR_TAB + "brlo %0") : + len == 2 ? ("breq .+2" CR_TAB + "brsh .+2" CR_TAB "rjmp %0") : - ("breq .+2" CR_TAB - "brsh .+4" CR_TAB + ("breq .+2" CR_TAB + "brsh .+4" CR_TAB "jmp %0")); default: if (reverse) @@ -3470,19 +3470,19 @@ ret_cond_branch (rtx x, int len, int reverse) } } else - { - switch (len) - { - case 1: - return "br%j1 %0"; - case 2: - return ("br%k1 .+2" CR_TAB - "rjmp %0"); - default: - return ("br%k1 .+4" CR_TAB - "jmp %0"); - } - } + { + switch (len) + { + case 1: + return "br%j1 %0"; + case 2: + return ("br%k1 .+2" CR_TAB + "rjmp %0"); + default: + return ("br%k1 .+4" CR_TAB + "jmp %0"); + } + } } return ""; } @@ -3493,25 +3493,25 @@ ret_cond_branch (rtx x, int len, int reverse) void avr_final_prescan_insn (rtx_insn *insn, rtx *operand ATTRIBUTE_UNUSED, - int num_operands ATTRIBUTE_UNUSED) + int num_operands ATTRIBUTE_UNUSED) { if (avr_log.rtx_costs) { rtx set = single_set (insn); if (set) - fprintf (asm_out_file, "/* DEBUG: cost = %d. */\n", - set_src_cost (SET_SRC (set), GET_MODE (SET_DEST (set)), + fprintf (asm_out_file, "/* DEBUG: cost = %d. */\n", + set_src_cost (SET_SRC (set), GET_MODE (SET_DEST (set)), optimize_insn_for_speed_p ())); else - fprintf (asm_out_file, "/* DEBUG: pattern-cost = %d. */\n", - rtx_cost (PATTERN (insn), VOIDmode, INSN, 0, - optimize_insn_for_speed_p())); + fprintf (asm_out_file, "/* DEBUG: pattern-cost = %d. */\n", + rtx_cost (PATTERN (insn), VOIDmode, INSN, 0, + optimize_insn_for_speed_p())); } if (avr_log.insn_addresses) fprintf (asm_out_file, ";; ADDR = %d\n", - (int) INSN_ADDRESSES (INSN_UID (insn))); + (int) INSN_ADDRESSES (INSN_UID (insn))); } @@ -3521,14 +3521,14 @@ avr_final_prescan_insn (rtx_insn *insn, rtx *operand ATTRIBUTE_UNUSED, after the last epilogue. */ static void -avr_asm_final_postscan_insn (FILE *stream, rtx_insn *insn, rtx*, int) +avr_asm_final_postscan_insn (FILE *stream, rtx_insn *insn, rtx *, int) { if (cfun->machine->gasisr.yes && !next_real_insn (insn)) { app_disable(); fprintf (stream, "\t__gcc_isr %d,r%d\n", GASISR_Done, - cfun->machine->gasisr.regno); + cfun->machine->gasisr.regno); } } @@ -3550,7 +3550,7 @@ avr_function_arg_regno_p (int r) void avr_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname, - tree fndecl ATTRIBUTE_UNUSED) + tree fndecl ATTRIBUTE_UNUSED) { cum->nregs = AVR_TINY ? 6 : 18; cum->regno = FIRST_CUM_REG; @@ -3622,10 +3622,10 @@ avr_function_arg_advance (cumulative_args_t cum_v, && !call_used_or_fixed_reg_p (cum->regno)) { /* FIXME: We ship info on failing tail-call in struct machine_function. - This uses internals of calls.cc:expand_call() and the way args_so_far - is used. targetm.function_ok_for_sibcall() needs to be extended to - pass &args_so_far, too. At present, CUMULATIVE_ARGS is target - dependent so that such an extension is not wanted. */ + This uses internals of calls.cc:expand_call() and the way args_so_far + is used. targetm.function_ok_for_sibcall() needs to be extended to + pass &args_so_far, too. At present, CUMULATIVE_ARGS is target + dependent so that such an extension is not wanted. */ cfun->machine->sibcall_fails = 1; } @@ -3638,9 +3638,9 @@ avr_function_arg_advance (cumulative_args_t cum_v, && cum->nregs >= 0) { for (int regno = cum->regno; regno < cum->regno + bytes; regno++) - if (fixed_regs[regno]) - warning (0, "fixed register %s used to pass parameter to function", - reg_names[regno]); + if (fixed_regs[regno]) + warning (0, "fixed register %s used to pass parameter to function", + reg_names[regno]); } if (cum->nregs <= 0) @@ -3683,10 +3683,10 @@ avr_function_ok_for_sibcall (tree decl_callee, tree exp_callee) decl_callee = fntype_callee; while (FUNCTION_TYPE != TREE_CODE (decl_callee) - && METHOD_TYPE != TREE_CODE (decl_callee)) - { - decl_callee = TREE_TYPE (decl_callee); - } + && METHOD_TYPE != TREE_CODE (decl_callee)) + { + decl_callee = TREE_TYPE (decl_callee); + } } /* Ensure that caller and callee have compatible epilogues */ @@ -3716,8 +3716,8 @@ avr_load_libgcc_p (rtx op) int n_bytes = GET_MODE_SIZE (mode); return (n_bytes > 2 - && !AVR_HAVE_LPMX - && avr_mem_flash_p (op)); + && !AVR_HAVE_LPMX + && avr_mem_flash_p (op)); } /* Return true if a value of mode MODE is read by __xload_* function. */ @@ -3728,7 +3728,7 @@ avr_xload_libgcc_p (machine_mode mode) int n_bytes = GET_MODE_SIZE (mode); return (n_bytes > 1 - || avr_n_flash > 1); + || avr_n_flash > 1); } @@ -3747,38 +3747,38 @@ static rtx avr_find_unused_d_reg (rtx_insn *insn, rtx exclude) { bool isr_p = (avr_interrupt_function_p (current_function_decl) - || avr_signal_function_p (current_function_decl)); + || avr_signal_function_p (current_function_decl)); for (int regno = 16; regno < 32; regno++) { rtx reg = all_regs_rtx[regno]; if ((exclude - && reg_overlap_mentioned_p (exclude, reg)) - || fixed_regs[regno]) - { - continue; - } + && reg_overlap_mentioned_p (exclude, reg)) + || fixed_regs[regno]) + { + continue; + } /* Try non-live register */ if (!df_regs_ever_live_p (regno) - && (TREE_THIS_VOLATILE (current_function_decl) - || cfun->machine->is_OS_task - || cfun->machine->is_OS_main - || (!isr_p && call_used_or_fixed_reg_p (regno)))) - { - return reg; - } + && (TREE_THIS_VOLATILE (current_function_decl) + || cfun->machine->is_OS_task + || cfun->machine->is_OS_main + || (!isr_p && call_used_or_fixed_reg_p (regno)))) + { + return reg; + } /* Any live register can be used if it is unused after. - Prologue/epilogue will care for it as needed. */ + Prologue/epilogue will care for it as needed. */ if (df_regs_ever_live_p (regno) - && reg_unused_after (insn, reg)) - { - return reg; - } + && reg_unused_after (insn, reg)) + { + return reg; + } } return NULL_RTX; @@ -3788,7 +3788,7 @@ avr_find_unused_d_reg (rtx_insn *insn, rtx exclude) /* Helper function for the next function in the case where only restricted version of LPM instruction is available. */ -static const char* +static const char * avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) { rtx dest = xop[0]; @@ -3811,68 +3811,68 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) gcc_assert (REG_Z == REGNO (addr)); switch (n_bytes) - { - default: - gcc_unreachable(); - - case 1: - avr_asm_len ("%4lpm", xop, plen, 1); - - if (regno_dest != LPM_REGNO) - avr_asm_len ("mov %0,%3", xop, plen, 1); - - return ""; + { + default: + gcc_unreachable(); - case 2: - if (REGNO (dest) == REG_Z) - return avr_asm_len ("%4lpm" CR_TAB - "push %3" CR_TAB - "adiw %2,1" CR_TAB - "%4lpm" CR_TAB - "mov %B0,%3" CR_TAB - "pop %A0", xop, plen, 6); + case 1: + avr_asm_len ("%4lpm", xop, plen, 1); - avr_asm_len ("%4lpm" CR_TAB - "mov %A0,%3" CR_TAB - "adiw %2,1" CR_TAB - "%4lpm" CR_TAB - "mov %B0,%3", xop, plen, 5); + if (regno_dest != LPM_REGNO) + avr_asm_len ("mov %0,%3", xop, plen, 1); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,1", xop, plen, 1); + return ""; - break; /* 2 */ - } + case 2: + if (REGNO (dest) == REG_Z) + return avr_asm_len ("%4lpm" CR_TAB + "push %3" CR_TAB + "adiw %2,1" CR_TAB + "%4lpm" CR_TAB + "mov %B0,%3" CR_TAB + "pop %A0", xop, plen, 6); + + avr_asm_len ("%4lpm" CR_TAB + "mov %A0,%3" CR_TAB + "adiw %2,1" CR_TAB + "%4lpm" CR_TAB + "mov %B0,%3", xop, plen, 5); + + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,1", xop, plen, 1); + + break; /* 2 */ + } break; /* REG */ case POST_INC: gcc_assert (REG_Z == REGNO (XEXP (addr, 0)) - && n_bytes <= 4); + && n_bytes <= 4); if (regno_dest == LPM_REGNO) - avr_asm_len ("%4lpm" CR_TAB - "adiw %2,1", xop, plen, 2); + avr_asm_len ("%4lpm" CR_TAB + "adiw %2,1", xop, plen, 2); else - avr_asm_len ("%4lpm" CR_TAB - "mov %A0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %A0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); if (n_bytes >= 2) - avr_asm_len ("%4lpm" CR_TAB - "mov %B0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %B0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); if (n_bytes >= 3) - avr_asm_len ("%4lpm" CR_TAB - "mov %C0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %C0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); if (n_bytes >= 4) - avr_asm_len ("%4lpm" CR_TAB - "mov %D0,%3" CR_TAB - "adiw %2,1", xop, plen, 3); + avr_asm_len ("%4lpm" CR_TAB + "mov %D0,%3" CR_TAB + "adiw %2,1", xop, plen, 3); break; /* POST_INC */ @@ -3887,7 +3887,7 @@ avr_out_lpm_no_lpmx (rtx_insn *insn, rtx *xop, int *plen) If PLEN != 0 set *PLEN to the length in words of the instruction sequence. Return "". */ -const char* +const char * avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) { rtx xop[7]; @@ -3905,7 +3905,7 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) if (MEM_P (dest)) { warning (0, "writing to address space %qs not supported", - avr_addrspace[MEM_ADDR_SPACE (dest)].name); + avr_addrspace[MEM_ADDR_SPACE (dest)].name); return ""; } @@ -3933,28 +3933,28 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) xop[3] = avr_find_unused_d_reg (insn, lpm_addr_reg_rtx); if (xop[3] != NULL_RTX) - { - avr_asm_len ("ldi %3,%4" CR_TAB - "out %i6,%3", xop, plen, 2); - } + { + avr_asm_len ("ldi %3,%4" CR_TAB + "out %i6,%3", xop, plen, 2); + } else if (segment == 1) - { - avr_asm_len ("clr %5" CR_TAB - "inc %5" CR_TAB - "out %i6,%5", xop, plen, 3); - } + { + avr_asm_len ("clr %5" CR_TAB + "inc %5" CR_TAB + "out %i6,%5", xop, plen, 3); + } else - { - avr_asm_len ("mov %5,%2" CR_TAB - "ldi %2,%4" CR_TAB - "out %i6,%2" CR_TAB - "mov %2,%5", xop, plen, 4); - } + { + avr_asm_len ("mov %5,%2" CR_TAB + "ldi %2,%4" CR_TAB + "out %i6,%2" CR_TAB + "mov %2,%5", xop, plen, 4); + } xop[4] = xstring_e; if (!AVR_HAVE_ELPMX) - return avr_out_lpm_no_lpmx (insn, xop, plen); + return avr_out_lpm_no_lpmx (insn, xop, plen); } else if (!AVR_HAVE_LPMX) { @@ -3973,70 +3973,70 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) gcc_assert (REG_Z == REGNO (addr)); switch (n_bytes) - { - default: - gcc_unreachable(); + { + default: + gcc_unreachable(); - case 1: - avr_asm_len ("%4lpm %0,%a2", xop, plen, 1); - break; + case 1: + avr_asm_len ("%4lpm %0,%a2", xop, plen, 1); + break; - case 2: - if (REGNO (dest) == REG_Z) - avr_asm_len ("%4lpm %5,%a2+" CR_TAB - "%4lpm %B0,%a2" CR_TAB - "mov %A0,%5", xop, plen, 3); - else - { - avr_asm_len ("%4lpm %A0,%a2+" CR_TAB - "%4lpm %B0,%a2", xop, plen, 2); + case 2: + if (REGNO (dest) == REG_Z) + avr_asm_len ("%4lpm %5,%a2+" CR_TAB + "%4lpm %B0,%a2" CR_TAB + "mov %A0,%5", xop, plen, 3); + else + { + avr_asm_len ("%4lpm %A0,%a2+" CR_TAB + "%4lpm %B0,%a2", xop, plen, 2); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,1", xop, plen, 1); - } + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,1", xop, plen, 1); + } - break; /* 2 */ + break; /* 2 */ - case 3: + case 3: - avr_asm_len ("%4lpm %A0,%a2+" CR_TAB - "%4lpm %B0,%a2+" CR_TAB - "%4lpm %C0,%a2", xop, plen, 3); + avr_asm_len ("%4lpm %A0,%a2+" CR_TAB + "%4lpm %B0,%a2+" CR_TAB + "%4lpm %C0,%a2", xop, plen, 3); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,2", xop, plen, 1); + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,2", xop, plen, 1); - break; /* 3 */ + break; /* 3 */ - case 4: + case 4: - avr_asm_len ("%4lpm %A0,%a2+" CR_TAB - "%4lpm %B0,%a2+", xop, plen, 2); + avr_asm_len ("%4lpm %A0,%a2+" CR_TAB + "%4lpm %B0,%a2+", xop, plen, 2); - if (REGNO (dest) == REG_Z - 2) - avr_asm_len ("%4lpm %5,%a2+" CR_TAB - "%4lpm %C0,%a2" CR_TAB - "mov %D0,%5", xop, plen, 3); - else - { - avr_asm_len ("%4lpm %C0,%a2+" CR_TAB - "%4lpm %D0,%a2", xop, plen, 2); + if (REGNO (dest) == REG_Z - 2) + avr_asm_len ("%4lpm %5,%a2+" CR_TAB + "%4lpm %C0,%a2" CR_TAB + "mov %D0,%5", xop, plen, 3); + else + { + avr_asm_len ("%4lpm %C0,%a2+" CR_TAB + "%4lpm %D0,%a2", xop, plen, 2); - if (!reg_unused_after (insn, addr)) - avr_asm_len ("sbiw %2,3", xop, plen, 1); - } + if (!reg_unused_after (insn, addr)) + avr_asm_len ("sbiw %2,3", xop, plen, 1); + } - break; /* 4 */ - } /* n_bytes */ + break; /* 4 */ + } /* n_bytes */ break; /* REG */ case POST_INC: gcc_assert (REG_Z == REGNO (XEXP (addr, 0)) - && n_bytes <= 4); + && n_bytes <= 4); - avr_asm_len ("%4lpm %A0,%a2+", xop, plen, 1); + avr_asm_len ("%4lpm %A0,%a2+", xop, plen, 1); if (n_bytes >= 2) avr_asm_len ("%4lpm %B0,%a2+", xop, plen, 1); if (n_bytes >= 3) avr_asm_len ("%4lpm %C0,%a2+", xop, plen, 1); if (n_bytes >= 4) avr_asm_len ("%4lpm %D0,%a2+", xop, plen, 1); @@ -4059,7 +4059,7 @@ avr_out_lpm (rtx_insn *insn, rtx *op, int *plen) /* Worker function for xload_8 insn. */ -const char* +const char * avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) { rtx xop[4]; @@ -4072,7 +4072,7 @@ avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) avr_asm_len (AVR_HAVE_LPMX ? "lpm %3,%a2" : "lpm", xop, plen, -1); avr_asm_len ("sbrc %1,7" CR_TAB - "ld %3,%a2", xop, plen, 2); + "ld %3,%a2", xop, plen, 2); if (REGNO (xop[0]) != REGNO (xop[3])) avr_asm_len ("mov %0,%3", xop, plen, 1); @@ -4081,7 +4081,7 @@ avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) } -const char* +const char * output_movqi (rtx_insn *insn, rtx operands[], int *plen) { rtx dest = operands[0]; @@ -4098,21 +4098,21 @@ output_movqi (rtx_insn *insn, rtx operands[], int *plen) if (REG_P (dest)) { if (REG_P (src)) /* mov r,r */ - { - if (test_hard_reg_class (STACK_REG, dest)) - return avr_asm_len ("out %0,%1", operands, plen, -1); - else if (test_hard_reg_class (STACK_REG, src)) - return avr_asm_len ("in %0,%1", operands, plen, -1); - - return avr_asm_len ("mov %0,%1", operands, plen, -1); - } + { + if (test_hard_reg_class (STACK_REG, dest)) + return avr_asm_len ("out %0,%1", operands, plen, -1); + else if (test_hard_reg_class (STACK_REG, src)) + return avr_asm_len ("in %0,%1", operands, plen, -1); + + return avr_asm_len ("mov %0,%1", operands, plen, -1); + } else if (CONSTANT_P (src)) - { - output_reload_in_const (operands, NULL_RTX, plen, false); - return ""; - } + { + output_reload_in_const (operands, NULL_RTX, plen, false); + return ""; + } else if (MEM_P (src)) - return out_movqi_r_mr (insn, operands, plen); /* mov r,m */ + return out_movqi_r_mr (insn, operands, plen); /* mov r,m */ } else if (MEM_P (dest)) { @@ -4145,51 +4145,51 @@ output_movhi (rtx_insn *insn, rtx xop[], int *plen) if (REG_P (dest)) { if (REG_P (src)) /* mov r,r */ - { - if (test_hard_reg_class (STACK_REG, dest)) - { - if (AVR_HAVE_8BIT_SP) - return avr_asm_len ("out __SP_L__,%A1", xop, plen, -1); - - if (AVR_XMEGA) - return avr_asm_len ("out __SP_L__,%A1" CR_TAB - "out __SP_H__,%B1", xop, plen, -2); - - /* Use simple load of SP if no interrupts are used. */ - - return TARGET_NO_INTERRUPTS - ? avr_asm_len ("out __SP_H__,%B1" CR_TAB - "out __SP_L__,%A1", xop, plen, -2) - : avr_asm_len ("in __tmp_reg__,__SREG__" CR_TAB - "cli" CR_TAB - "out __SP_H__,%B1" CR_TAB - "out __SREG__,__tmp_reg__" CR_TAB - "out __SP_L__,%A1", xop, plen, -5); - } - else if (test_hard_reg_class (STACK_REG, src)) - { - return !AVR_HAVE_SPH - ? avr_asm_len ("in %A0,__SP_L__" CR_TAB - "clr %B0", xop, plen, -2) - - : avr_asm_len ("in %A0,__SP_L__" CR_TAB - "in %B0,__SP_H__", xop, plen, -2); - } - - return AVR_HAVE_MOVW - ? avr_asm_len ("movw %0,%1", xop, plen, -1) - - : avr_asm_len ("mov %A0,%A1" CR_TAB - "mov %B0,%B1", xop, plen, -2); - } /* REG_P (src) */ + { + if (test_hard_reg_class (STACK_REG, dest)) + { + if (AVR_HAVE_8BIT_SP) + return avr_asm_len ("out __SP_L__,%A1", xop, plen, -1); + + if (AVR_XMEGA) + return avr_asm_len ("out __SP_L__,%A1" CR_TAB + "out __SP_H__,%B1", xop, plen, -2); + + /* Use simple load of SP if no interrupts are used. */ + + return TARGET_NO_INTERRUPTS + ? avr_asm_len ("out __SP_H__,%B1" CR_TAB + "out __SP_L__,%A1", xop, plen, -2) + : avr_asm_len ("in __tmp_reg__,__SREG__" CR_TAB + "cli" CR_TAB + "out __SP_H__,%B1" CR_TAB + "out __SREG__,__tmp_reg__" CR_TAB + "out __SP_L__,%A1", xop, plen, -5); + } + else if (test_hard_reg_class (STACK_REG, src)) + { + return !AVR_HAVE_SPH + ? avr_asm_len ("in %A0,__SP_L__" CR_TAB + "clr %B0", xop, plen, -2) + + : avr_asm_len ("in %A0,__SP_L__" CR_TAB + "in %B0,__SP_H__", xop, plen, -2); + } + + return AVR_HAVE_MOVW + ? avr_asm_len ("movw %0,%1", xop, plen, -1) + + : avr_asm_len ("mov %A0,%A1" CR_TAB + "mov %B0,%B1", xop, plen, -2); + } /* REG_P (src) */ else if (CONSTANT_P (src)) - { - return output_reload_inhi (xop, NULL, plen); - } + { + return output_reload_inhi (xop, NULL, plen); + } else if (MEM_P (src)) - { - return out_movhi_r_mr (insn, xop, plen); /* mov r,m */ - } + { + return out_movhi_r_mr (insn, xop, plen); /* mov r,m */ + } } else if (MEM_P (dest)) { @@ -4209,7 +4209,7 @@ output_movhi (rtx_insn *insn, rtx xop[], int *plen) /* Same as out_movqi_r_mr, but TINY does not have ADIW or SBIW */ -static const char* +static const char * avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4217,7 +4217,7 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) rtx x = XEXP (src, 0); avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %0,%b1" , op, plen, -3); + "ld %0,%b1" , op, plen, -3); if (!reg_overlap_mentioned_p (dest, XEXP (x, 0)) && !reg_unused_after (insn, XEXP (x, 0))) @@ -4226,7 +4226,7 @@ avr_out_movqi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) return ""; } -static const char* +static const char * out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4237,8 +4237,8 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) { int n_words = AVR_TINY ? 1 : 2; return io_address_operand (x, QImode) - ? avr_asm_len ("in %0,%i1", op, plen, -1) - : avr_asm_len ("lds %0,%m1", op, plen, -n_words); + ? avr_asm_len ("in %0,%i1", op, plen, -1) + : avr_asm_len ("lds %0,%m1", op, plen, -n_words); } if (GET_CODE (x) == PLUS @@ -4250,40 +4250,40 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) int disp = INTVAL (XEXP (x, 1)); if (AVR_TINY) - return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen); + return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen); if (disp - GET_MODE_SIZE (GET_MODE (src)) >= 63) - { - if (REGNO (XEXP (x, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) - return avr_asm_len ("adiw r28,%o1-63" CR_TAB - "ldd %0,Y+63" CR_TAB - "sbiw r28,%o1-63", op, plen, -3); - - return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB - "sbci r29,hi8(-%o1)" CR_TAB - "ld %0,Y" CR_TAB - "subi r28,lo8(%o1)" CR_TAB - "sbci r29,hi8(%o1)", op, plen, -5); - } + { + if (REGNO (XEXP (x, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) + return avr_asm_len ("adiw r28,%o1-63" CR_TAB + "ldd %0,Y+63" CR_TAB + "sbiw r28,%o1-63", op, plen, -3); + + return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + "sbci r29,hi8(-%o1)" CR_TAB + "ld %0,Y" CR_TAB + "subi r28,lo8(%o1)" CR_TAB + "sbci r29,hi8(%o1)", op, plen, -5); + } else if (REGNO (XEXP (x, 0)) == REG_X) - { - /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude - it but I have this situation with extremal optimizing options. */ + { + /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude + it but I have this situation with extremal optimizing options. */ - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %0,X", op, plen, -2); + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %0,X", op, plen, -2); - if (!reg_overlap_mentioned_p (dest, XEXP (x, 0)) - && !reg_unused_after (insn, XEXP (x, 0))) - { - avr_asm_len ("sbiw r26,%o1", op, plen, 1); - } + if (!reg_overlap_mentioned_p (dest, XEXP (x, 0)) + && !reg_unused_after (insn, XEXP (x, 0))) + { + avr_asm_len ("sbiw r26,%o1", op, plen, 1); + } - return ""; - } + return ""; + } return avr_asm_len ("ldd %0,%1", op, plen, -1); } @@ -4294,7 +4294,7 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen) /* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ -static const char* +static const char * avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4304,13 +4304,13 @@ avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) int reg_dest = true_regnum (dest); int reg_base = true_regnum (base); - if (reg_dest == reg_base) /* R = (R) */ + if (reg_dest == reg_base) /* R = (R) */ return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB "ld %B0,%1" CR_TAB "mov %A0,__tmp_reg__", op, plen, -3); avr_asm_len ("ld %A0,%1+" CR_TAB - "ld %B0,%1", op, plen, -2); + "ld %B0,%1", op, plen, -2); if (!reg_unused_after (insn, base)) avr_asm_len (TINY_SBIW (%E1, %F1, 1), op, plen, 2); @@ -4321,7 +4321,7 @@ avr_out_movhi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) /* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ -static const char* +static const char * avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4334,18 +4334,18 @@ avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_base == reg_dest) { return avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld __tmp_reg__,%b1+" CR_TAB - "ld %B0,%b1" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -5); + "ld __tmp_reg__,%b1+" CR_TAB + "ld %B0,%b1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -5); } else { avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1", op, plen, -4); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1", op, plen, -4); if (!reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len (TINY_SBIW (%I1, %J1, %o1+1), op, plen, 2); + avr_asm_len (TINY_SBIW (%I1, %J1, %o1+1), op, plen, 2); return ""; } @@ -4354,7 +4354,7 @@ avr_out_movhi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) /* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ -static const char* +static const char * avr_out_movhi_r_mr_pre_dec_tiny (rtx_insn *insn, rtx op[], int *plen) { int mem_volatile_p = 0; @@ -4371,16 +4371,16 @@ avr_out_movhi_r_mr_pre_dec_tiny (rtx_insn *insn, rtx op[], int *plen) if (!mem_volatile_p) return avr_asm_len ("ld %B0,%1" CR_TAB - "ld %A0,%1", op, plen, -2); + "ld %A0,%1", op, plen, -2); return avr_asm_len (TINY_SBIW (%I1, %J1, 2) CR_TAB - "ld %A0,%p1+" CR_TAB - "ld %B0,%p1" CR_TAB - TINY_SBIW (%I1, %J1, 1), op, plen, -6); + "ld %A0,%p1+" CR_TAB + "ld %B0,%p1" CR_TAB + TINY_SBIW (%I1, %J1, 1), op, plen, -6); } -static const char* +static const char * out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -4395,22 +4395,22 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) if (reg_base > 0) { if (AVR_TINY) - return avr_out_movhi_r_mr_reg_no_disp_tiny (insn, op, plen); + return avr_out_movhi_r_mr_reg_no_disp_tiny (insn, op, plen); if (reg_dest == reg_base) /* R = (R) */ - return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB - "ld %B0,%1" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -3); + return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB + "ld %B0,%1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -3); if (reg_base != REG_X) - return avr_asm_len ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1", op, plen, -2); + return avr_asm_len ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1", op, plen, -2); avr_asm_len ("ld %A0,X+" CR_TAB - "ld %B0,X", op, plen, -2); + "ld %B0,X", op, plen, -2); if (!reg_unused_after (insn, base)) - avr_asm_len ("sbiw r26,1", op, plen, 1); + avr_asm_len ("sbiw r26,1", op, plen, 1); return ""; } @@ -4420,56 +4420,56 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) int reg_base = true_regnum (XEXP (base, 0)); if (AVR_TINY) - return avr_out_movhi_r_mr_reg_disp_tiny (insn, op, plen); + return avr_out_movhi_r_mr_reg_disp_tiny (insn, op, plen); if (disp > MAX_LD_OFFSET (GET_MODE (src))) - { - if (REGNO (XEXP (base, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - return disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)) - ? avr_asm_len ("adiw r28,%o1-62" CR_TAB - "ldd %A0,Y+62" CR_TAB - "ldd %B0,Y+63" CR_TAB - "sbiw r28,%o1-62", op, plen, -4) - - : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB - "sbci r29,hi8(-%o1)" CR_TAB - "ld %A0,Y" CR_TAB - "ldd %B0,Y+1" CR_TAB - "subi r28,lo8(%o1)" CR_TAB - "sbci r29,hi8(%o1)", op, plen, -6); - } + { + if (REGNO (XEXP (base, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + return disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)) + ? avr_asm_len ("adiw r28,%o1-62" CR_TAB + "ldd %A0,Y+62" CR_TAB + "ldd %B0,Y+63" CR_TAB + "sbiw r28,%o1-62", op, plen, -4) + + : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + "sbci r29,hi8(-%o1)" CR_TAB + "ld %A0,Y" CR_TAB + "ldd %B0,Y+1" CR_TAB + "subi r28,lo8(%o1)" CR_TAB + "sbci r29,hi8(%o1)", op, plen, -6); + } /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude - it but I have this situation with extremal - optimization options. */ + it but I have this situation with extremal + optimization options. */ if (reg_base == REG_X) - { - if (reg_base == reg_dest) - return avr_asm_len ("adiw r26,%o1" CR_TAB - "ld __tmp_reg__,X+" CR_TAB - "ld %B0,X" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -4); + { + if (reg_base == reg_dest) + return avr_asm_len ("adiw r26,%o1" CR_TAB + "ld __tmp_reg__,X+" CR_TAB + "ld %B0,X" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -4); - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %A0,X+" CR_TAB - "ld %B0,X", op, plen, -3); + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X", op, plen, -3); - if (!reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len ("sbiw r26,%o1+1", op, plen, 1); + if (!reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o1+1", op, plen, 1); - return ""; - } + return ""; + } return reg_base == reg_dest - ? avr_asm_len ("ldd __tmp_reg__,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "mov %A0,__tmp_reg__", op, plen, -3) + ? avr_asm_len ("ldd __tmp_reg__,%A1" CR_TAB + "ldd %B0,%B1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -3) - : avr_asm_len ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1", op, plen, -2); + : avr_asm_len ("ldd %A0,%A1" CR_TAB + "ldd %B0,%B1", op, plen, -2); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { @@ -4477,46 +4477,46 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen) return avr_out_movhi_r_mr_pre_dec_tiny (insn, op, plen); if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) - fatal_insn ("incorrect insn:", insn); + fatal_insn ("incorrect insn:", insn); if (!mem_volatile_p) - return avr_asm_len ("ld %B0,%1" CR_TAB - "ld %A0,%1", op, plen, -2); + return avr_asm_len ("ld %B0,%1" CR_TAB + "ld %A0,%1", op, plen, -2); return REGNO (XEXP (base, 0)) == REG_X - ? avr_asm_len ("sbiw r26,2" CR_TAB - "ld %A0,X+" CR_TAB - "ld %B0,X" CR_TAB - "sbiw r26,1", op, plen, -4) + ? avr_asm_len ("sbiw r26,2" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X" CR_TAB + "sbiw r26,1", op, plen, -4) - : avr_asm_len ("sbiw %r1,2" CR_TAB - "ld %A0,%p1" CR_TAB - "ldd %B0,%p1+1", op, plen, -3); + : avr_asm_len ("sbiw %r1,2" CR_TAB + "ld %A0,%p1" CR_TAB + "ldd %B0,%p1+1", op, plen, -3); } else if (GET_CODE (base) == POST_INC) /* (R++) */ { if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) - fatal_insn ("incorrect insn:", insn); + fatal_insn ("incorrect insn:", insn); return avr_asm_len ("ld %A0,%1" CR_TAB - "ld %B0,%1", op, plen, -2); + "ld %B0,%1", op, plen, -2); } else if (CONSTANT_ADDRESS_P (base)) { int n_words = AVR_TINY ? 2 : 4; return io_address_operand (base, HImode) - ? avr_asm_len ("in %A0,%i1" CR_TAB - "in %B0,%i1+1", op, plen, -2) + ? avr_asm_len ("in %A0,%i1" CR_TAB + "in %B0,%i1+1", op, plen, -2) - : avr_asm_len ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1", op, plen, -n_words); + : avr_asm_len ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1", op, plen, -n_words); } fatal_insn ("unknown move insn:",insn); return ""; } -static const char* +static const char * avr_out_movsi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4562,7 +4562,7 @@ avr_out_movsi_r_mr_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) } -static const char* +static const char * avr_out_movsi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4575,42 +4575,42 @@ avr_out_movsi_r_mr_reg_disp_tiny (rtx_insn *insn, rtx op[], int *l) { /* "ld r26,-X" is undefined */ return *l = 9, (TINY_ADIW (%I1, %J1, %o1+3) CR_TAB - "ld %D0,%b1" CR_TAB - "ld %C0,-%b1" CR_TAB - "ld __tmp_reg__,-%b1" CR_TAB - TINY_SBIW (%I1, %J1, 1) CR_TAB - "ld %A0,%b1" CR_TAB - "mov %B0,__tmp_reg__"); + "ld %D0,%b1" CR_TAB + "ld %C0,-%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%I1, %J1, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__"); } else if (reg_dest == reg_base - 2) { return *l = 7, (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld __tmp_reg__,%b1+" CR_TAB - "ld %D0,%b1" CR_TAB - "mov %C0,__tmp_reg__"); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld __tmp_reg__,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + "mov %C0,__tmp_reg__"); } else if (reg_unused_after (insn, XEXP (base, 0))) { return *l = 6, (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld %C0,%b1+" CR_TAB - "ld %D0,%b1"); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1"); } else { return *l = 8, (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld %C0,%b1+" CR_TAB - "ld %D0,%b1" CR_TAB - TINY_SBIW (%I1, %J1, %o1+3)); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + TINY_SBIW (%I1, %J1, %o1+3)); } } -static const char* +static const char * out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4626,11 +4626,11 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) if (reg_base > 0) { if (AVR_TINY) - return avr_out_movsi_r_mr_reg_no_disp_tiny (insn, op, l); + return avr_out_movsi_r_mr_reg_no_disp_tiny (insn, op, l); - if (reg_base == REG_X) /* (R26) */ - { - if (reg_dest == REG_X) + if (reg_base == REG_X) /* (R26) */ + { + if (reg_dest == REG_X) /* "ld r26,-X" is undefined */ return *l=7, ("adiw r26,3" CR_TAB "ld r29,X" CR_TAB @@ -4639,51 +4639,51 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) "sbiw r26,1" CR_TAB "ld r26,X" CR_TAB "mov r27,__tmp_reg__"); - else if (reg_dest == REG_X - 2) - return *l=5, ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld __tmp_reg__,X+" CR_TAB - "ld %D0,X" CR_TAB - "mov %C0,__tmp_reg__"); - else if (reg_unused_after (insn, base)) - return *l=4, ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X+" CR_TAB - "ld %D0,X"); - else - return *l=5, ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X+" CR_TAB - "ld %D0,X" CR_TAB - "sbiw r26,3"); - } + else if (reg_dest == REG_X - 2) + return *l=5, ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld __tmp_reg__,X+" CR_TAB + "ld %D0,X" CR_TAB + "mov %C0,__tmp_reg__"); + else if (reg_unused_after (insn, base)) + return *l=4, ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X+" CR_TAB + "ld %D0,X"); + else + return *l=5, ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X+" CR_TAB + "ld %D0,X" CR_TAB + "sbiw r26,3"); + } else - { - if (reg_dest == reg_base) - return *l=5, ("ldd %D0,%1+3" CR_TAB - "ldd %C0,%1+2" CR_TAB - "ldd __tmp_reg__,%1+1" CR_TAB - "ld %A0,%1" CR_TAB - "mov %B0,__tmp_reg__"); - else if (reg_base == reg_dest + 2) - return *l=5, ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1" CR_TAB - "ldd __tmp_reg__,%1+2" CR_TAB - "ldd %D0,%1+3" CR_TAB - "mov %C0,__tmp_reg__"); - else - return *l=4, ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1" CR_TAB - "ldd %C0,%1+2" CR_TAB - "ldd %D0,%1+3"); - } + { + if (reg_dest == reg_base) + return *l=5, ("ldd %D0,%1+3" CR_TAB + "ldd %C0,%1+2" CR_TAB + "ldd __tmp_reg__,%1+1" CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__"); + else if (reg_base == reg_dest + 2) + return *l=5, ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1" CR_TAB + "ldd __tmp_reg__,%1+2" CR_TAB + "ldd %D0,%1+3" CR_TAB + "mov %C0,__tmp_reg__"); + else + return *l=4, ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1" CR_TAB + "ldd %C0,%1+2" CR_TAB + "ldd %D0,%1+3"); + } } else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_movsi_r_mr_reg_disp_tiny (insn, op, l); + return avr_out_movsi_r_mr_reg_disp_tiny (insn, op, l); if (disp > MAX_LD_OFFSET (GET_MODE (src))) { @@ -4741,21 +4741,21 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) "sbiw r26,%o1+3"); } if (reg_dest == reg_base) - return *l=5, ("ldd %D0,%D1" CR_TAB - "ldd %C0,%C1" CR_TAB - "ldd __tmp_reg__,%B1" CR_TAB - "ldd %A0,%A1" CR_TAB - "mov %B0,__tmp_reg__"); + return *l=5, ("ldd %D0,%D1" CR_TAB + "ldd %C0,%C1" CR_TAB + "ldd __tmp_reg__,%B1" CR_TAB + "ldd %A0,%A1" CR_TAB + "mov %B0,__tmp_reg__"); else if (reg_dest == reg_base - 2) - return *l=5, ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "ldd __tmp_reg__,%C1" CR_TAB - "ldd %D0,%D1" CR_TAB - "mov %C0,__tmp_reg__"); + return *l=5, ("ldd %A0,%A1" CR_TAB + "ldd %B0,%B1" CR_TAB + "ldd __tmp_reg__,%C1" CR_TAB + "ldd %D0,%D1" CR_TAB + "mov %C0,__tmp_reg__"); return *l=4, ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "ldd %C0,%C1" CR_TAB - "ldd %D0,%D1"); + "ldd %B0,%B1" CR_TAB + "ldd %C0,%C1" CR_TAB + "ldd %D0,%D1"); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return *l=4, ("ld %D0,%1" CR_TAB @@ -4770,28 +4770,28 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l) else if (CONSTANT_ADDRESS_P (base)) { if (io_address_operand (base, SImode)) - { - *l = 4; - return ("in %A0,%i1" CR_TAB - "in %B0,%i1+1" CR_TAB - "in %C0,%i1+2" CR_TAB - "in %D0,%i1+3"); - } + { + *l = 4; + return ("in %A0,%i1" CR_TAB + "in %B0,%i1+1" CR_TAB + "in %C0,%i1+2" CR_TAB + "in %D0,%i1+3"); + } else - { - *l = AVR_TINY ? 4 : 8; - return ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1" CR_TAB - "lds %C0,%m1+2" CR_TAB - "lds %D0,%m1+3"); - } + { + *l = AVR_TINY ? 4 : 8; + return ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1" CR_TAB + "lds %C0,%m1+2" CR_TAB + "lds %D0,%m1+3"); + } } fatal_insn ("unknown move insn:",insn); return ""; } -static const char* +static const char * avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4804,35 +4804,35 @@ avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) { /* "ld r26,-X" is undefined */ if (reg_unused_after (insn, base)) - { - return *l = 7, ("mov __tmp_reg__, %B1" CR_TAB + { + return *l = 7, ("mov __tmp_reg__, %B1" CR_TAB "st %0,%A1" CR_TAB TINY_ADIW (%E0, %F0, 1) CR_TAB "st %0+,__tmp_reg__" CR_TAB "st %0+,%C1" CR_TAB "st %0+,%D1"); - } + } else - { - return *l = 9, ("mov __tmp_reg__, %B1" CR_TAB + { + return *l = 9, ("mov __tmp_reg__, %B1" CR_TAB "st %0,%A1" CR_TAB TINY_ADIW (%E0, %F0, 1) CR_TAB "st %0+,__tmp_reg__" CR_TAB "st %0+,%C1" CR_TAB "st %0+,%D1" CR_TAB TINY_SBIW (%E0, %F0, 3)); - } + } } else if (reg_base == reg_src + 2) { if (reg_unused_after (insn, base)) return *l = 7, ("mov __zero_reg__,%C1" CR_TAB - "mov __tmp_reg__,%D1" CR_TAB - "st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,__zero_reg__" CR_TAB - "st %0,__tmp_reg__" CR_TAB - "clr __zero_reg__"); + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__"); else return *l = 9, ("mov __zero_reg__,%C1" CR_TAB "mov __tmp_reg__,%D1" CR_TAB @@ -4851,7 +4851,7 @@ avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *l) TINY_SBIW (%E0, %F0, 3)); } -static const char* +static const char * avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) { rtx dest = op[0]; @@ -4864,38 +4864,38 @@ avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) { *l = 11; return ("mov __tmp_reg__,%A2" CR_TAB - "mov __zero_reg__,%B2" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0+,__zero_reg__" CR_TAB - "st %b0+,%C2" CR_TAB - "st %b0,%D2" CR_TAB - "clr __zero_reg__" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + "mov __zero_reg__,%B2" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0+,%C2" CR_TAB + "st %b0,%D2" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); } else if (reg_src == reg_base - 2) { *l = 11; return ("mov __tmp_reg__,%C2" CR_TAB - "mov __zero_reg__,%D2" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A0" CR_TAB - "st %b0+,%B0" CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0,__zero_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + "mov __zero_reg__,%D2" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A0" CR_TAB + "st %b0+,%B0" CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0,__zero_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); } *l = 8; return (TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A1" CR_TAB - "st %b0+,%B1" CR_TAB - "st %b0+,%C1" CR_TAB - "st %b0,%D1" CR_TAB - TINY_SBIW (%I0, %J0, %o0+3)); + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0+,%C1" CR_TAB + "st %b0,%D1" CR_TAB + TINY_SBIW (%I0, %J0, %o0+3)); } -static const char* +static const char * out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) { rtx dest = op[0]; @@ -4911,76 +4911,76 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) if (CONSTANT_ADDRESS_P (base)) { if (io_address_operand (base, SImode)) - { - return *l=4,("out %i0, %A1" CR_TAB - "out %i0+1,%B1" CR_TAB - "out %i0+2,%C1" CR_TAB - "out %i0+3,%D1"); - } + { + return *l=4,("out %i0, %A1" CR_TAB + "out %i0+1,%B1" CR_TAB + "out %i0+2,%C1" CR_TAB + "out %i0+3,%D1"); + } else - { - *l = AVR_TINY ? 4 : 8; - return ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1" CR_TAB - "sts %m0+2,%C1" CR_TAB - "sts %m0+3,%D1"); - } + { + *l = AVR_TINY ? 4 : 8; + return ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1" CR_TAB + "sts %m0+2,%C1" CR_TAB + "sts %m0+3,%D1"); + } } - if (reg_base > 0) /* (r) */ + if (reg_base > 0) /* (r) */ { if (AVR_TINY) - return avr_out_movsi_mr_r_reg_no_disp_tiny (insn, op, l); + return avr_out_movsi_mr_r_reg_no_disp_tiny (insn, op, l); - if (reg_base == REG_X) /* (R26) */ - { - if (reg_src == REG_X) - { + if (reg_base == REG_X) /* (R26) */ + { + if (reg_src == REG_X) + { /* "st X+,r26" is undefined */ - if (reg_unused_after (insn, base)) + if (reg_unused_after (insn, base)) return *l=6, ("mov __tmp_reg__,r27" CR_TAB "st X,r26" CR_TAB "adiw r26,1" CR_TAB "st X+,__tmp_reg__" CR_TAB "st X+,r28" CR_TAB "st X,r29"); - else - return *l=7, ("mov __tmp_reg__,r27" CR_TAB + else + return *l=7, ("mov __tmp_reg__,r27" CR_TAB "st X,r26" CR_TAB "adiw r26,1" CR_TAB "st X+,__tmp_reg__" CR_TAB "st X+,r28" CR_TAB "st X,r29" CR_TAB "sbiw r26,3"); - } - else if (reg_base == reg_src + 2) - { - if (reg_unused_after (insn, base)) - return *l=7, ("mov __zero_reg__,%C1" CR_TAB - "mov __tmp_reg__,%D1" CR_TAB - "st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,__zero_reg__" CR_TAB - "st %0,__tmp_reg__" CR_TAB - "clr __zero_reg__"); - else - return *l=8, ("mov __zero_reg__,%C1" CR_TAB - "mov __tmp_reg__,%D1" CR_TAB - "st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,__zero_reg__" CR_TAB - "st %0,__tmp_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - "sbiw r26,3"); - } - return *l=5, ("st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0+,%C1" CR_TAB - "st %0,%D1" CR_TAB - "sbiw r26,3"); - } + } + else if (reg_base == reg_src + 2) + { + if (reg_unused_after (insn, base)) + return *l=7, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__"); + else + return *l=8, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + "sbiw r26,3"); + } + return *l=5, ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,%C1" CR_TAB + "st %0,%D1" CR_TAB + "sbiw r26,3"); + } else - return *l=4, ("st %0,%A1" CR_TAB + return *l=4, ("st %0,%A1" CR_TAB "std %0+1,%B1" CR_TAB "std %0+2,%C1" CR_TAB "std %0+3,%D1"); @@ -4990,7 +4990,7 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l) int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_movsi_mr_r_reg_disp_tiny (op, l); + return avr_out_movsi_mr_r_reg_disp_tiny (op, l); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) @@ -5125,8 +5125,8 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) } else if (CONSTANT_P (src)) { - return output_reload_insisf (operands, NULL_RTX, real_l); - } + return output_reload_insisf (operands, NULL_RTX, real_l); + } else if (MEM_P (src)) return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */ } @@ -5135,7 +5135,7 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) const char *templ; if (src == CONST0_RTX (GET_MODE (dest))) - operands[1] = zero_reg_rtx; + operands[1] = zero_reg_rtx; templ = out_movsi_mr_r (insn, operands, real_l); @@ -5152,7 +5152,7 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l) /* Handle loads of 24-bit types from memory to register. */ -static const char* +static const char * avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5164,11 +5164,11 @@ avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_base == reg_dest) { return avr_asm_len (TINY_ADIW (%E1, %F1, 2) CR_TAB - "ld %C0,%1" CR_TAB - "ld __tmp_reg__,-%1" CR_TAB - TINY_SBIW (%E1, %F1, 1) CR_TAB - "ld %A0,%1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -8); + "ld %C0,%1" CR_TAB + "ld __tmp_reg__,-%1" CR_TAB + TINY_SBIW (%E1, %F1, 1) CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); } else { @@ -5177,15 +5177,15 @@ avr_out_load_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) "ld %C0,%1", op, plen, -3); if (reg_dest != reg_base - 2 - && !reg_unused_after (insn, base)) - { - avr_asm_len (TINY_SBIW (%E1, %F1, 2), op, plen, 2); - } + && !reg_unused_after (insn, base)) + { + avr_asm_len (TINY_SBIW (%E1, %F1, 2), op, plen, 2); + } return ""; } } -static const char* +static const char * avr_out_load_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5198,28 +5198,28 @@ avr_out_load_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_base == reg_dest) { return avr_asm_len (TINY_ADIW (%I1, %J1, %o1+2) CR_TAB - "ld %C0,%b1" CR_TAB - "ld __tmp_reg__,-%b1" CR_TAB - TINY_SBIW (%I1, %J1, 1) CR_TAB - "ld %A0,%b1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -8); + "ld %C0,%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%I1, %J1, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); } else { avr_asm_len (TINY_ADIW (%I1, %J1, %o1) CR_TAB - "ld %A0,%b1+" CR_TAB - "ld %B0,%b1+" CR_TAB - "ld %C0,%b1", op, plen, -5); + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1", op, plen, -5); if (reg_dest != reg_base - 2 - && !reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len (TINY_SBIW (%I1, %J1, %o1+2), op, plen, 2); + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len (TINY_SBIW (%I1, %J1, %o1+2), op, plen, 2); return ""; } } -static const char* +static const char * avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5231,126 +5231,126 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) if (reg_base > 0) { if (AVR_TINY) - return avr_out_load_psi_reg_no_disp_tiny (insn, op, plen); - - if (reg_base == REG_X) /* (R26) */ - { - if (reg_dest == REG_X) - /* "ld r26,-X" is undefined */ - return avr_asm_len ("adiw r26,2" CR_TAB - "ld r28,X" CR_TAB - "ld __tmp_reg__,-X" CR_TAB - "sbiw r26,1" CR_TAB - "ld r26,X" CR_TAB - "mov r27,__tmp_reg__", op, plen, -6); - else - { - avr_asm_len ("ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X", op, plen, -3); - - if (reg_dest != REG_X - 2 - && !reg_unused_after (insn, base)) - { - avr_asm_len ("sbiw r26,2", op, plen, 1); - } - - return ""; - } - } + return avr_out_load_psi_reg_no_disp_tiny (insn, op, plen); + + if (reg_base == REG_X) /* (R26) */ + { + if (reg_dest == REG_X) + /* "ld r26,-X" is undefined */ + return avr_asm_len ("adiw r26,2" CR_TAB + "ld r28,X" CR_TAB + "ld __tmp_reg__,-X" CR_TAB + "sbiw r26,1" CR_TAB + "ld r26,X" CR_TAB + "mov r27,__tmp_reg__", op, plen, -6); + else + { + avr_asm_len ("ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X", op, plen, -3); + + if (reg_dest != REG_X - 2 + && !reg_unused_after (insn, base)) + { + avr_asm_len ("sbiw r26,2", op, plen, 1); + } + + return ""; + } + } else /* reg_base != REG_X */ - { - if (reg_dest == reg_base) - return avr_asm_len ("ldd %C0,%1+2" CR_TAB - "ldd __tmp_reg__,%1+1" CR_TAB - "ld %A0,%1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -4); - else - return avr_asm_len ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1" CR_TAB - "ldd %C0,%1+2", op, plen, -3); - } + { + if (reg_dest == reg_base) + return avr_asm_len ("ldd %C0,%1+2" CR_TAB + "ldd __tmp_reg__,%1+1" CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -4); + else + return avr_asm_len ("ld %A0,%1" CR_TAB + "ldd %B0,%1+1" CR_TAB + "ldd %C0,%1+2", op, plen, -3); + } } else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_load_psi_reg_disp_tiny (insn, op, plen); + return avr_out_load_psi_reg_disp_tiny (insn, op, plen); if (disp > MAX_LD_OFFSET (GET_MODE (src))) - { - if (REGNO (XEXP (base, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) - return avr_asm_len ("adiw r28,%o1-61" CR_TAB - "ldd %A0,Y+61" CR_TAB - "ldd %B0,Y+62" CR_TAB - "ldd %C0,Y+63" CR_TAB - "sbiw r28,%o1-61", op, plen, -5); - - return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB - "sbci r29,hi8(-%o1)" CR_TAB - "ld %A0,Y" CR_TAB - "ldd %B0,Y+1" CR_TAB - "ldd %C0,Y+2" CR_TAB - "subi r28,lo8(%o1)" CR_TAB - "sbci r29,hi8(%o1)", op, plen, -7); - } + { + if (REGNO (XEXP (base, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src))) + return avr_asm_len ("adiw r28,%o1-61" CR_TAB + "ldd %A0,Y+61" CR_TAB + "ldd %B0,Y+62" CR_TAB + "ldd %C0,Y+63" CR_TAB + "sbiw r28,%o1-61", op, plen, -5); + + return avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + "sbci r29,hi8(-%o1)" CR_TAB + "ld %A0,Y" CR_TAB + "ldd %B0,Y+1" CR_TAB + "ldd %C0,Y+2" CR_TAB + "subi r28,lo8(%o1)" CR_TAB + "sbci r29,hi8(%o1)", op, plen, -7); + } reg_base = true_regnum (XEXP (base, 0)); if (reg_base == REG_X) - { - /* R = (X + d) */ - if (reg_dest == REG_X) - { - /* "ld r26,-X" is undefined */ - return avr_asm_len ("adiw r26,%o1+2" CR_TAB - "ld r28,X" CR_TAB - "ld __tmp_reg__,-X" CR_TAB - "sbiw r26,1" CR_TAB - "ld r26,X" CR_TAB - "mov r27,__tmp_reg__", op, plen, -6); - } - - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %A0,X+" CR_TAB - "ld %B0,X+" CR_TAB - "ld %C0,X", op, plen, -4); - - if (reg_dest != REG_W - && !reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len ("sbiw r26,%o1+2", op, plen, 1); - - return ""; - } + { + /* R = (X + d) */ + if (reg_dest == REG_X) + { + /* "ld r26,-X" is undefined */ + return avr_asm_len ("adiw r26,%o1+2" CR_TAB + "ld r28,X" CR_TAB + "ld __tmp_reg__,-X" CR_TAB + "sbiw r26,1" CR_TAB + "ld r26,X" CR_TAB + "mov r27,__tmp_reg__", op, plen, -6); + } + + avr_asm_len ("adiw r26,%o1" CR_TAB + "ld %A0,X+" CR_TAB + "ld %B0,X+" CR_TAB + "ld %C0,X", op, plen, -4); + + if (reg_dest != REG_W + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o1+2", op, plen, 1); + + return ""; + } if (reg_dest == reg_base) - return avr_asm_len ("ldd %C0,%C1" CR_TAB - "ldd __tmp_reg__,%B1" CR_TAB - "ldd %A0,%A1" CR_TAB - "mov %B0,__tmp_reg__", op, plen, -4); + return avr_asm_len ("ldd %C0,%C1" CR_TAB + "ldd __tmp_reg__,%B1" CR_TAB + "ldd %A0,%A1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -4); return avr_asm_len ("ldd %A0,%A1" CR_TAB - "ldd %B0,%B1" CR_TAB - "ldd %C0,%C1", op, plen, -3); + "ldd %B0,%B1" CR_TAB + "ldd %C0,%C1", op, plen, -3); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return avr_asm_len ("ld %C0,%1" CR_TAB - "ld %B0,%1" CR_TAB - "ld %A0,%1", op, plen, -3); + "ld %B0,%1" CR_TAB + "ld %A0,%1", op, plen, -3); else if (GET_CODE (base) == POST_INC) /* (R++) */ return avr_asm_len ("ld %A0,%1" CR_TAB - "ld %B0,%1" CR_TAB - "ld %C0,%1", op, plen, -3); + "ld %B0,%1" CR_TAB + "ld %C0,%1", op, plen, -3); else if (CONSTANT_ADDRESS_P (base)) { int n_words = AVR_TINY ? 3 : 6; - return avr_asm_len ("lds %A0,%m1" CR_TAB - "lds %B0,%m1+1" CR_TAB - "lds %C0,%m1+2", op, plen , -n_words); + return avr_asm_len ("lds %A0,%m1" CR_TAB + "lds %B0,%m1+1" CR_TAB + "lds %C0,%m1+2", op, plen , -n_words); } fatal_insn ("unknown move insn:",insn); @@ -5358,7 +5358,7 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen) } -static const char* +static const char * avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5370,25 +5370,25 @@ avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_base == reg_src) { avr_asm_len ("st %0,%A1" CR_TAB - "mov __tmp_reg__,%B1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB /* st X+, r27 is undefined */ - "st %0+,__tmp_reg__" CR_TAB - "st %0,%C1", op, plen, -6); + "mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB /* st X+, r27 is undefined */ + "st %0+,__tmp_reg__" CR_TAB + "st %0,%C1", op, plen, -6); } else if (reg_src == reg_base - 2) { avr_asm_len ("st %0,%A1" CR_TAB - "mov __tmp_reg__,%C1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0+,%B1" CR_TAB - "st %0,__tmp_reg__", op, plen, 6); + "mov __tmp_reg__,%C1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0+,%B1" CR_TAB + "st %0,__tmp_reg__", op, plen, 6); } else { avr_asm_len ("st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0,%C1", op, plen, -3); + "st %0+,%B1" CR_TAB + "st %0,%C1", op, plen, -3); } if (!reg_unused_after (insn, base)) @@ -5397,7 +5397,7 @@ avr_out_store_psi_reg_no_disp_tiny (rtx_insn *insn, rtx *op, int *plen) return ""; } -static const char* +static const char * avr_out_store_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5408,23 +5408,23 @@ avr_out_store_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) if (reg_src == reg_base) avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB - "mov __zero_reg__,%B1" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,__tmp_reg__" CR_TAB - "st %b0+,__zero_reg__" CR_TAB - "st %b0,%C1" CR_TAB - "clr __zero_reg__", op, plen, -8); + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0,%C1" CR_TAB + "clr __zero_reg__", op, plen, -8); else if (reg_src == reg_base - 2) avr_asm_len ("mov __tmp_reg__,%C1" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A1" CR_TAB - "st %b0+,%B1" CR_TAB - "st %b0,__tmp_reg__", op, plen, -6); + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,__tmp_reg__", op, plen, -6); else avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0+,%A1" CR_TAB - "st %b0+,%B1" CR_TAB - "st %b0,%C1", op, plen, -5); + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,%C1", op, plen, -5); if (!reg_unused_after (insn, XEXP (base, 0))) avr_asm_len (TINY_SBIW (%I0, %J0, %o0+2), op, plen, 2); @@ -5434,7 +5434,7 @@ avr_out_store_psi_reg_disp_tiny (rtx_insn *insn, rtx *op, int *plen) /* Handle store of 24-bit type from register or zero to memory. */ -static const char* +static const char * avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -5446,90 +5446,90 @@ avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen) { int n_words = AVR_TINY ? 3 : 6; return avr_asm_len ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1" CR_TAB - "sts %m0+2,%C1", op, plen, -n_words); + "sts %m0+1,%B1" CR_TAB + "sts %m0+2,%C1", op, plen, -n_words); } - if (reg_base > 0) /* (r) */ + if (reg_base > 0) /* (r) */ { if (AVR_TINY) - return avr_out_store_psi_reg_no_disp_tiny (insn, op, plen); + return avr_out_store_psi_reg_no_disp_tiny (insn, op, plen); - if (reg_base == REG_X) /* (R26) */ - { - gcc_assert (!reg_overlap_mentioned_p (base, src)); + if (reg_base == REG_X) /* (R26) */ + { + gcc_assert (!reg_overlap_mentioned_p (base, src)); - avr_asm_len ("st %0+,%A1" CR_TAB - "st %0+,%B1" CR_TAB - "st %0,%C1", op, plen, -3); + avr_asm_len ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0,%C1", op, plen, -3); - if (!reg_unused_after (insn, base)) - avr_asm_len ("sbiw r26,2", op, plen, 1); + if (!reg_unused_after (insn, base)) + avr_asm_len ("sbiw r26,2", op, plen, 1); - return ""; - } + return ""; + } else - return avr_asm_len ("st %0,%A1" CR_TAB - "std %0+1,%B1" CR_TAB - "std %0+2,%C1", op, plen, -3); + return avr_asm_len ("st %0,%A1" CR_TAB + "std %0+1,%B1" CR_TAB + "std %0+2,%C1", op, plen, -3); } else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_store_psi_reg_disp_tiny (insn, op, plen); + return avr_out_store_psi_reg_disp_tiny (insn, op, plen); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) - { - if (reg_base != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) - return avr_asm_len ("adiw r28,%o0-61" CR_TAB - "std Y+61,%A1" CR_TAB - "std Y+62,%B1" CR_TAB - "std Y+63,%C1" CR_TAB - "sbiw r28,%o0-61", op, plen, -5); - - return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "st Y,%A1" CR_TAB - "std Y+1,%B1" CR_TAB - "std Y+2,%C1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -7); - } + { + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) + return avr_asm_len ("adiw r28,%o0-61" CR_TAB + "std Y+61,%A1" CR_TAB + "std Y+62,%B1" CR_TAB + "std Y+63,%C1" CR_TAB + "sbiw r28,%o0-61", op, plen, -5); + + return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "st Y,%A1" CR_TAB + "std Y+1,%B1" CR_TAB + "std Y+2,%C1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -7); + } if (reg_base == REG_X) - { - /* (X + d) = R */ - gcc_assert (!reg_overlap_mentioned_p (XEXP (base, 0), src)); + { + /* (X + d) = R */ + gcc_assert (!reg_overlap_mentioned_p (XEXP (base, 0), src)); - avr_asm_len ("adiw r26,%o0" CR_TAB - "st X+,%A1" CR_TAB - "st X+,%B1" CR_TAB - "st X,%C1", op, plen, -4); + avr_asm_len ("adiw r26,%o0" CR_TAB + "st X+,%A1" CR_TAB + "st X+,%B1" CR_TAB + "st X,%C1", op, plen, -4); - if (!reg_unused_after (insn, XEXP (base, 0))) - avr_asm_len ("sbiw r26,%o0+2", op, plen, 1); + if (!reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len ("sbiw r26,%o0+2", op, plen, 1); - return ""; - } + return ""; + } return avr_asm_len ("std %A0,%A1" CR_TAB - "std %B0,%B1" CR_TAB - "std %C0,%C1", op, plen, -3); + "std %B0,%B1" CR_TAB + "std %C0,%C1", op, plen, -3); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ return avr_asm_len ("st %0,%C1" CR_TAB - "st %0,%B1" CR_TAB - "st %0,%A1", op, plen, -3); + "st %0,%B1" CR_TAB + "st %0,%A1", op, plen, -3); else if (GET_CODE (base) == POST_INC) /* (R++) */ return avr_asm_len ("st %0,%A1" CR_TAB - "st %0,%B1" CR_TAB - "st %0,%C1", op, plen, -3); + "st %0,%B1" CR_TAB + "st %0,%C1", op, plen, -3); fatal_insn ("unknown move insn:",insn); return ""; @@ -5553,34 +5553,34 @@ avr_out_movpsi (rtx_insn *insn, rtx *op, int *plen) if (register_operand (dest, VOIDmode)) { if (register_operand (src, VOIDmode)) /* mov r,r */ - { - if (true_regnum (dest) > true_regnum (src)) - { - avr_asm_len ("mov %C0,%C1", op, plen, -1); - - if (AVR_HAVE_MOVW) - return avr_asm_len ("movw %A0,%A1", op, plen, 1); - else - return avr_asm_len ("mov %B0,%B1" CR_TAB - "mov %A0,%A1", op, plen, 2); - } - else - { - if (AVR_HAVE_MOVW) - avr_asm_len ("movw %A0,%A1", op, plen, -1); - else - avr_asm_len ("mov %A0,%A1" CR_TAB - "mov %B0,%B1", op, plen, -2); - - return avr_asm_len ("mov %C0,%C1", op, plen, 1); - } - } + { + if (true_regnum (dest) > true_regnum (src)) + { + avr_asm_len ("mov %C0,%C1", op, plen, -1); + + if (AVR_HAVE_MOVW) + return avr_asm_len ("movw %A0,%A1", op, plen, 1); + else + return avr_asm_len ("mov %B0,%B1" CR_TAB + "mov %A0,%A1", op, plen, 2); + } + else + { + if (AVR_HAVE_MOVW) + avr_asm_len ("movw %A0,%A1", op, plen, -1); + else + avr_asm_len ("mov %A0,%A1" CR_TAB + "mov %B0,%B1", op, plen, -2); + + return avr_asm_len ("mov %C0,%C1", op, plen, 1); + } + } else if (CONSTANT_P (src)) - { - return avr_out_reload_inpsi (op, NULL_RTX, plen); - } + { + return avr_out_reload_inpsi (op, NULL_RTX, plen); + } else if (MEM_P (src)) - return avr_out_load_psi (insn, op, plen); /* mov r,m */ + return avr_out_load_psi (insn, op, plen); /* mov r,m */ } else if (MEM_P (dest)) { @@ -5596,7 +5596,7 @@ avr_out_movpsi (rtx_insn *insn, rtx *op, int *plen) return ""; } -static const char* +static const char * avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5606,13 +5606,13 @@ avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_overlap_mentioned_p (src, XEXP (x, 0))) { avr_asm_len ("mov __tmp_reg__,%1" CR_TAB - TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0,__tmp_reg__", op, plen, -4); + TINY_ADIW (%I0, %J0, %o0) CR_TAB + "st %b0,__tmp_reg__", op, plen, -4); } else { avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB - "st %b0,%1", op, plen, -3); + "st %b0,%1", op, plen, -3); } if (!reg_unused_after (insn, XEXP (x, 0))) @@ -5621,7 +5621,7 @@ avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) return ""; } -static const char* +static const char * out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5632,55 +5632,55 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) { int n_words = AVR_TINY ? 1 : 2; return io_address_operand (x, QImode) - ? avr_asm_len ("out %i0,%1", op, plen, -1) - : avr_asm_len ("sts %m0,%1", op, plen, -n_words); + ? avr_asm_len ("out %i0,%1", op, plen, -1) + : avr_asm_len ("sts %m0,%1", op, plen, -n_words); } else if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1))) + && REG_P (XEXP (x, 0)) + && CONST_INT_P (XEXP (x, 1))) { /* memory access by reg+disp */ int disp = INTVAL (XEXP (x, 1)); if (AVR_TINY) - return avr_out_movqi_mr_r_reg_disp_tiny (insn, op, plen); + return avr_out_movqi_mr_r_reg_disp_tiny (insn, op, plen); if (disp - GET_MODE_SIZE (GET_MODE (dest)) >= 63) - { - if (REGNO (XEXP (x, 0)) != REG_Y) - fatal_insn ("incorrect insn:",insn); - - if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) - return avr_asm_len ("adiw r28,%o0-63" CR_TAB - "std Y+63,%1" CR_TAB - "sbiw r28,%o0-63", op, plen, -3); - - return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "st Y,%1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -5); - } + { + if (REGNO (XEXP (x, 0)) != REG_Y) + fatal_insn ("incorrect insn:",insn); + + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) + return avr_asm_len ("adiw r28,%o0-63" CR_TAB + "std Y+63,%1" CR_TAB + "sbiw r28,%o0-63", op, plen, -3); + + return avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "st Y,%1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -5); + } else if (REGNO (XEXP (x, 0)) == REG_X) - { - if (reg_overlap_mentioned_p (src, XEXP (x, 0))) - { - avr_asm_len ("mov __tmp_reg__,%1" CR_TAB - "adiw r26,%o0" CR_TAB - "st X,__tmp_reg__", op, plen, -3); - } - else - { - avr_asm_len ("adiw r26,%o0" CR_TAB - "st X,%1", op, plen, -2); - } - - if (!reg_unused_after (insn, XEXP (x, 0))) - avr_asm_len ("sbiw r26,%o0", op, plen, 1); - - return ""; - } + { + if (reg_overlap_mentioned_p (src, XEXP (x, 0))) + { + avr_asm_len ("mov __tmp_reg__,%1" CR_TAB + "adiw r26,%o0" CR_TAB + "st X,__tmp_reg__", op, plen, -3); + } + else + { + avr_asm_len ("adiw r26,%o0" CR_TAB + "st X,%1", op, plen, -2); + } + + if (!reg_unused_after (insn, XEXP (x, 0))) + avr_asm_len ("sbiw r26,%o0", op, plen, 1); + + return ""; + } return avr_asm_len ("std %0,%1", op, plen, -1); } @@ -5692,7 +5692,7 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen) /* Helper for the next function for XMEGA. It does the same but with low byte first. */ -static const char* +static const char * avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5708,101 +5708,101 @@ avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen) if (CONSTANT_ADDRESS_P (base)) { return io_address_operand (base, HImode) - ? avr_asm_len ("out %i0,%A1" CR_TAB - "out %i0+1,%B1", op, plen, -2) + ? avr_asm_len ("out %i0,%A1" CR_TAB + "out %i0+1,%B1", op, plen, -2) - : avr_asm_len ("sts %m0,%A1" CR_TAB - "sts %m0+1,%B1", op, plen, -4); + : avr_asm_len ("sts %m0,%A1" CR_TAB + "sts %m0+1,%B1", op, plen, -4); } if (reg_base > 0) { if (reg_base != REG_X) - return avr_asm_len ("st %0,%A1" CR_TAB - "std %0+1,%B1", op, plen, -2); + return avr_asm_len ("st %0,%A1" CR_TAB + "std %0+1,%B1", op, plen, -2); if (reg_src == REG_X) - /* "st X+,r26" and "st -X,r26" are undefined. */ - avr_asm_len ("mov __tmp_reg__,r27" CR_TAB - "st X,r26" CR_TAB - "adiw r26,1" CR_TAB - "st X,__tmp_reg__", op, plen, -4); + /* "st X+,r26" and "st -X,r26" are undefined. */ + avr_asm_len ("mov __tmp_reg__,r27" CR_TAB + "st X,r26" CR_TAB + "adiw r26,1" CR_TAB + "st X,__tmp_reg__", op, plen, -4); else - avr_asm_len ("st X+,%A1" CR_TAB - "st X,%B1", op, plen, -2); + avr_asm_len ("st X+,%A1" CR_TAB + "st X,%B1", op, plen, -2); return reg_unused_after (insn, base) - ? "" - : avr_asm_len ("sbiw r26,1", op, plen, 1); + ? "" + : avr_asm_len ("sbiw r26,1", op, plen, 1); } else if (GET_CODE (base) == PLUS) { int disp = INTVAL (XEXP (base, 1)); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) - { - if (reg_base != REG_Y) - fatal_insn ("incorrect insn:",insn); - - return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) - ? avr_asm_len ("adiw r28,%o0-62" CR_TAB - "std Y+62,%A1" CR_TAB - "std Y+63,%B1" CR_TAB - "sbiw r28,%o0-62", op, plen, -4) - - : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "st Y,%A1" CR_TAB - "std Y+1,%B1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -6); - } + { + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + + return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) + ? avr_asm_len ("adiw r28,%o0-62" CR_TAB + "std Y+62,%A1" CR_TAB + "std Y+63,%B1" CR_TAB + "sbiw r28,%o0-62", op, plen, -4) + + : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "st Y,%A1" CR_TAB + "std Y+1,%B1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -6); + } if (reg_base != REG_X) - return avr_asm_len ("std %A0,%A1" CR_TAB - "std %B0,%B1", op, plen, -2); + return avr_asm_len ("std %A0,%A1" CR_TAB + "std %B0,%B1", op, plen, -2); /* (X + d) = R */ return reg_src == REG_X - ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB - "mov __zero_reg__,r27" CR_TAB - "adiw r26,%o0" CR_TAB - "st X+,__tmp_reg__" CR_TAB - "st X,__zero_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - "sbiw r26,%o0+1", op, plen, -7) - - : avr_asm_len ("adiw r26,%o0" CR_TAB - "st X+,%A1" CR_TAB - "st X,%B1" CR_TAB - "sbiw r26,%o0+1", op, plen, -4); + ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB + "mov __zero_reg__,r27" CR_TAB + "adiw r26,%o0" CR_TAB + "st X+,__tmp_reg__" CR_TAB + "st X,__zero_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + "sbiw r26,%o0+1", op, plen, -7) + + : avr_asm_len ("adiw r26,%o0" CR_TAB + "st X+,%A1" CR_TAB + "st X,%B1" CR_TAB + "sbiw r26,%o0+1", op, plen, -4); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { if (!mem_volatile_p) - return avr_asm_len ("st %0,%B1" CR_TAB - "st %0,%A1", op, plen, -2); + return avr_asm_len ("st %0,%B1" CR_TAB + "st %0,%A1", op, plen, -2); return REGNO (XEXP (base, 0)) == REG_X - ? avr_asm_len ("sbiw r26,2" CR_TAB - "st X+,%A1" CR_TAB - "st X,%B1" CR_TAB - "sbiw r26,1", op, plen, -4) + ? avr_asm_len ("sbiw r26,2" CR_TAB + "st X+,%A1" CR_TAB + "st X,%B1" CR_TAB + "sbiw r26,1", op, plen, -4) - : avr_asm_len ("sbiw %r0,2" CR_TAB - "st %p0,%A1" CR_TAB - "std %p0+1,%B1", op, plen, -3); + : avr_asm_len ("sbiw %r0,2" CR_TAB + "st %p0,%A1" CR_TAB + "std %p0+1,%B1", op, plen, -3); } else if (GET_CODE (base) == POST_INC) /* (R++) */ { return avr_asm_len ("st %0,%A1" CR_TAB - "st %0,%B1", op, plen, -2); + "st %0,%B1", op, plen, -2); } fatal_insn ("unknown move insn:",insn); return ""; } -static const char* +static const char * avr_out_movhi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5815,26 +5815,26 @@ avr_out_movhi_mr_r_reg_no_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_base == reg_src) { return !mem_volatile_p && reg_unused_after (insn, src) - ? avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB - "st %0,%A1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0,__tmp_reg__", op, plen, -5) - : avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB - TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0,__tmp_reg__" CR_TAB - TINY_SBIW (%E0, %F0, 1) CR_TAB - "st %0, %A1", op, plen, -7); + ? avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,__tmp_reg__", op, plen, -5) + : avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%E0, %F0, 1) CR_TAB + "st %0,__tmp_reg__" CR_TAB + TINY_SBIW (%E0, %F0, 1) CR_TAB + "st %0, %A1", op, plen, -7); } return !mem_volatile_p && reg_unused_after (insn, base) ? avr_asm_len ("st %0+,%A1" CR_TAB - "st %0,%B1", op, plen, -2) + "st %0,%B1", op, plen, -2) : avr_asm_len (TINY_ADIW (%E0, %F0, 1) CR_TAB - "st %0,%B1" CR_TAB - "st -%0,%A1", op, plen, -4); + "st %0,%B1" CR_TAB + "st -%0,%A1", op, plen, -4); } -static const char* +static const char * avr_out_movhi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5845,15 +5845,15 @@ avr_out_movhi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) if (reg_src == reg_base) avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB - "mov __zero_reg__,%B1" CR_TAB - TINY_ADIW (%I0, %J0, %o0+1) CR_TAB - "st %b0,__zero_reg__" CR_TAB - "st -%b0,__tmp_reg__" CR_TAB - "clr __zero_reg__", op, plen, -7); + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%I0, %J0, %o0+1) CR_TAB + "st %b0,__zero_reg__" CR_TAB + "st -%b0,__tmp_reg__" CR_TAB + "clr __zero_reg__", op, plen, -7); else avr_asm_len (TINY_ADIW (%I0, %J0, %o0+1) CR_TAB - "st %b0,%B1" CR_TAB - "st -%b0,%A1", op, plen, -4); + "st %b0,%B1" CR_TAB + "st -%b0,%A1", op, plen, -4); if (!reg_unused_after (insn, XEXP (base, 0))) avr_asm_len (TINY_SBIW (%I0, %J0, %o0), op, plen, 2); @@ -5861,16 +5861,16 @@ avr_out_movhi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen) return ""; } -static const char* +static const char * avr_out_movhi_mr_r_post_inc_tiny (rtx op[], int *plen) { return avr_asm_len (TINY_ADIW (%I0, %J0, 1) CR_TAB - "st %p0,%B1" CR_TAB - "st -%p0,%A1" CR_TAB - TINY_ADIW (%I0, %J0, 2), op, plen, -6); + "st %p0,%B1" CR_TAB + "st -%p0,%A1" CR_TAB + TINY_ADIW (%I0, %J0, 2), op, plen, -6); } -static const char* +static const char * out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) { rtx dest = op[0]; @@ -5893,111 +5893,111 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen) { int n_words = AVR_TINY ? 2 : 4; return io_address_operand (base, HImode) - ? avr_asm_len ("out %i0+1,%B1" CR_TAB - "out %i0,%A1", op, plen, -2) + ? avr_asm_len ("out %i0+1,%B1" CR_TAB + "out %i0,%A1", op, plen, -2) - : avr_asm_len ("sts %m0+1,%B1" CR_TAB - "sts %m0,%A1", op, plen, -n_words); + : avr_asm_len ("sts %m0+1,%B1" CR_TAB + "sts %m0,%A1", op, plen, -n_words); } if (reg_base > 0) { if (AVR_TINY) - return avr_out_movhi_mr_r_reg_no_disp_tiny (insn, op, plen); + return avr_out_movhi_mr_r_reg_no_disp_tiny (insn, op, plen); if (reg_base != REG_X) - return avr_asm_len ("std %0+1,%B1" CR_TAB - "st %0,%A1", op, plen, -2); + return avr_asm_len ("std %0+1,%B1" CR_TAB + "st %0,%A1", op, plen, -2); if (reg_src == REG_X) - /* "st X+,r26" and "st -X,r26" are undefined. */ - return !mem_volatile_p && reg_unused_after (insn, src) - ? avr_asm_len ("mov __tmp_reg__,r27" CR_TAB - "st X,r26" CR_TAB - "adiw r26,1" CR_TAB - "st X,__tmp_reg__", op, plen, -4) - - : avr_asm_len ("mov __tmp_reg__,r27" CR_TAB - "adiw r26,1" CR_TAB - "st X,__tmp_reg__" CR_TAB - "sbiw r26,1" CR_TAB - "st X,r26", op, plen, -5); + /* "st X+,r26" and "st -X,r26" are undefined. */ + return !mem_volatile_p && reg_unused_after (insn, src) + ? avr_asm_len ("mov __tmp_reg__,r27" CR_TAB + "st X,r26" CR_TAB + "adiw r26,1" CR_TAB + "st X,__tmp_reg__", op, plen, -4) + + : avr_asm_len ("mov __tmp_reg__,r27" CR_TAB + "adiw r26,1" CR_TAB + "st X,__tmp_reg__" CR_TAB + "sbiw r26,1" CR_TAB + "st X,r26", op, plen, -5); return !mem_volatile_p && reg_unused_after (insn, base) - ? avr_asm_len ("st X+,%A1" CR_TAB - "st X,%B1", op, plen, -2) - : avr_asm_len ("adiw r26,1" CR_TAB - "st X,%B1" CR_TAB - "st -X,%A1", op, plen, -3); + ? avr_asm_len ("st X+,%A1" CR_TAB + "st X,%B1", op, plen, -2) + : avr_asm_len ("adiw r26,1" CR_TAB + "st X,%B1" CR_TAB + "st -X,%A1", op, plen, -3); } else if (GET_CODE (base) == PLUS) { int disp = INTVAL (XEXP (base, 1)); if (AVR_TINY) - return avr_out_movhi_mr_r_reg_disp_tiny (insn, op, plen); + return avr_out_movhi_mr_r_reg_disp_tiny (insn, op, plen); reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) - { - if (reg_base != REG_Y) - fatal_insn ("incorrect insn:",insn); - - return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) - ? avr_asm_len ("adiw r28,%o0-62" CR_TAB - "std Y+63,%B1" CR_TAB - "std Y+62,%A1" CR_TAB - "sbiw r28,%o0-62", op, plen, -4) - - : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB - "sbci r29,hi8(-%o0)" CR_TAB - "std Y+1,%B1" CR_TAB - "st Y,%A1" CR_TAB - "subi r28,lo8(%o0)" CR_TAB - "sbci r29,hi8(%o0)", op, plen, -6); - } + { + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + + return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)) + ? avr_asm_len ("adiw r28,%o0-62" CR_TAB + "std Y+63,%B1" CR_TAB + "std Y+62,%A1" CR_TAB + "sbiw r28,%o0-62", op, plen, -4) + + : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB + "sbci r29,hi8(-%o0)" CR_TAB + "std Y+1,%B1" CR_TAB + "st Y,%A1" CR_TAB + "subi r28,lo8(%o0)" CR_TAB + "sbci r29,hi8(%o0)", op, plen, -6); + } if (reg_base != REG_X) - return avr_asm_len ("std %B0,%B1" CR_TAB - "std %A0,%A1", op, plen, -2); + return avr_asm_len ("std %B0,%B1" CR_TAB + "std %A0,%A1", op, plen, -2); /* (X + d) = R */ return reg_src == REG_X - ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB - "mov __zero_reg__,r27" CR_TAB - "adiw r26,%o0+1" CR_TAB - "st X,__zero_reg__" CR_TAB - "st -X,__tmp_reg__" CR_TAB - "clr __zero_reg__" CR_TAB - "sbiw r26,%o0", op, plen, -7) - - : avr_asm_len ("adiw r26,%o0+1" CR_TAB - "st X,%B1" CR_TAB - "st -X,%A1" CR_TAB - "sbiw r26,%o0", op, plen, -4); + ? avr_asm_len ("mov __tmp_reg__,r26" CR_TAB + "mov __zero_reg__,r27" CR_TAB + "adiw r26,%o0+1" CR_TAB + "st X,__zero_reg__" CR_TAB + "st -X,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + "sbiw r26,%o0", op, plen, -7) + + : avr_asm_len ("adiw r26,%o0+1" CR_TAB + "st X,%B1" CR_TAB + "st -X,%A1" CR_TAB + "sbiw r26,%o0", op, plen, -4); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { return avr_asm_len ("st %0,%B1" CR_TAB - "st %0,%A1", op, plen, -2); + "st %0,%A1", op, plen, -2); } else if (GET_CODE (base) == POST_INC) /* (R++) */ { if (!mem_volatile_p) - return avr_asm_len ("st %0,%A1" CR_TAB - "st %0,%B1", op, plen, -2); + return avr_asm_len ("st %0,%A1" CR_TAB + "st %0,%B1", op, plen, -2); if (AVR_TINY) - return avr_out_movhi_mr_r_post_inc_tiny (op, plen); + return avr_out_movhi_mr_r_post_inc_tiny (op, plen); return REGNO (XEXP (base, 0)) == REG_X - ? avr_asm_len ("adiw r26,1" CR_TAB - "st X,%B1" CR_TAB - "st -X,%A1" CR_TAB - "adiw r26,2", op, plen, -4) + ? avr_asm_len ("adiw r26,1" CR_TAB + "st X,%B1" CR_TAB + "st -X,%A1" CR_TAB + "adiw r26,2", op, plen, -4) - : avr_asm_len ("std %p0+1,%B1" CR_TAB - "st %p0,%A1" CR_TAB - "adiw %r0,2", op, plen, -3); + : avr_asm_len ("std %p0+1,%B1" CR_TAB + "st %p0,%A1" CR_TAB + "adiw %r0,2", op, plen, -3); } fatal_insn ("unknown move insn:",insn); return ""; @@ -6009,10 +6009,10 @@ static bool avr_frame_pointer_required_p (void) { return (cfun->calls_alloca - || cfun->calls_setjmp - || cfun->has_nonlocal_label - || crtl->args.info.nregs == 0 - || get_frame_size () > 0); + || cfun->calls_setjmp + || cfun->has_nonlocal_label + || crtl->args.info.nregs == 0 + || get_frame_size () > 0); } @@ -6157,7 +6157,7 @@ avr_canonicalize_comparison (int *icode, rtx *op0, rtx *op1, bool op0_fixed) PLEN != NULL: Set *PLEN to the length (in words) of the sequence. Don't output anything. */ -const char* +const char * avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) { /* Register to compare and value to compare against. */ @@ -6186,7 +6186,7 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) gcc_assert (REG_P (xreg)); gcc_assert ((CONST_INT_P (xval) && n_bytes <= 4) - || (const_double_operand (xval, VOIDmode) && n_bytes == 8)); + || (const_double_operand (xval, VOIDmode) && n_bytes == 8)); if (plen) *plen = 0; @@ -6201,29 +6201,29 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) && reg_unused_after (insn, xreg)) { if (xval == const1_rtx) - { - avr_asm_len ("dec %A0" CR_TAB - "or %A0,%B0", xop, plen, 2); + { + avr_asm_len ("dec %A0" CR_TAB + "or %A0,%B0", xop, plen, 2); - if (n_bytes >= 3) - avr_asm_len ("or %A0,%C0", xop, plen, 1); + if (n_bytes >= 3) + avr_asm_len ("or %A0,%C0", xop, plen, 1); - if (n_bytes >= 4) - avr_asm_len ("or %A0,%D0", xop, plen, 1); + if (n_bytes >= 4) + avr_asm_len ("or %A0,%D0", xop, plen, 1); - return ""; - } + return ""; + } else if (xval == constm1_rtx) - { - if (n_bytes >= 4) - avr_asm_len ("and %A0,%D0", xop, plen, 1); + { + if (n_bytes >= 4) + avr_asm_len ("and %A0,%D0", xop, plen, 1); - if (n_bytes >= 3) - avr_asm_len ("and %A0,%C0", xop, plen, 1); + if (n_bytes >= 3) + avr_asm_len ("and %A0,%C0", xop, plen, 1); - return avr_asm_len ("and %A0,%B0" CR_TAB - "com %A0", xop, plen, 2); - } + return avr_asm_len ("and %A0,%B0" CR_TAB + "com %A0", xop, plen, 2); + } } /* Comparisons == -1 and != -1 of a d-register that's used after the @@ -6245,13 +6245,13 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) rtx xhi8 = simplify_gen_subreg (QImode, xval, mode, 1); if (INTVAL (xlo8) == INTVAL (xhi8)) - { - xop[0] = xreg; - xop[1] = xlo8; + { + xop[0] = xreg; + xop[1] = xlo8; - return avr_asm_len ("cpi %A0,%1" CR_TAB - "cpc %B0,%A0", xop, plen, 2); - } + return avr_asm_len ("cpi %A0,%1" CR_TAB + "cpc %B0,%A0", xop, plen, 2); + } } for (int i = 0; i < n_bytes; i++) @@ -6272,74 +6272,74 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) /* Word registers >= R24 can use SBIW/ADIW with 0..63. */ if (i == 0 - && test_hard_reg_class (ADDW_REGS, reg8)) - { - int val16 = trunc_int_for_mode (INTVAL (xval), HImode); - - if (IN_RANGE (val16, 0, 63) - && (val8 == 0 - || reg_unused_after (insn, xreg))) - { - if (AVR_TINY) - avr_asm_len (TINY_SBIW (%A0, %B0, %1), xop, plen, 2); - else - avr_asm_len ("sbiw %0,%1", xop, plen, 1); - - i++; - continue; - } - - if (n_bytes == 2 - && IN_RANGE (val16, -63, -1) - && compare_eq_p (insn) - && reg_unused_after (insn, xreg)) - { - return AVR_TINY - ? avr_asm_len (TINY_ADIW (%A0, %B0, %n1), xop, plen, 2) - : avr_asm_len ("adiw %0,%n1", xop, plen, 1); - } - } + && test_hard_reg_class (ADDW_REGS, reg8)) + { + int val16 = trunc_int_for_mode (INTVAL (xval), HImode); + + if (IN_RANGE (val16, 0, 63) + && (val8 == 0 + || reg_unused_after (insn, xreg))) + { + if (AVR_TINY) + avr_asm_len (TINY_SBIW (%A0, %B0, %1), xop, plen, 2); + else + avr_asm_len ("sbiw %0,%1", xop, plen, 1); + + i++; + continue; + } + + if (n_bytes == 2 + && IN_RANGE (val16, -63, -1) + && compare_eq_p (insn) + && reg_unused_after (insn, xreg)) + { + return AVR_TINY + ? avr_asm_len (TINY_ADIW (%A0, %B0, %n1), xop, plen, 2) + : avr_asm_len ("adiw %0,%n1", xop, plen, 1); + } + } /* Comparing against 0 is easy. */ if (val8 == 0) - { - avr_asm_len (i == 0 - ? "cp %0,__zero_reg__" - : "cpc %0,__zero_reg__", xop, plen, 1); - continue; - } + { + avr_asm_len (i == 0 + ? "cp %0,__zero_reg__" + : "cpc %0,__zero_reg__", xop, plen, 1); + continue; + } /* Upper registers can compare and subtract-with-carry immediates. - Notice that compare instructions do the same as respective subtract - instruction; the only difference is that comparisons don't write - the result back to the target register. */ + Notice that compare instructions do the same as respective subtract + instruction; the only difference is that comparisons don't write + the result back to the target register. */ if (ld_reg_p) - { - if (i == 0) - { - avr_asm_len ("cpi %0,%1", xop, plen, 1); - continue; - } - else if (reg_unused_after (insn, xreg)) - { - avr_asm_len ("sbci %0,%1", xop, plen, 1); - continue; - } - } + { + if (i == 0) + { + avr_asm_len ("cpi %0,%1", xop, plen, 1); + continue; + } + else if (reg_unused_after (insn, xreg)) + { + avr_asm_len ("sbci %0,%1", xop, plen, 1); + continue; + } + } /* Must load the value into the scratch register. */ gcc_assert (REG_P (xop[2])); if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", xop, plen, 1); + avr_asm_len ("ldi %2,%1", xop, plen, 1); clobber_val = (int) val8; avr_asm_len (i == 0 - ? "cp %0,%2" - : "cpc %0,%2", xop, plen, 1); + ? "cp %0,%2" + : "cpc %0,%2", xop, plen, 1); } return ""; @@ -6348,7 +6348,7 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen) /* Prepare operands of compare_const_di2 to be used with avr_out_compare. */ -const char* +const char * avr_out_compare64 (rtx_insn *insn, rtx *op, int *plen) { rtx xop[3]; @@ -6362,7 +6362,7 @@ avr_out_compare64 (rtx_insn *insn, rtx *op, int *plen) /* Output test instruction for HImode. */ -const char* +const char * avr_out_tsthi (rtx_insn *insn, rtx *op, int *plen) { if (compare_sign_p (insn)) @@ -6370,7 +6370,7 @@ avr_out_tsthi (rtx_insn *insn, rtx *op, int *plen) avr_asm_len ("tst %B0", op, plen, -1); } else if (reg_unused_after (insn, op[0]) - && compare_eq_p (insn)) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ avr_asm_len ("or %A0,%B0", op, plen, -1); @@ -6386,7 +6386,7 @@ avr_out_tsthi (rtx_insn *insn, rtx *op, int *plen) /* Output test instruction for PSImode. */ -const char* +const char * avr_out_tstpsi (rtx_insn *insn, rtx *op, int *plen) { if (compare_sign_p (insn)) @@ -6394,11 +6394,11 @@ avr_out_tstpsi (rtx_insn *insn, rtx *op, int *plen) avr_asm_len ("tst %C0", op, plen, -1); } else if (reg_unused_after (insn, op[0]) - && compare_eq_p (insn)) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ avr_asm_len ("or %A0,%B0" CR_TAB - "or %A0,%C0", op, plen, -2); + "or %A0,%C0", op, plen, -2); } else { @@ -6411,7 +6411,7 @@ avr_out_tstpsi (rtx_insn *insn, rtx *op, int *plen) /* Output test instruction for SImode. */ -const char* +const char * avr_out_tstsi (rtx_insn *insn, rtx *op, int *plen) { if (compare_sign_p (insn)) @@ -6419,12 +6419,12 @@ avr_out_tstsi (rtx_insn *insn, rtx *op, int *plen) avr_asm_len ("tst %D0", op, plen, -1); } else if (reg_unused_after (insn, op[0]) - && compare_eq_p (insn)) + && compare_eq_p (insn)) { /* Faster than sbiw if we can clobber the operand. */ avr_asm_len ("or %A0,%B0" CR_TAB - "or %A0,%C0" CR_TAB - "or %A0,%D0", op, plen, -3); + "or %A0,%C0" CR_TAB + "or %A0,%D0", op, plen, -3); } else { @@ -6441,7 +6441,7 @@ avr_out_tstsi (rtx_insn *insn, rtx *op, int *plen) PLEN != 0: Set *PLEN to the code length in words. Don't output anything. PLEN == 0: Print instructions. */ -const char* +const char * avr_out_cmp_ext (rtx xop[], enum rtx_code code, int *plen) { // The smaller reg is the one that's to be extended. Get its index as z. @@ -6533,56 +6533,56 @@ out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[], If a scratch reg is not available, then the parallel will contain only a set and clobber of REG_CC. */ bool scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int count = INTVAL (operands[2]); int max_len = 10; /* If larger than this, always use a loop. */ if (count <= 0) - return; + return; if (count < 8 && !scratch) - use_zero_reg = true; + use_zero_reg = true; if (optimize_size) - max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5)); + max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5)); if (t_len * count <= max_len) - { - /* Output shifts inline with no loop - faster. */ + { + /* Output shifts inline with no loop - faster. */ - while (count-- > 0) - avr_asm_len (templ, op, plen, t_len); + while (count-- > 0) + avr_asm_len (templ, op, plen, t_len); - return; - } + return; + } if (scratch) - { - avr_asm_len ("ldi %3,%2", op, plen, 1); - } + { + avr_asm_len ("ldi %3,%2", op, plen, 1); + } else if (use_zero_reg) - { - /* Hack to save one word: use __zero_reg__ as loop counter. - Set one bit, then shift in a loop until it is 0 again. */ + { + /* Hack to save one word: use __zero_reg__ as loop counter. + Set one bit, then shift in a loop until it is 0 again. */ - op[3] = zero_reg_rtx; + op[3] = zero_reg_rtx; - avr_asm_len ("set" CR_TAB - "bld %3,%2-1", op, plen, 2); - } + avr_asm_len ("set" CR_TAB + "bld %3,%2-1", op, plen, 2); + } else - { - /* No scratch register available, use one from LD_REGS (saved in - __tmp_reg__) that doesn't overlap with registers to shift. */ + { + /* No scratch register available, use one from LD_REGS (saved in + __tmp_reg__) that doesn't overlap with registers to shift. */ - op[3] = all_regs_rtx[((REGNO (op[0]) - 1) & 15) + 16]; - op[4] = tmp_reg_rtx; - saved_in_tmp = true; + op[3] = all_regs_rtx[((REGNO (op[0]) - 1) & 15) + 16]; + op[4] = tmp_reg_rtx; + saved_in_tmp = true; - avr_asm_len ("mov %4,%3" CR_TAB - "ldi %3,%2", op, plen, 2); - } + avr_asm_len ("mov %4,%3" CR_TAB + "ldi %3,%2", op, plen, 2); + } second_label = false; } @@ -6600,11 +6600,11 @@ out_shift_with_cnt (const char *templ, rtx_insn *insn, rtx operands[], op[3] = op[2]; if (!reg_unused_after (insn, op[2]) - || reg_overlap_mentioned_p (op[0], op[2])) - { - op[3] = tmp_reg_rtx; - avr_asm_len ("mov %3,%2", op, plen, 1); - } + || reg_overlap_mentioned_p (op[0], op[2])) + { + op[3] = tmp_reg_rtx; + avr_asm_len ("mov %3,%2", op, plen, 1); + } } else fatal_insn ("bad shift insn:", insn); @@ -6718,7 +6718,7 @@ ashlqi3_out (rtx_insn *insn, rtx operands[], int *len) fatal_insn ("internal compiler error. Incorrect shift:", insn); out_shift_with_cnt ("lsl %0", - insn, operands, len, 1); + insn, operands, len, 1); return ""; } @@ -6731,8 +6731,8 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *len) if (CONST_INT_P (operands[2])) { int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]); int k; int *t = len; @@ -6977,14 +6977,14 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsl %A0" CR_TAB - "rol %B0", insn, operands, len, 2); + "rol %B0", insn, operands, len, 2); return ""; } /* 24-bit shift left */ -const char* +const char * avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen) { if (plen) @@ -6993,54 +6993,54 @@ avr_out_ashlpsi3 (rtx_insn *insn, rtx *op, int *plen) if (CONST_INT_P (op[2])) { switch (INTVAL (op[2])) - { - default: - if (INTVAL (op[2]) < 24) - break; - - return avr_asm_len ("clr %A0" CR_TAB - "clr %B0" CR_TAB - "clr %C0", op, plen, 3); - - case 8: - { - int reg0 = REGNO (op[0]); - int reg1 = REGNO (op[1]); - - if (reg0 >= reg1) - return avr_asm_len ("mov %C0,%B1" CR_TAB - "mov %B0,%A1" CR_TAB - "clr %A0", op, plen, 3); - else - return avr_asm_len ("clr %A0" CR_TAB - "mov %B0,%A1" CR_TAB - "mov %C0,%B1", op, plen, 3); - } - - case 16: - { - int reg0 = REGNO (op[0]); - int reg1 = REGNO (op[1]); - - if (reg0 + 2 != reg1) - avr_asm_len ("mov %C0,%A0", op, plen, 1); - - return avr_asm_len ("clr %B0" CR_TAB - "clr %A0", op, plen, 2); - } - - case 23: - return avr_asm_len ("clr %C0" CR_TAB - "lsr %A0" CR_TAB - "ror %C0" CR_TAB - "clr %B0" CR_TAB - "clr %A0", op, plen, 5); - } + { + default: + if (INTVAL (op[2]) < 24) + break; + + return avr_asm_len ("clr %A0" CR_TAB + "clr %B0" CR_TAB + "clr %C0", op, plen, 3); + + case 8: + { + int reg0 = REGNO (op[0]); + int reg1 = REGNO (op[1]); + + if (reg0 >= reg1) + return avr_asm_len ("mov %C0,%B1" CR_TAB + "mov %B0,%A1" CR_TAB + "clr %A0", op, plen, 3); + else + return avr_asm_len ("clr %A0" CR_TAB + "mov %B0,%A1" CR_TAB + "mov %C0,%B1", op, plen, 3); + } + + case 16: + { + int reg0 = REGNO (op[0]); + int reg1 = REGNO (op[1]); + + if (reg0 + 2 != reg1) + avr_asm_len ("mov %C0,%A0", op, plen, 1); + + return avr_asm_len ("clr %B0" CR_TAB + "clr %A0", op, plen, 2); + } + + case 23: + return avr_asm_len ("clr %C0" CR_TAB + "lsr %A0" CR_TAB + "ror %C0" CR_TAB + "clr %B0" CR_TAB + "clr %A0", op, plen, 5); + } } out_shift_with_cnt ("lsl %A0" CR_TAB - "rol %B0" CR_TAB - "rol %C0", insn, op, plen, 3); + "rol %B0" CR_TAB + "rol %C0", insn, op, plen, 3); return ""; } @@ -7128,9 +7128,9 @@ ashlsi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsl %A0" CR_TAB - "rol %B0" CR_TAB - "rol %C0" CR_TAB - "rol %D0", insn, operands, len, 4); + "rol %B0" CR_TAB + "rol %C0" CR_TAB + "rol %D0", insn, operands, len, 4); return ""; } @@ -7201,7 +7201,7 @@ ashrqi3_out (rtx_insn *insn, rtx operands[], int *len) fatal_insn ("internal compiler error. Incorrect shift:", insn); out_shift_with_cnt ("asr %0", - insn, operands, len, 1); + insn, operands, len, 1); return ""; } @@ -7214,8 +7214,8 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len) if (CONST_INT_P (operands[2])) { int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]); int k; int *t = len; @@ -7261,9 +7261,9 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len) "sbc %B0,%B0"); else return *len = 4, ("mov %A0,%B1" CR_TAB - "clr %B0" CR_TAB - "sbrc %A0,7" CR_TAB - "dec %B0"); + "clr %B0" CR_TAB + "sbrc %A0,7" CR_TAB + "dec %B0"); } case 9: @@ -7366,14 +7366,14 @@ ashrhi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("asr %B0" CR_TAB - "ror %A0", insn, operands, len, 2); + "ror %A0", insn, operands, len, 2); return ""; } /* 24-bit arithmetic shift right */ -const char* +const char * avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen) { int dest = REGNO (op[0]); @@ -7382,50 +7382,50 @@ avr_out_ashrpsi3 (rtx_insn *insn, rtx *op, int *plen) if (CONST_INT_P (op[2])) { if (plen) - *plen = 0; + *plen = 0; switch (INTVAL (op[2])) - { - case 8: - if (dest <= src) - return avr_asm_len ("mov %A0,%B1" CR_TAB - "mov %B0,%C1" CR_TAB - "clr %C0" CR_TAB - "sbrc %B0,7" CR_TAB - "dec %C0", op, plen, 5); - else - return avr_asm_len ("clr %C0" CR_TAB - "sbrc %C1,7" CR_TAB - "dec %C0" CR_TAB - "mov %B0,%C1" CR_TAB - "mov %A0,%B1", op, plen, 5); - - case 16: - if (dest != src + 2) - avr_asm_len ("mov %A0,%C1", op, plen, 1); - - return avr_asm_len ("clr %B0" CR_TAB - "sbrc %A0,7" CR_TAB - "com %B0" CR_TAB - "mov %C0,%B0", op, plen, 4); - - default: - if (INTVAL (op[2]) < 24) - break; - - /* fall through */ - - case 23: - return avr_asm_len ("lsl %C0" CR_TAB - "sbc %A0,%A0" CR_TAB - "mov %B0,%A0" CR_TAB - "mov %C0,%A0", op, plen, 4); - } /* switch */ + { + case 8: + if (dest <= src) + return avr_asm_len ("mov %A0,%B1" CR_TAB + "mov %B0,%C1" CR_TAB + "clr %C0" CR_TAB + "sbrc %B0,7" CR_TAB + "dec %C0", op, plen, 5); + else + return avr_asm_len ("clr %C0" CR_TAB + "sbrc %C1,7" CR_TAB + "dec %C0" CR_TAB + "mov %B0,%C1" CR_TAB + "mov %A0,%B1", op, plen, 5); + + case 16: + if (dest != src + 2) + avr_asm_len ("mov %A0,%C1", op, plen, 1); + + return avr_asm_len ("clr %B0" CR_TAB + "sbrc %A0,7" CR_TAB + "com %B0" CR_TAB + "mov %C0,%B0", op, plen, 4); + + default: + if (INTVAL (op[2]) < 24) + break; + + /* fall through */ + + case 23: + return avr_asm_len ("lsl %C0" CR_TAB + "sbc %A0,%A0" CR_TAB + "mov %B0,%A0" CR_TAB + "mov %C0,%A0", op, plen, 4); + } /* switch */ } out_shift_with_cnt ("asr %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, op, plen, 3); + "ror %B0" CR_TAB + "ror %A0", insn, op, plen, 3); return ""; } @@ -7521,9 +7521,9 @@ ashrsi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("asr %D0" CR_TAB - "ror %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, operands, len, 4); + "ror %C0" CR_TAB + "ror %B0" CR_TAB + "ror %A0", insn, operands, len, 4); return ""; } @@ -7618,7 +7618,7 @@ lshrqi3_out (rtx_insn *insn, rtx operands[], int *len) fatal_insn ("internal compiler error. Incorrect shift:", insn); out_shift_with_cnt ("lsr %0", - insn, operands, len, 1); + insn, operands, len, 1); return ""; } @@ -7630,8 +7630,8 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *len) if (CONST_INT_P (operands[2])) { int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL - && XVECLEN (PATTERN (insn), 0) == 3 - && REG_P (operands[3])); + && XVECLEN (PATTERN (insn), 0) == 3 + && REG_P (operands[3])); int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]); int k; int *t = len; @@ -7876,14 +7876,14 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsr %B0" CR_TAB - "ror %A0", insn, operands, len, 2); + "ror %A0", insn, operands, len, 2); return ""; } /* 24-bit logic shift right */ -const char* +const char * avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen) { int dest = REGNO (op[0]); @@ -7892,45 +7892,45 @@ avr_out_lshrpsi3 (rtx_insn *insn, rtx *op, int *plen) if (CONST_INT_P (op[2])) { if (plen) - *plen = 0; + *plen = 0; switch (INTVAL (op[2])) - { - case 8: - if (dest <= src) - return avr_asm_len ("mov %A0,%B1" CR_TAB - "mov %B0,%C1" CR_TAB - "clr %C0", op, plen, 3); - else - return avr_asm_len ("clr %C0" CR_TAB - "mov %B0,%C1" CR_TAB - "mov %A0,%B1", op, plen, 3); - - case 16: - if (dest != src + 2) - avr_asm_len ("mov %A0,%C1", op, plen, 1); - - return avr_asm_len ("clr %B0" CR_TAB - "clr %C0", op, plen, 2); - - default: - if (INTVAL (op[2]) < 24) - break; - - /* fall through */ - - case 23: - return avr_asm_len ("bst %C1,7" CR_TAB - "clr %A0" CR_TAB - "clr %B0" CR_TAB - "clr %C0" CR_TAB - "bld %A0,0", op, plen, 5); - } /* switch */ + { + case 8: + if (dest <= src) + return avr_asm_len ("mov %A0,%B1" CR_TAB + "mov %B0,%C1" CR_TAB + "clr %C0", op, plen, 3); + else + return avr_asm_len ("clr %C0" CR_TAB + "mov %B0,%C1" CR_TAB + "mov %A0,%B1", op, plen, 3); + + case 16: + if (dest != src + 2) + avr_asm_len ("mov %A0,%C1", op, plen, 1); + + return avr_asm_len ("clr %B0" CR_TAB + "clr %C0", op, plen, 2); + + default: + if (INTVAL (op[2]) < 24) + break; + + /* fall through */ + + case 23: + return avr_asm_len ("bst %C1,7" CR_TAB + "clr %A0" CR_TAB + "clr %B0" CR_TAB + "clr %C0" CR_TAB + "bld %A0,0", op, plen, 5); + } /* switch */ } out_shift_with_cnt ("lsr %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, op, plen, 3); + "ror %B0" CR_TAB + "ror %A0", insn, op, plen, 3); return ""; } @@ -8024,9 +8024,9 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len) len = t; } out_shift_with_cnt ("lsr %D0" CR_TAB - "ror %C0" CR_TAB - "ror %B0" CR_TAB - "ror %A0", insn, operands, len, 4); + "ror %C0" CR_TAB + "ror %B0" CR_TAB + "ror %A0", insn, operands, len, 4); return ""; } @@ -8059,7 +8059,7 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *len) static void avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, - enum rtx_code code_sat, int sign, bool out_label) + enum rtx_code code_sat, int sign, bool out_label) { /* MODE of the operation. */ machine_mode mode = GET_MODE (xop[0]); @@ -8097,26 +8097,26 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, *pcc = MINUS == code ? (int) CC_SET_CZN : (int) CC_CLOBBER; for (int i = 0; i < n_bytes; i++) - { - /* We operate byte-wise on the destination. */ - op[0] = simplify_gen_subreg (QImode, xop[0], mode, i); - op[1] = simplify_gen_subreg (QImode, xop[2], mode, i); - - if (i == 0) - avr_asm_len (code == PLUS ? "add %0,%1" : "sub %0,%1", - op, plen, 1); - else - avr_asm_len (code == PLUS ? "adc %0,%1" : "sbc %0,%1", - op, plen, 1); - } + { + /* We operate byte-wise on the destination. */ + op[0] = simplify_gen_subreg (QImode, xop[0], mode, i); + op[1] = simplify_gen_subreg (QImode, xop[2], mode, i); + + if (i == 0) + avr_asm_len (code == PLUS ? "add %0,%1" : "sub %0,%1", + op, plen, 1); + else + avr_asm_len (code == PLUS ? "adc %0,%1" : "sbc %0,%1", + op, plen, 1); + } if (reg_overlap_mentioned_p (xop[0], xop[2])) - { - gcc_assert (REGNO (xop[0]) == REGNO (xop[2])); + { + gcc_assert (REGNO (xop[0]) == REGNO (xop[2])); - if (MINUS == code) - return; - } + if (MINUS == code) + return; + } goto saturate; } @@ -8145,19 +8145,19 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, if (SS_PLUS == code_sat && MINUS == code && sign < 0 && 0x80 == (INTVAL (simplify_gen_subreg (QImode, xval, imode, n_bytes-1)) - & GET_MODE_MASK (QImode))) + & GET_MODE_MASK (QImode))) { /* We compute x + 0x80 by means of SUB instructions. We negated the - constant subtrahend above and are left with x - (-128) so that we - need something like SUBI r,128 which does not exist because SUBI sets - V according to the sign of the subtrahend. Notice the only case - where this must be done is when NEG overflowed in case [2s] because - the V computation needs the right sign of the subtrahend. */ + constant subtrahend above and are left with x - (-128) so that we + need something like SUBI r,128 which does not exist because SUBI sets + V according to the sign of the subtrahend. Notice the only case + where this must be done is when NEG overflowed in case [2s] because + the V computation needs the right sign of the subtrahend. */ rtx msb = simplify_gen_subreg (QImode, xop[0], mode, n_bytes - 1); avr_asm_len ("subi %0,128" CR_TAB - "brmi 0f", &msb, plen, 2); + "brmi 0f", &msb, plen, 2); out_brvc = false; goto saturate; @@ -8181,100 +8181,100 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, /* To get usable cc0 no low-bytes must have been skipped. */ if (i && !started) - *pcc = CC_CLOBBER; + *pcc = CC_CLOBBER; if (!started - && i % 2 == 0 - && i + 2 <= n_bytes - && test_hard_reg_class (ADDW_REGS, reg8)) - { - rtx xval16 = simplify_gen_subreg (HImode, xval, imode, i); - unsigned int val16 = UINTVAL (xval16) & GET_MODE_MASK (HImode); - - /* Registers R24, X, Y, Z can use ADIW/SBIW with constants < 64 - i.e. operate word-wise. */ - - if (val16 < 64) - { - if (val16 != 0) - { - started = true; - avr_asm_len (code == PLUS ? "adiw %0,%1" : "sbiw %0,%1", - op, plen, 1); - - if (n_bytes == 2 && PLUS == code) - *pcc = CC_SET_CZN; - } - - i++; - continue; - } - } + && i % 2 == 0 + && i + 2 <= n_bytes + && test_hard_reg_class (ADDW_REGS, reg8)) + { + rtx xval16 = simplify_gen_subreg (HImode, xval, imode, i); + unsigned int val16 = UINTVAL (xval16) & GET_MODE_MASK (HImode); + + /* Registers R24, X, Y, Z can use ADIW/SBIW with constants < 64 + i.e. operate word-wise. */ + + if (val16 < 64) + { + if (val16 != 0) + { + started = true; + avr_asm_len (code == PLUS ? "adiw %0,%1" : "sbiw %0,%1", + op, plen, 1); + + if (n_bytes == 2 && PLUS == code) + *pcc = CC_SET_CZN; + } + + i++; + continue; + } + } if (val8 == 0) - { - if (started) - avr_asm_len (code == PLUS - ? "adc %0,__zero_reg__" : "sbc %0,__zero_reg__", - op, plen, 1); - continue; - } + { + if (started) + avr_asm_len (code == PLUS + ? "adc %0,__zero_reg__" : "sbc %0,__zero_reg__", + op, plen, 1); + continue; + } else if ((val8 == 1 || val8 == 0xff) - && UNKNOWN == code_sat - && !started - && i == n_bytes - 1) - { - avr_asm_len ((code == PLUS) ^ (val8 == 1) ? "dec %0" : "inc %0", - op, plen, 1); - *pcc = CC_CLOBBER; - break; - } + && UNKNOWN == code_sat + && !started + && i == n_bytes - 1) + { + avr_asm_len ((code == PLUS) ^ (val8 == 1) ? "dec %0" : "inc %0", + op, plen, 1); + *pcc = CC_CLOBBER; + break; + } switch (code) - { - case PLUS: + { + case PLUS: - gcc_assert (plen != NULL || (op[2] && REG_P (op[2]))); + gcc_assert (plen != NULL || (op[2] && REG_P (op[2]))); - if (plen != NULL && UNKNOWN != code_sat) - { - /* This belongs to the x + 0x80 corner case. The code with - ADD instruction is not smaller, thus make this case - expensive so that the caller won't pick it. */ + if (plen != NULL && UNKNOWN != code_sat) + { + /* This belongs to the x + 0x80 corner case. The code with + ADD instruction is not smaller, thus make this case + expensive so that the caller won't pick it. */ - *plen += 10; - break; - } + *plen += 10; + break; + } - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len (started ? "adc %0,%2" : "add %0,%2", op, plen, 1); + avr_asm_len (started ? "adc %0,%2" : "add %0,%2", op, plen, 1); - break; /* PLUS */ + break; /* PLUS */ - case MINUS: + case MINUS: - if (ld_reg_p) - avr_asm_len (started ? "sbci %0,%1" : "subi %0,%1", op, plen, 1); - else - { - gcc_assert (plen != NULL || REG_P (op[2])); + if (ld_reg_p) + avr_asm_len (started ? "sbci %0,%1" : "subi %0,%1", op, plen, 1); + else + { + gcc_assert (plen != NULL || REG_P (op[2])); - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len (started ? "sbc %0,%2" : "sub %0,%2", op, plen, 1); - } + avr_asm_len (started ? "sbc %0,%2" : "sub %0,%2", op, plen, 1); + } - break; /* MINUS */ + break; /* MINUS */ - default: - /* Unknown code */ - gcc_unreachable(); - } + default: + /* Unknown code */ + gcc_unreachable(); + } started = true; @@ -8338,86 +8338,86 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, case SS_MINUS: if (out_brvc) - avr_asm_len ("brvc 0f", op, plen, 1); + avr_asm_len ("brvc 0f", op, plen, 1); if (reg_overlap_mentioned_p (xop[0], xop[2])) - { - /* [1s,reg] */ - - if (n_bytes == 1) - avr_asm_len ("ldi %0,0x7f" CR_TAB - "adc %0,__zero_reg__", op, plen, 2); - else - avr_asm_len ("ldi %0,0x7f" CR_TAB - "ldi %1,0xff" CR_TAB - "adc %1,__zero_reg__" CR_TAB - "adc %0,__zero_reg__", op, plen, 4); - } + { + /* [1s,reg] */ + + if (n_bytes == 1) + avr_asm_len ("ldi %0,0x7f" CR_TAB + "adc %0,__zero_reg__", op, plen, 2); + else + avr_asm_len ("ldi %0,0x7f" CR_TAB + "ldi %1,0xff" CR_TAB + "adc %1,__zero_reg__" CR_TAB + "adc %0,__zero_reg__", op, plen, 4); + } else if (sign == 0 && PLUS == code) - { - /* [1s,reg] */ - - op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); - - if (n_bytes == 1) - avr_asm_len ("ldi %0,0x80" CR_TAB - "sbrs %2,7" CR_TAB - "dec %0", op, plen, 3); - else - avr_asm_len ("ldi %0,0x80" CR_TAB - "cp %2,%0" CR_TAB - "sbc %1,%1" CR_TAB - "sbci %0,0", op, plen, 4); - } + { + /* [1s,reg] */ + + op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); + + if (n_bytes == 1) + avr_asm_len ("ldi %0,0x80" CR_TAB + "sbrs %2,7" CR_TAB + "dec %0", op, plen, 3); + else + avr_asm_len ("ldi %0,0x80" CR_TAB + "cp %2,%0" CR_TAB + "sbc %1,%1" CR_TAB + "sbci %0,0", op, plen, 4); + } else if (sign == 0 && MINUS == code) - { - /* [3s,reg] */ - - op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); - - if (n_bytes == 1) - avr_asm_len ("ldi %0,0x7f" CR_TAB - "sbrs %2,7" CR_TAB - "inc %0", op, plen, 3); - else - avr_asm_len ("ldi %0,0x7f" CR_TAB - "cp %0,%2" CR_TAB - "sbc %1,%1" CR_TAB - "sbci %0,-1", op, plen, 4); - } + { + /* [3s,reg] */ + + op[2] = simplify_gen_subreg (QImode, xop[2], mode, n_bytes-1); + + if (n_bytes == 1) + avr_asm_len ("ldi %0,0x7f" CR_TAB + "sbrs %2,7" CR_TAB + "inc %0", op, plen, 3); + else + avr_asm_len ("ldi %0,0x7f" CR_TAB + "cp %0,%2" CR_TAB + "sbc %1,%1" CR_TAB + "sbci %0,-1", op, plen, 4); + } else if ((sign < 0) ^ (SS_MINUS == code_sat)) - { - /* [1s,const,B < 0] [2s,B < 0] */ - /* [3s,const,B > 0] [4s,B > 0] */ - - if (n_bytes == 8) - { - avr_asm_len ("%~call __clr_8", op, plen, len_call); - need_copy = false; - } - - avr_asm_len ("ldi %0,0x80", op, plen, 1); - if (n_bytes > 1 && need_copy) - avr_asm_len ("clr %1", op, plen, 1); - } + { + /* [1s,const,B < 0] [2s,B < 0] */ + /* [3s,const,B > 0] [4s,B > 0] */ + + if (n_bytes == 8) + { + avr_asm_len ("%~call __clr_8", op, plen, len_call); + need_copy = false; + } + + avr_asm_len ("ldi %0,0x80", op, plen, 1); + if (n_bytes > 1 && need_copy) + avr_asm_len ("clr %1", op, plen, 1); + } else if ((sign > 0) ^ (SS_MINUS == code_sat)) - { - /* [1s,const,B > 0] [2s,B > 0] */ - /* [3s,const,B < 0] [4s,B < 0] */ - - if (n_bytes == 8) - { - avr_asm_len ("sec" CR_TAB - "%~call __sbc_8", op, plen, 1 + len_call); - need_copy = false; - } - - avr_asm_len ("ldi %0,0x7f", op, plen, 1); - if (n_bytes > 1 && need_copy) - avr_asm_len ("ldi %1,0xff", op, plen, 1); - } + { + /* [1s,const,B > 0] [2s,B > 0] */ + /* [3s,const,B < 0] [4s,B < 0] */ + + if (n_bytes == 8) + { + avr_asm_len ("sec" CR_TAB + "%~call __sbc_8", op, plen, 1 + len_call); + need_copy = false; + } + + avr_asm_len ("ldi %0,0x7f", op, plen, 1); + if (n_bytes > 1 && need_copy) + avr_asm_len ("ldi %1,0xff", op, plen, 1); + } else - gcc_unreachable(); + gcc_unreachable(); break; @@ -8427,22 +8427,22 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, avr_asm_len (PLUS == code ? "brcc 0f" : "brcs 0f", op, plen, 1); if (n_bytes == 8) - { - if (MINUS == code) - avr_asm_len ("sec", op, plen, 1); - avr_asm_len ("%~call __sbc_8", op, plen, len_call); + { + if (MINUS == code) + avr_asm_len ("sec", op, plen, 1); + avr_asm_len ("%~call __sbc_8", op, plen, len_call); - need_copy = false; - } + need_copy = false; + } else - { - if (MINUS == code && !test_hard_reg_class (LD_REGS, op[0])) - avr_asm_len ("sec" CR_TAB - "sbc %0,%0", op, plen, 2); - else - avr_asm_len (PLUS == code ? "sbc %0,%0" : "ldi %0,0xff", - op, plen, 1); - } + { + if (MINUS == code && !test_hard_reg_class (LD_REGS, op[0])) + avr_asm_len ("sec" CR_TAB + "sbc %0,%0", op, plen, 2); + else + avr_asm_len (PLUS == code ? "sbc %0,%0" : "ldi %0,0xff", + op, plen, 1); + } break; /* US_PLUS */ case US_MINUS: @@ -8451,12 +8451,12 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, avr_asm_len (PLUS == code ? "brcs 0f" : "brcc 0f", op, plen, 1); if (n_bytes == 8) - { - avr_asm_len ("%~call __clr_8", op, plen, len_call); - need_copy = false; - } + { + avr_asm_len ("%~call __clr_8", op, plen, len_call); + need_copy = false; + } else - avr_asm_len ("clr %0", op, plen, 1); + avr_asm_len ("clr %0", op, plen, 1); break; } @@ -8467,37 +8467,37 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, if (need_copy && n_bytes > 1) { if (US_MINUS == code_sat || US_PLUS == code_sat) - { - avr_asm_len ("mov %1,%0", op, plen, 1); - - if (n_bytes > 2) - { - op[0] = xop[0]; - if (AVR_HAVE_MOVW) - avr_asm_len ("movw %0,%1", op, plen, 1); - else - avr_asm_len ("mov %A0,%1" CR_TAB - "mov %B0,%1", op, plen, 2); - } - } + { + avr_asm_len ("mov %1,%0", op, plen, 1); + + if (n_bytes > 2) + { + op[0] = xop[0]; + if (AVR_HAVE_MOVW) + avr_asm_len ("movw %0,%1", op, plen, 1); + else + avr_asm_len ("mov %A0,%1" CR_TAB + "mov %B0,%1", op, plen, 2); + } + } else if (n_bytes > 2) - { - op[0] = xop[0]; - avr_asm_len ("mov %A0,%1" CR_TAB - "mov %B0,%1", op, plen, 2); - } + { + op[0] = xop[0]; + avr_asm_len ("mov %A0,%1" CR_TAB + "mov %B0,%1", op, plen, 2); + } } if (need_copy && n_bytes == 8) { if (AVR_HAVE_MOVW) - avr_asm_len ("movw %r0+2,%0" CR_TAB - "movw %r0+4,%0", xop, plen, 2); + avr_asm_len ("movw %r0+2,%0" CR_TAB + "movw %r0+4,%0", xop, plen, 2); else - avr_asm_len ("mov %r0+2,%0" CR_TAB - "mov %r0+3,%0" CR_TAB - "mov %r0+4,%0" CR_TAB - "mov %r0+5,%0", xop, plen, 4); + avr_asm_len ("mov %r0+2,%0" CR_TAB + "mov %r0+3,%0" CR_TAB + "mov %r0+4,%0" CR_TAB + "mov %r0+5,%0", xop, plen, 4); } if (out_label) @@ -8513,7 +8513,7 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc, This is a helper for the function below. The only insns that need this are additions/subtraction for pointer modes, i.e. HImode and PSImode. */ -static const char* +static const char * avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc) { machine_mode mode = GET_MODE (xop[0]); @@ -8525,14 +8525,14 @@ avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc) *pcc = MINUS == code ? (int) CC_SET_CZN : (int) CC_SET_N; avr_asm_len (PLUS == code - ? "subi %A0,lo8(-(%2))" CR_TAB "sbci %B0,hi8(-(%2))" - : "subi %A0,lo8(%2)" CR_TAB "sbci %B0,hi8(%2)", - xop, plen, -2); + ? "subi %A0,lo8(-(%2))" CR_TAB "sbci %B0,hi8(-(%2))" + : "subi %A0,lo8(%2)" CR_TAB "sbci %B0,hi8(%2)", + xop, plen, -2); if (PSImode == mode) avr_asm_len (PLUS == code - ? "sbci %C0,hlo8(-(%2))" - : "sbci %C0,hlo8(%2)", xop, plen, 1); + ? "sbci %C0,hlo8(-(%2))" + : "sbci %C0,hlo8(%2)", xop, plen, 1); return ""; } @@ -8559,7 +8559,7 @@ avr_out_plus_symbol (rtx *xop, enum rtx_code code, int *plen, int *pcc) Return "" */ -const char* +const char * avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc, bool out_label) { int cc_plus, cc_minus, cc_dummy; @@ -8598,11 +8598,11 @@ avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc, bool out_label) else { if (!REG_P (xop[2]) - && !CONST_INT_P (xop[2]) - && !CONST_FIXED_P (xop[2])) - { - return avr_out_plus_symbol (xop, code, plen, pcc); - } + && !CONST_INT_P (xop[2]) + && !CONST_FIXED_P (xop[2])) + { + return avr_out_plus_symbol (xop, code, plen, pcc); + } op[0] = avr_to_int_mode (xop[0]); op[1] = avr_to_int_mode (xop[1]); @@ -8653,7 +8653,7 @@ avr_out_plus (rtx insn, rtx *xop, int *plen, int *pcc, bool out_label) If PLEN == NULL, then output the instructions. If PLEN != NULL, then set *PLEN to the length of the sequence in words. */ -const char* +const char * avr_out_plus_set_ZN (rtx *xop, int *plen) { if (plen) @@ -8772,7 +8772,7 @@ avr_out_plus_set_ZN (rtx *xop, int *plen) register or SCRATCH if no clobber register is needed for the operation. INSN is an INSN_P or a pattern of an insn. */ -const char* +const char * avr_out_bitop (rtx insn, rtx *xop, int *plen) { /* CODE and MODE of the operation. */ @@ -8820,94 +8820,94 @@ avr_out_bitop (rtx insn, rtx *xop, int *plen) op[1] = GEN_INT (val8); switch (code) - { - case IOR: + { + case IOR: if (pop8 == 0) - continue; - else if (ld_reg_p) - avr_asm_len ("ori %0,%1", op, plen, 1); + continue; + else if (ld_reg_p) + avr_asm_len ("ori %0,%1", op, plen, 1); else if (pop8 == 1) - { - if (set_t != 1) - avr_asm_len ("set", op, plen, 1); - set_t = 1; - - op[1] = GEN_INT (exact_log2 (val8)); - avr_asm_len ("bld %0,%1", op, plen, 1); - } + { + if (set_t != 1) + avr_asm_len ("set", op, plen, 1); + set_t = 1; + + op[1] = GEN_INT (exact_log2 (val8)); + avr_asm_len ("bld %0,%1", op, plen, 1); + } else if (pop8 == 8) - { - if (op[3] != NULL_RTX) - avr_asm_len ("mov %0,%3", op, plen, 1); - else - avr_asm_len ("clr %0" CR_TAB - "dec %0", op, plen, 2); + { + if (op[3] != NULL_RTX) + avr_asm_len ("mov %0,%3", op, plen, 1); + else + avr_asm_len ("clr %0" CR_TAB + "dec %0", op, plen, 2); - op[3] = op[0]; - } - else - { - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + op[3] = op[0]; + } + else + { + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len ("or %0,%2", op, plen, 1); - } + avr_asm_len ("or %0,%2", op, plen, 1); + } - continue; /* IOR */ + continue; /* IOR */ - case AND: + case AND: if (pop8 == 8) - continue; + continue; else if (pop8 == 0) - avr_asm_len ("clr %0", op, plen, 1); - else if (ld_reg_p) - avr_asm_len ("andi %0,%1", op, plen, 1); + avr_asm_len ("clr %0", op, plen, 1); + else if (ld_reg_p) + avr_asm_len ("andi %0,%1", op, plen, 1); else if (pop8 == 7) - { - if (set_t != 0) - avr_asm_len ("clt", op, plen, 1); - set_t = 0; + { + if (set_t != 0) + avr_asm_len ("clt", op, plen, 1); + set_t = 0; - op[1] = GEN_INT (exact_log2 (GET_MODE_MASK (QImode) & ~val8)); - avr_asm_len ("bld %0,%1", op, plen, 1); - } - else - { - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; + op[1] = GEN_INT (exact_log2 (GET_MODE_MASK (QImode) & ~val8)); + avr_asm_len ("bld %0,%1", op, plen, 1); + } + else + { + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; - avr_asm_len ("and %0,%2", op, plen, 1); - } + avr_asm_len ("and %0,%2", op, plen, 1); + } - continue; /* AND */ + continue; /* AND */ - case XOR: + case XOR: if (pop8 == 0) - continue; + continue; else if (pop8 == 8) - avr_asm_len ("com %0", op, plen, 1); - else if (ld_reg_p && val8 == (1 << 7)) - avr_asm_len ("subi %0,%1", op, plen, 1); - else - { - if (clobber_val != (int) val8) - avr_asm_len ("ldi %2,%1", op, plen, 1); - clobber_val = (int) val8; - - avr_asm_len ("eor %0,%2", op, plen, 1); - } - - continue; /* XOR */ - - default: - /* Unknown rtx_code */ - gcc_unreachable(); - } + avr_asm_len ("com %0", op, plen, 1); + else if (ld_reg_p && val8 == (1 << 7)) + avr_asm_len ("subi %0,%1", op, plen, 1); + else + { + if (clobber_val != (int) val8) + avr_asm_len ("ldi %2,%1", op, plen, 1); + clobber_val = (int) val8; + + avr_asm_len ("eor %0,%2", op, plen, 1); + } + + continue; /* XOR */ + + default: + /* Unknown rtx_code */ + gcc_unreachable(); + } } /* for all sub-bytes */ return ""; @@ -8919,7 +8919,7 @@ avr_out_bitop (rtx insn, rtx *xop, int *plen) otherwise, set *PLEN to the length of the instruction sequence (in words) as printed with PLEN == NULL. */ -const char* +const char * avr_out_sign_extend (rtx_insn *insn, rtx *xop, int *plen) { // Size in bytes of source resp. destination operand. @@ -8937,11 +8937,11 @@ avr_out_sign_extend (rtx_insn *insn, rtx *xop, int *plen) gcc_assert (n_src <= 2); if (n_src == 2) - avr_asm_len (AVR_HAVE_MOVW - ? "movw %0,%1" - : "mov %B0,%B1", xop, plen, 1); + avr_asm_len (AVR_HAVE_MOVW + ? "movw %0,%1" + : "mov %B0,%B1", xop, plen, 1); if (n_src == 1 || !AVR_HAVE_MOVW) - avr_asm_len ("mov %A0,%A1", xop, plen, 1); + avr_asm_len ("mov %A0,%A1", xop, plen, 1); } // Set Carry to the sign bit MSB.7... @@ -8968,7 +8968,7 @@ avr_out_sign_extend (rtx_insn *insn, rtx *xop, int *plen) PLEN != NULL: Set *PLEN to the length of that sequence. Return "". */ -const char* +const char * avr_out_addto_sp (rtx *op, int *plen) { int pc_len = AVR_2_BYTE_PC ? 2 : 3; @@ -8980,24 +8980,24 @@ avr_out_addto_sp (rtx *op, int *plen) if (addend < 0) { if (flag_verbose_asm || flag_print_asm_name) - avr_asm_len (ASM_COMMENT_START "SP -= %n0", op, plen, 0); + avr_asm_len (ASM_COMMENT_START "SP -= %n0", op, plen, 0); while (addend <= -pc_len) - { - addend += pc_len; - avr_asm_len ("rcall .", op, plen, 1); - } + { + addend += pc_len; + avr_asm_len ("rcall .", op, plen, 1); + } while (addend++ < 0) - avr_asm_len ("push __tmp_reg__", op, plen, 1); + avr_asm_len ("push __tmp_reg__", op, plen, 1); } else if (addend > 0) { if (flag_verbose_asm || flag_print_asm_name) - avr_asm_len (ASM_COMMENT_START "SP += %0", op, plen, 0); + avr_asm_len (ASM_COMMENT_START "SP += %0", op, plen, 0); while (addend-- > 0) - avr_asm_len ("pop __tmp_reg__", op, plen, 1); + avr_asm_len ("pop __tmp_reg__", op, plen, 1); } return ""; @@ -9010,57 +9010,57 @@ avr_out_addto_sp (rtx *op, int *plen) If PLEN != NULL then store the length of the sequence (in words) in *PLEN. Return "". */ -const char* +const char * avr_out_insert_notbit (rtx_insn *insn, rtx op[], int *plen) { if (INTVAL (op[1]) == 7 && test_hard_reg_class (LD_REGS, op[0])) { /* If the inserted bit number is 7 and we have a d-reg, then invert - the bit after the insertion by means of SUBI *,0x80. */ + the bit after the insertion by means of SUBI *,0x80. */ if (INTVAL (op[3]) == 7 - && REGNO (op[0]) == REGNO (op[2])) - { - avr_asm_len ("subi %0,0x80", op, plen, -1); - } + && REGNO (op[0]) == REGNO (op[2])) + { + avr_asm_len ("subi %0,0x80", op, plen, -1); + } else - { - avr_asm_len ("bst %2,%3" CR_TAB - "bld %0,%1" CR_TAB - "subi %0,0x80", op, plen, -3); - } + { + avr_asm_len ("bst %2,%3" CR_TAB + "bld %0,%1" CR_TAB + "subi %0,0x80", op, plen, -3); + } } else if (test_hard_reg_class (LD_REGS, op[0]) - && (INTVAL (op[1]) != INTVAL (op[3]) - || !reg_overlap_mentioned_p (op[0], op[2]))) + && (INTVAL (op[1]) != INTVAL (op[3]) + || !reg_overlap_mentioned_p (op[0], op[2]))) { /* If the destination bit is in a d-reg we can jump depending - on the source bit and use ANDI / ORI. This just applies if we - have not an early-clobber situation with the bit. */ + on the source bit and use ANDI / ORI. This just applies if we + have not an early-clobber situation with the bit. */ avr_asm_len ("andi %0,~(1<<%1)" CR_TAB - "sbrs %2,%3" CR_TAB - "ori %0,1<<%1", op, plen, -3); + "sbrs %2,%3" CR_TAB + "ori %0,1<<%1", op, plen, -3); } else { /* Otherwise, invert the bit by means of COM before we store it with - BST and then undo the COM if needed. */ + BST and then undo the COM if needed. */ avr_asm_len ("com %2" CR_TAB - "bst %2,%3", op, plen, -2); + "bst %2,%3", op, plen, -2); if (!reg_unused_after (insn, op[2]) - // A simple 'reg_unused_after' is not enough because that function - // assumes that the destination register is overwritten completely - // and hence is in order for our purpose. This is not the case - // with BLD which just changes one bit of the destination. - || reg_overlap_mentioned_p (op[0], op[2])) - { - /* Undo the COM from above. */ - avr_asm_len ("com %2", op, plen, 1); - } + // A simple 'reg_unused_after' is not enough because that function + // assumes that the destination register is overwritten completely + // and hence is in order for our purpose. This is not the case + // with BLD which just changes one bit of the destination. + || reg_overlap_mentioned_p (op[0], op[2])) + { + /* Undo the COM from above. */ + avr_asm_len ("com %2", op, plen, 1); + } avr_asm_len ("bld %0,%1", op, plen, 1); } @@ -9076,7 +9076,7 @@ avr_out_insert_notbit (rtx_insn *insn, rtx op[], int *plen) PLEN != 0: Set *PLEN to the code length in words. Don't output anything. PLEN == 0: Output instructions. */ -const char* +const char * avr_out_extr (rtx_insn *insn, rtx xop[], int *plen) { rtx dest = xop[0]; @@ -9143,8 +9143,8 @@ avr_out_extr (rtx_insn *insn, rtx xop[], int *plen) PLEN != 0: Set *PLEN to the code length in words. Don't output anything. PLEN == 0: Output instructions. */ -const char* -avr_out_extr_not (rtx_insn* /* insn */, rtx xop[], int *plen) +const char * +avr_out_extr_not (rtx_insn * /* insn */, rtx xop[], int *plen) { rtx dest = xop[0]; rtx src = xop[1]; @@ -9208,7 +9208,7 @@ avr_out_extr_not (rtx_insn* /* insn */, rtx xop[], int *plen) shifted by 1 bit. When the destination is a signed fractional, the sign is stored in either the carry or T bit. */ -const char* +const char * avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) { rtx xop[6]; @@ -9259,17 +9259,17 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) val[i]->regno_msb = REGNO (xop[i]) + val[i]->bytes - 1; if (SCALAR_INT_MODE_P (mode)) - { - val[i]->sbit = intsigned; - val[i]->fbit = 0; - } + { + val[i]->sbit = intsigned; + val[i]->fbit = 0; + } else if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) - { - val[i]->sbit = SIGNED_SCALAR_FIXED_POINT_MODE_P (mode); - val[i]->fbit = GET_MODE_FBIT (mode); - } + { + val[i]->sbit = SIGNED_SCALAR_FIXED_POINT_MODE_P (mode); + val[i]->fbit = GET_MODE_FBIT (mode); + } else - fatal_insn ("unsupported fixed-point conversion", insn); + fatal_insn ("unsupported fixed-point conversion", insn); val[i]->fbyte = (1 + val[i]->fbit) / BITS_PER_UNIT; val[i]->ibyte = val[i]->bytes - val[i]->fbyte; @@ -9308,9 +9308,9 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) && !TARGET_FRACT_CONV_TRUNC) { bool overlap - = (src.regno <= - (offset ? dest.regno_msb - sign_bytes : dest.regno + zero_bytes - 1) - && dest.regno - offset -1 >= dest.regno); + = (src.regno <= + (offset ? dest.regno_msb - sign_bytes : dest.regno + zero_bytes - 1) + && dest.regno - offset -1 >= dest.regno); unsigned s0 = dest.regno - offset -1; bool use_src = true; unsigned sn; @@ -9318,103 +9318,103 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) bool have_carry = false; if (src.ibyte > dest.ibyte) - copied_msb -= src.ibyte - dest.ibyte; + copied_msb -= src.ibyte - dest.ibyte; for (sn = s0; sn <= copied_msb; sn++) - if (!IN_RANGE (sn, dest.regno, dest.regno_msb) - && !reg_unused_after (insn, all_regs_rtx[sn])) - use_src = false; + if (!IN_RANGE (sn, dest.regno, dest.regno_msb) + && !reg_unused_after (insn, all_regs_rtx[sn])) + use_src = false; if (use_src && TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0)) - { - avr_asm_len ("tst %0" CR_TAB "brpl 0f", - &all_regs_rtx[src.regno_msb], plen, 2); - sn = src.regno; - if (sn < s0) - { - if (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], sn)) - avr_asm_len ("cpi %0,1", &all_regs_rtx[sn], plen, 1); - else - avr_asm_len ("sec" CR_TAB - "cpc %0,__zero_reg__", - &all_regs_rtx[sn], plen, 2); - have_carry = true; - } - while (++sn < s0) - avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - - avr_asm_len (have_carry ? "sbci %0,128" : "subi %0,129", - &all_regs_rtx[s0], plen, 1); - for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) - avr_asm_len ("sbci %0,255", &all_regs_rtx[sn], plen, 1); - avr_asm_len ("\n0:", NULL, plen, 0); - frac_rounded = true; - } + { + avr_asm_len ("tst %0" CR_TAB "brpl 0f", + &all_regs_rtx[src.regno_msb], plen, 2); + sn = src.regno; + if (sn < s0) + { + if (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], sn)) + avr_asm_len ("cpi %0,1", &all_regs_rtx[sn], plen, 1); + else + avr_asm_len ("sec" CR_TAB + "cpc %0,__zero_reg__", + &all_regs_rtx[sn], plen, 2); + have_carry = true; + } + while (++sn < s0) + avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + + avr_asm_len (have_carry ? "sbci %0,128" : "subi %0,129", + &all_regs_rtx[s0], plen, 1); + for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) + avr_asm_len ("sbci %0,255", &all_regs_rtx[sn], plen, 1); + avr_asm_len ("\n0:", NULL, plen, 0); + frac_rounded = true; + } else if (use_src && overlap) - { - avr_asm_len ("clr __tmp_reg__" CR_TAB - "sbrc %1,0" CR_TAB - "dec __tmp_reg__", xop, plen, 1); - sn = src.regno; - if (sn < s0) - { - avr_asm_len ("add %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); - have_carry = true; - } - - while (++sn < s0) - avr_asm_len ("adc %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); - - if (have_carry) - avr_asm_len ("clt" CR_TAB - "bld __tmp_reg__,7" CR_TAB - "adc %0,__tmp_reg__", - &all_regs_rtx[s0], plen, 1); - else - avr_asm_len ("lsr __tmp_reg" CR_TAB - "add %0,__tmp_reg__", - &all_regs_rtx[s0], plen, 2); - for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) - avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - frac_rounded = true; - } + { + avr_asm_len ("clr __tmp_reg__" CR_TAB + "sbrc %1,0" CR_TAB + "dec __tmp_reg__", xop, plen, 1); + sn = src.regno; + if (sn < s0) + { + avr_asm_len ("add %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); + have_carry = true; + } + + while (++sn < s0) + avr_asm_len ("adc %0,__tmp_reg__", &all_regs_rtx[sn], plen, 1); + + if (have_carry) + avr_asm_len ("clt" CR_TAB + "bld __tmp_reg__,7" CR_TAB + "adc %0,__tmp_reg__", + &all_regs_rtx[s0], plen, 1); + else + avr_asm_len ("lsr __tmp_reg" CR_TAB + "add %0,__tmp_reg__", + &all_regs_rtx[s0], plen, 2); + for (sn = src.regno + src.fbyte; sn <= copied_msb; sn++) + avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + frac_rounded = true; + } else if (overlap) - { - bool use_src - = (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0) - && (IN_RANGE (s0, dest.regno, dest.regno_msb) - || reg_unused_after (insn, all_regs_rtx[s0]))); - xop[2] = all_regs_rtx[s0]; - unsigned sn = src.regno; - if (!use_src || sn == s0) - avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1); - /* We need to consider to-be-discarded bits - if the value is negative. */ - if (sn < s0) - { - avr_asm_len ("tst %0" CR_TAB - "brpl 0f", - &all_regs_rtx[src.regno_msb], plen, 2); - /* Test to-be-discarded bytes for any nozero bits. - ??? Could use OR or SBIW to test two registers at once. */ - if (sn < s0) - avr_asm_len ("cp %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - - while (++sn < s0) - avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); - /* Set bit 0 in __tmp_reg__ if any of the lower bits was set. */ - if (use_src) - avr_asm_len ("breq 0f" CR_TAB - "ori %2,1" - "\n0:\t" "mov __tmp_reg__,%2", - xop, plen, 3); - else - avr_asm_len ("breq 0f" CR_TAB - "set" CR_TAB - "bld __tmp_reg__,0\n0:", - xop, plen, 3); - } - lsb_in_tmp_reg = true; - } + { + bool use_src + = (TEST_HARD_REG_BIT (reg_class_contents[LD_REGS], s0) + && (IN_RANGE (s0, dest.regno, dest.regno_msb) + || reg_unused_after (insn, all_regs_rtx[s0]))); + xop[2] = all_regs_rtx[s0]; + unsigned sn = src.regno; + if (!use_src || sn == s0) + avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1); + /* We need to consider to-be-discarded bits + if the value is negative. */ + if (sn < s0) + { + avr_asm_len ("tst %0" CR_TAB + "brpl 0f", + &all_regs_rtx[src.regno_msb], plen, 2); + /* Test to-be-discarded bytes for any nozero bits. + ??? Could use OR or SBIW to test two registers at once. */ + if (sn < s0) + avr_asm_len ("cp %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + + while (++sn < s0) + avr_asm_len ("cpc %0,__zero_reg__", &all_regs_rtx[sn], plen, 1); + /* Set bit 0 in __tmp_reg__ if any of the lower bits was set. */ + if (use_src) + avr_asm_len ("breq 0f" CR_TAB + "ori %2,1" + "\n0:\t" "mov __tmp_reg__,%2", + xop, plen, 3); + else + avr_asm_len ("breq 0f" CR_TAB + "set" CR_TAB + "bld __tmp_reg__,0\n0:", + xop, plen, 3); + } + lsb_in_tmp_reg = true; + } } /* Step 1: Clear bytes at the low end and copy payload bits from source @@ -9447,85 +9447,85 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) int stepw = 0; if (clr0) - { - if (AVR_HAVE_MOVW && clr1 && clrw) - { - xop[2] = all_regs_rtx[d0 & ~1]; - xop[3] = clrw; - code = "movw %2,%3"; - stepw = step; - } - else - { - xop[2] = all_regs_rtx[d0]; - code = "clr %2"; - - if (++clr_n >= 2 - && !clrw - && d0 % 2 == (step > 0)) - { - clrw = all_regs_rtx[d0 & ~1]; - } - } - } + { + if (AVR_HAVE_MOVW && clr1 && clrw) + { + xop[2] = all_regs_rtx[d0 & ~1]; + xop[3] = clrw; + code = "movw %2,%3"; + stepw = step; + } + else + { + xop[2] = all_regs_rtx[d0]; + code = "clr %2"; + + if (++clr_n >= 2 + && !clrw + && d0 % 2 == (step > 0)) + { + clrw = all_regs_rtx[d0 & ~1]; + } + } + } else if (offset && s0 <= (signed) src.regno_msb) - { - int movw = AVR_HAVE_MOVW && offset % 2 == 0 - && d0 % 2 == (offset > 0) - && d1 <= dest.regno_msb && d1 >= dest.regno - && s1 <= (signed) src.regno_msb && s1 >= (signed) src.regno; - - xop[2] = all_regs_rtx[d0 & ~movw]; - xop[3] = all_regs_rtx[s0 & ~movw]; - code = movw ? "movw %2,%3" : "mov %2,%3"; - stepw = step * movw; - } + { + int movw = AVR_HAVE_MOVW && offset % 2 == 0 + && d0 % 2 == (offset > 0) + && d1 <= dest.regno_msb && d1 >= dest.regno + && s1 <= (signed) src.regno_msb && s1 >= (signed) src.regno; + + xop[2] = all_regs_rtx[d0 & ~movw]; + xop[3] = all_regs_rtx[s0 & ~movw]; + code = movw ? "movw %2,%3" : "mov %2,%3"; + stepw = step * movw; + } if (code) - { - if (sign_extend && shift != ASHIFT && !sign_in_carry - && (d0 == src.regno_msb || d0 + stepw == src.regno_msb)) - { - /* We are going to override the sign bit. If we sign-extend, - store the sign in the Carry flag. This is not needed if - the destination will be ASHIFT in the remainder because - the ASHIFT will set Carry without extra instruction. */ - - avr_asm_len ("lsl %0", &all_regs_rtx[src.regno_msb], plen, 1); - sign_in_carry = true; - } - - unsigned src_msb = dest.regno_msb - sign_bytes - offset + 1; - - if (!sign_extend && shift == ASHIFTRT && !msb_in_carry - && src.ibyte > dest.ibyte - && (d0 == src_msb || d0 + stepw == src_msb)) - { - /* We are going to override the MSB. If we shift right, - store the MSB in the Carry flag. This is only needed if - we don't sign-extend becaue with sign-extension the MSB - (the sign) will be produced by the sign extension. */ - - avr_asm_len ("lsr %0", &all_regs_rtx[src_msb], plen, 1); - msb_in_carry = true; - } - - unsigned src_lsb = dest.regno - offset -1; - - if (shift == ASHIFT && src.fbyte > dest.fbyte && !lsb_in_carry + { + if (sign_extend && shift != ASHIFT && !sign_in_carry + && (d0 == src.regno_msb || d0 + stepw == src.regno_msb)) + { + /* We are going to override the sign bit. If we sign-extend, + store the sign in the Carry flag. This is not needed if + the destination will be ASHIFT in the remainder because + the ASHIFT will set Carry without extra instruction. */ + + avr_asm_len ("lsl %0", &all_regs_rtx[src.regno_msb], plen, 1); + sign_in_carry = true; + } + + unsigned src_msb = dest.regno_msb - sign_bytes - offset + 1; + + if (!sign_extend && shift == ASHIFTRT && !msb_in_carry + && src.ibyte > dest.ibyte + && (d0 == src_msb || d0 + stepw == src_msb)) + { + /* We are going to override the MSB. If we shift right, + store the MSB in the Carry flag. This is only needed if + we don't sign-extend becaue with sign-extension the MSB + (the sign) will be produced by the sign extension. */ + + avr_asm_len ("lsr %0", &all_regs_rtx[src_msb], plen, 1); + msb_in_carry = true; + } + + unsigned src_lsb = dest.regno - offset -1; + + if (shift == ASHIFT && src.fbyte > dest.fbyte && !lsb_in_carry && !lsb_in_tmp_reg - && (d0 == src_lsb || d0 + stepw == src_lsb)) - { - /* We are going to override the new LSB; store it into carry. */ + && (d0 == src_lsb || d0 + stepw == src_lsb)) + { + /* We are going to override the new LSB; store it into carry. */ - avr_asm_len ("lsl %0", &all_regs_rtx[src_lsb], plen, 1); - code_ashift = "rol %0"; - lsb_in_carry = true; - } + avr_asm_len ("lsl %0", &all_regs_rtx[src_lsb], plen, 1); + code_ashift = "rol %0"; + lsb_in_carry = true; + } - avr_asm_len (code, xop, plen, 1); - d0 += stepw; - } + avr_asm_len (code, xop, plen, 1); + d0 += stepw; + } } /* Step 2: Shift destination left by 1 bit position. This might be needed @@ -9553,7 +9553,7 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) /* Overflow goes with set carry. Clear carry otherwise. */ avr_asm_len ("brvs 0f" CR_TAB - "clc\n0:", NULL, plen, 2); + "clc\n0:", NULL, plen, 2); } /* Likewise, when converting from accumulator types to integer, we need to round up negative values. */ @@ -9603,32 +9603,32 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) avr_asm_len ("dec __zero_reg__", NULL, plen, 1); if (have_carry) avr_asm_len ("clt" CR_TAB - "bld __zero_reg__,7", NULL, plen, 2); + "bld __zero_reg__,7", NULL, plen, 2); else avr_asm_len ("lsr __zero_reg__", NULL, plen, 1); avr_asm_len (have_carry && lsb_in_tmp_reg - ? "adc __tmp_reg__,__zero_reg__" - : have_carry ? "adc %2,__zero_reg__" - : lsb_in_tmp_reg ? "add __tmp_reg__,__zero_reg__" - : "add %2,__zero_reg__", + ? "adc __tmp_reg__,__zero_reg__" + : have_carry ? "adc %2,__zero_reg__" + : lsb_in_tmp_reg ? "add __tmp_reg__,__zero_reg__" + : "add %2,__zero_reg__", xop, plen, 1); avr_asm_len ("eor __zero_reg__,__zero_reg__", NULL, plen, 1); } - for (d0 = dest.regno + zero_bytes; + for (d0 = dest.regno + zero_bytes; d0 <= dest.regno_msb - sign_bytes; d0++) avr_asm_len ("adc %0,__zero_reg__", &all_regs_rtx[d0], plen, 1); - avr_asm_len (lsb_in_tmp_reg + avr_asm_len (lsb_in_tmp_reg ? "\n0:\t" "lsl __tmp_reg__" - : "\n0:\t" "lsl %2", + : "\n0:\t" "lsl %2", xop, plen, 1); } else if (MAY_CLOBBER (s0)) - avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); + avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); else - avr_asm_len ("mov __tmp_reg__,%0" CR_TAB - "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); + avr_asm_len ("mov __tmp_reg__,%0" CR_TAB + "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); code_ashift = "rol %0"; lsb_in_carry = true; @@ -9637,11 +9637,11 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) if (shift == ASHIFT) { for (d0 = dest.regno + zero_bytes; - d0 <= dest.regno_msb - sign_bytes; d0++) - { - avr_asm_len (code_ashift, &all_regs_rtx[d0], plen, 1); - code_ashift = "rol %0"; - } + d0 <= dest.regno_msb - sign_bytes; d0++) + { + avr_asm_len (code_ashift, &all_regs_rtx[d0], plen, 1); + code_ashift = "rol %0"; + } lsb_in_carry = false; sign_in_carry = true; @@ -9656,10 +9656,10 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) unsigned s0 = dest.regno_msb - sign_bytes - offset + 1; if (MAY_CLOBBER (s0)) - avr_asm_len ("lsr %0", &all_regs_rtx[s0], plen, 1); + avr_asm_len ("lsr %0", &all_regs_rtx[s0], plen, 1); else - avr_asm_len ("mov __tmp_reg__,%0" CR_TAB - "lsr __tmp_reg__", &all_regs_rtx[s0], plen, 2); + avr_asm_len ("mov __tmp_reg__,%0" CR_TAB + "lsr __tmp_reg__", &all_regs_rtx[s0], plen, 2); msb_in_carry = true; } @@ -9672,10 +9672,10 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) unsigned s0 = src.regno_msb; if (MAY_CLOBBER (s0)) - avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); + avr_asm_len ("lsl %0", &all_regs_rtx[s0], plen, 1); else - avr_asm_len ("mov __tmp_reg__,%0" CR_TAB - "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); + avr_asm_len ("mov __tmp_reg__,%0" CR_TAB + "lsl __tmp_reg__", &all_regs_rtx[s0], plen, 2); sign_in_carry = true; } @@ -9688,21 +9688,21 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) for (d0 = dest.regno_msb - sign_bytes + 1; d0 <= dest.regno_msb; d0++) { if (AVR_HAVE_MOVW && movw - && d0 % 2 == 0 && d0 + 1 <= dest.regno_msb) - { - xop[2] = all_regs_rtx[d0]; - xop[3] = movw; - avr_asm_len ("movw %2,%3", xop, plen, 1); - d0++; - } + && d0 % 2 == 0 && d0 + 1 <= dest.regno_msb) + { + xop[2] = all_regs_rtx[d0]; + xop[3] = movw; + avr_asm_len ("movw %2,%3", xop, plen, 1); + d0++; + } else - { - avr_asm_len (sign_extend ? "sbc %0,%0" : "clr %0", - &all_regs_rtx[d0], plen, 1); + { + avr_asm_len (sign_extend ? "sbc %0,%0" : "clr %0", + &all_regs_rtx[d0], plen, 1); - if (++copies >= 2 && !movw && d0 % 2 == 1) - movw = all_regs_rtx[d0-1]; - } + if (++copies >= 2 && !movw && d0 % 2 == 1) + movw = all_regs_rtx[d0-1]; + } } /* for */ @@ -9714,17 +9714,17 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) const char *code_ashiftrt = "lsr %0"; if (sign_extend || msb_in_carry) - code_ashiftrt = "ror %0"; + code_ashiftrt = "ror %0"; if (src.sbit && src.ibyte == dest.ibyte) - code_ashiftrt = "asr %0"; + code_ashiftrt = "asr %0"; for (d0 = dest.regno_msb - sign_bytes; - d0 >= dest.regno + zero_bytes - 1 && d0 >= dest.regno; d0--) - { - avr_asm_len (code_ashiftrt, &all_regs_rtx[d0], plen, 1); - code_ashiftrt = "ror %0"; - } + d0 >= dest.regno + zero_bytes - 1 && d0 >= dest.regno; d0--) + { + avr_asm_len (code_ashiftrt, &all_regs_rtx[d0], plen, 1); + code_ashiftrt = "ror %0"; + } } #undef MAY_CLOBBER @@ -9739,7 +9739,7 @@ avr_out_fract (rtx_insn *insn, rtx operands[], bool intsigned, int *plen) of the sequence if PLEN != NULL. Most of this function deals with preparing operands for calls to `avr_out_plus' and `avr_out_bitop'. */ -const char* +const char * avr_out_round (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *xop, int *plen) { scalar_mode mode = as_a <scalar_mode> (GET_MODE (xop[0])); @@ -9771,7 +9771,7 @@ avr_out_round (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *xop, int *plen) avr_out_plus (xpattern, op, plen_add, NULL, false /* Don't print "0:" */); avr_asm_len ("rjmp 1f" CR_TAB - "0:", NULL, plen_add, 1); + "0:", NULL, plen_add, 1); // Keep all bits from RP and higher: ... 2^(-RP) // Clear all bits from RP+1 and lower: 2^(-RP-1) ... @@ -9843,101 +9843,101 @@ avr_rotate_bytes (rtx operands[]) src = simplify_gen_subreg (move_mode, operands[1], mode, 0); dst = simplify_gen_subreg (move_mode, operands[0], mode, 1); if (!rtx_equal_p (dst, src)) - { - emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); - emit_move_insn (src, gen_rtx_XOR (QImode, src, dst)); - emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); - } + { + emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); + emit_move_insn (src, gen_rtx_XOR (QImode, src, dst)); + emit_move_insn (dst, gen_rtx_XOR (QImode, dst, src)); + } } else { #define MAX_SIZE 8 /* GET_MODE_SIZE (DImode) / GET_MODE_SIZE (QImode) */ /* Create linked list of moves to determine move order. */ struct { - rtx src, dst; - int links; + rtx src, dst; + int links; } move[MAX_SIZE + 8]; int blocked, moves; gcc_assert (size <= MAX_SIZE); /* Generate list of subreg moves. */ for (int i = 0; i < size; i++) - { - int from = i; - int to = (from + offset) % size; - move[i].src = simplify_gen_subreg (move_mode, operands[1], - mode, from * move_size); - move[i].dst = simplify_gen_subreg (move_mode, operands[0], - mode, to * move_size); - move[i].links = -1; - } + { + int from = i; + int to = (from + offset) % size; + move[i].src = simplify_gen_subreg (move_mode, operands[1], + mode, from * move_size); + move[i].dst = simplify_gen_subreg (move_mode, operands[0], + mode, to * move_size); + move[i].links = -1; + } /* Mark dependence where a dst of one move is the src of another move. - The first move is a conflict as it must wait until second is - performed. We ignore moves to self - we catch this later. */ + The first move is a conflict as it must wait until second is + performed. We ignore moves to self - we catch this later. */ if (overlapped) - for (int i = 0; i < size; i++) - if (reg_overlap_mentioned_p (move[i].dst, operands[1])) - for (int j = 0; j < size; j++) - if (j != i && rtx_equal_p (move[j].src, move[i].dst)) - { - /* The dst of move i is the src of move j. */ - move[i].links = j; - break; - } + for (int i = 0; i < size; i++) + if (reg_overlap_mentioned_p (move[i].dst, operands[1])) + for (int j = 0; j < size; j++) + if (j != i && rtx_equal_p (move[j].src, move[i].dst)) + { + /* The dst of move i is the src of move j. */ + move[i].links = j; + break; + } blocked = -1; moves = 0; /* Go through move list and perform non-conflicting moves. As each - non-overlapping move is made, it may remove other conflicts - so the process is repeated until no conflicts remain. */ + non-overlapping move is made, it may remove other conflicts + so the process is repeated until no conflicts remain. */ do - { - blocked = -1; - moves = 0; - /* Emit move where dst is not also a src or we have used that - src already. */ - for (int i = 0; i < size; i++) - if (move[i].src != NULL_RTX) - { - if (move[i].links == -1 - || move[move[i].links].src == NULL_RTX) - { - moves++; - /* Ignore NOP moves to self. */ - if (!rtx_equal_p (move[i].dst, move[i].src)) - emit_move_insn (move[i].dst, move[i].src); - - /* Remove conflict from list. */ - move[i].src = NULL_RTX; - } - else - blocked = i; - } - - /* Check for deadlock. This is when no moves occurred and we have - at least one blocked move. */ - if (moves == 0 && blocked != -1) - { - /* Need to use scratch register to break deadlock. - Add move to put dst of blocked move into scratch. - When this move occurs, it will break chain deadlock. - The scratch register is substituted for real move. */ - - gcc_assert (SCRATCH != GET_CODE (scratch)); - - move[size].src = move[blocked].dst; - move[size].dst = scratch; - /* Scratch move is never blocked. */ - move[size].links = -1; - /* Make sure we have valid link. */ - gcc_assert (move[blocked].links != -1); - /* Replace src of blocking move with scratch reg. */ - move[move[blocked].links].src = scratch; - /* Make dependent on scratch move occurring. */ - move[blocked].links = size; - size=size+1; - } - } + { + blocked = -1; + moves = 0; + /* Emit move where dst is not also a src or we have used that + src already. */ + for (int i = 0; i < size; i++) + if (move[i].src != NULL_RTX) + { + if (move[i].links == -1 + || move[move[i].links].src == NULL_RTX) + { + moves++; + /* Ignore NOP moves to self. */ + if (!rtx_equal_p (move[i].dst, move[i].src)) + emit_move_insn (move[i].dst, move[i].src); + + /* Remove conflict from list. */ + move[i].src = NULL_RTX; + } + else + blocked = i; + } + + /* Check for deadlock. This is when no moves occurred and we have + at least one blocked move. */ + if (moves == 0 && blocked != -1) + { + /* Need to use scratch register to break deadlock. + Add move to put dst of blocked move into scratch. + When this move occurs, it will break chain deadlock. + The scratch register is substituted for real move. */ + + gcc_assert (SCRATCH != GET_CODE (scratch)); + + move[size].src = move[blocked].dst; + move[size].dst = scratch; + /* Scratch move is never blocked. */ + move[size].links = -1; + /* Make sure we have valid link. */ + gcc_assert (move[blocked].links != -1); + /* Replace src of blocking move with scratch reg. */ + move[move[blocked].links].src = scratch; + /* Make dependent on scratch move occurring. */ + move[blocked].links = size; + size=size+1; + } + } while (blocked != -1); } return true; @@ -9977,7 +9977,7 @@ avr_adjust_insn_length (rtx_insn *insn, int len) if (adjust_len == ADJUST_LEN_NO) { /* Nothing to adjust: The length from attribute "length" is fine. - This is the default. */ + This is the default. */ return len; } @@ -10205,10 +10205,10 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p) /* varasm fails to handle big fixed modes that don't fit in hwi. */ for (unsigned n = 0; n < size; n++) - { - rtx xn = simplify_gen_subreg (QImode, x, GET_MODE (x), n); - default_assemble_integer (xn, 1, aligned_p); - } + { + rtx xn = simplify_gen_subreg (QImode, x, GET_MODE (x), n); + default_assemble_integer (xn, 1, aligned_p); + } return true; } @@ -10244,18 +10244,18 @@ static bool avr_class_likely_spilled_p (reg_class_t c) { return (c != ALL_REGS && - (AVR_TINY ? 1 : c != ADDW_REGS)); + (AVR_TINY ? 1 : c != ADDW_REGS)); } /* Valid attributes: - progmem - Put data to program memory. - signal - Make a function to be hardware interrupt. - After function prologue interrupts remain disabled. - interrupt - Make a function to be hardware interrupt. Before function - prologue interrupts are enabled by means of SEI. - naked - Don't generate function prologue/epilogue and RET - instruction. */ + progmem - Put data to program memory. + signal - Make a function to be hardware interrupt. + After function prologue interrupts remain disabled. + interrupt - Make a function to be hardware interrupt. Before function + prologue interrupts are enabled by means of SEI. + naked - Don't generate function prologue/epilogue and RET + instruction. */ /* Handle a "progmem" attribute; arguments as in struct attribute_spec.handler. */ @@ -10283,7 +10283,7 @@ avr_handle_progmem_attribute (tree *node, tree name, } else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node)) { - *no_add_attrs = false; + *no_add_attrs = false; } else { @@ -10317,9 +10317,9 @@ avr_handle_fndecl_attribute (tree *node, tree name, static tree avr_handle_fntype_attribute (tree *node, tree name, - tree args ATTRIBUTE_UNUSED, - int flags ATTRIBUTE_UNUSED, - bool *no_add_attrs) + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) { if (TREE_CODE (*node) != FUNCTION_TYPE) { @@ -10333,24 +10333,24 @@ avr_handle_fntype_attribute (tree *node, tree name, static tree avr_handle_absdata_attribute (tree *node, tree name, tree /* args */, - int /* flags */, bool *no_add) + int /* flags */, bool *no_add) { location_t loc = DECL_SOURCE_LOCATION (*node); if (AVR_TINY) { if (TREE_CODE (*node) != VAR_DECL - || (!TREE_STATIC (*node) && !DECL_EXTERNAL (*node))) - { - warning_at (loc, OPT_Wattributes, "%qE attribute only applies to" - " variables in static storage", name); - *no_add = true; - } + || (!TREE_STATIC (*node) && !DECL_EXTERNAL (*node))) + { + warning_at (loc, OPT_Wattributes, "%qE attribute only applies to" + " variables in static storage", name); + *no_add = true; + } } else { warning_at (loc, OPT_Wattributes, "%qE attribute only supported" - " for reduced Tiny cores", name); + " for reduced Tiny cores", name); *no_add = true; } @@ -10439,8 +10439,8 @@ avr_eval_addr_attrib (rtx x) if (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_IO) { attr = lookup_attribute ("io", DECL_ATTRIBUTES (decl)); - if (!attr || !TREE_VALUE (attr)) - attr = lookup_attribute ("io_low", DECL_ATTRIBUTES (decl)); + if (!attr || !TREE_VALUE (attr)) + attr = lookup_attribute ("io_low", DECL_ATTRIBUTES (decl)); } if (!attr || !TREE_VALUE (attr)) attr = lookup_attribute ("address", DECL_ATTRIBUTES (decl)); @@ -10491,16 +10491,16 @@ avr_addr_space_supported_p (addr_space_t as, location_t loc) if (AVR_TINY) { if (loc != UNKNOWN_LOCATION) - error_at (loc, "address spaces are not supported for reduced " - "Tiny devices"); + error_at (loc, "address spaces are not supported for reduced " + "Tiny devices"); return false; } else if (avr_addrspace[as].segment >= avr_n_flash) { if (loc != UNKNOWN_LOCATION) - error_at (loc, "address space %qs not supported for devices with " - "flash size up to %d KiB", avr_addrspace[as].name, - 64 * avr_n_flash); + error_at (loc, "address space %qs not supported for devices with " + "flash size up to %d KiB", avr_addrspace[as].name, + 64 * avr_n_flash); return false; } @@ -10578,7 +10578,7 @@ static bool avr_decl_absdata_p (tree decl, tree attributes) { return (VAR_P (decl) - && NULL_TREE != lookup_attribute ("absdata", attributes)); + && NULL_TREE != lookup_attribute ("absdata", attributes)); } @@ -10601,23 +10601,23 @@ avr_nonconst_pointer_addrspace (tree typ) /* Pointer to function: Test the function's return type. */ if (FUNCTION_TYPE == TREE_CODE (target)) - return avr_nonconst_pointer_addrspace (TREE_TYPE (target)); + return avr_nonconst_pointer_addrspace (TREE_TYPE (target)); /* "Ordinary" pointers... */ while (TREE_CODE (target) == ARRAY_TYPE) - target = TREE_TYPE (target); + target = TREE_TYPE (target); /* Pointers to non-generic address space must be const. */ as = TYPE_ADDR_SPACE (target); if (!ADDR_SPACE_GENERIC_P (as) - && !TYPE_READONLY (target) - && avr_addr_space_supported_p (as)) - { - return as; - } + && !TYPE_READONLY (target) + && avr_addr_space_supported_p (as)) + { + return as; + } /* Scan pointer's target type. */ @@ -10651,40 +10651,40 @@ avr_pgm_check_var_decl (tree node) case VAR_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (node)), as) - reason = _("variable"); + reason = _("variable"); break; case PARM_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (node)), as) - reason = _("function parameter"); + reason = _("function parameter"); break; case FIELD_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (node)), as) - reason = _("structure field"); + reason = _("structure field"); break; case FUNCTION_DECL: if (as = avr_nonconst_pointer_addrspace (TREE_TYPE (TREE_TYPE (node))), - as) - reason = _("return type of function"); + as) + reason = _("return type of function"); break; case POINTER_TYPE: if (as = avr_nonconst_pointer_addrspace (node), as) - reason = _("pointer"); + reason = _("pointer"); break; } if (reason) { if (TYPE_P (node)) - error ("pointer targeting address space %qs must be const in %qT", - avr_addrspace[as].name, node); + error ("pointer targeting address space %qs must be const in %qT", + avr_addrspace[as].name, node); else - error ("pointer targeting address space %qs must be const" - " in %s %q+D", - avr_addrspace[as].name, reason, node); + error ("pointer targeting address space %qs must be const" + " in %s %q+D", + avr_addrspace[as].name, reason, node); } return reason == NULL; @@ -10720,7 +10720,7 @@ avr_insert_attributes (tree node, tree *attributes) && NULL == lookup_attribute ("OS_task", *attributes)) { *attributes = tree_cons (get_identifier ("OS_task"), - NULL, *attributes); + NULL, *attributes); } /* Add the section attribute if the variable is in progmem. */ @@ -10733,31 +10733,31 @@ avr_insert_attributes (tree node, tree *attributes) tree node0 = node; /* For C++, we have to peel arrays in order to get correct - determination of readonlyness. */ + determination of readonlyness. */ do - node0 = TREE_TYPE (node0); + node0 = TREE_TYPE (node0); while (TREE_CODE (node0) == ARRAY_TYPE); if (error_mark_node == node0) - return; + return; as = TYPE_ADDR_SPACE (TREE_TYPE (node)); if (!TYPE_READONLY (node0) - && !TREE_READONLY (node)) - { - const char *reason = "__attribute__((progmem))"; + && !TREE_READONLY (node)) + { + const char *reason = "__attribute__((progmem))"; - if (!ADDR_SPACE_GENERIC_P (as)) - reason = avr_addrspace[as].name; + if (!ADDR_SPACE_GENERIC_P (as)) + reason = avr_addrspace[as].name; - if (avr_log.progmem) - avr_edump ("\n%?: %t\n%t\n", node, node0); + if (avr_log.progmem) + avr_edump ("\n%?: %t\n%t\n", node, node0); - error ("variable %q+D must be const in order to be put into" - " read-only section by means of %qs", node, reason); - } + error ("variable %q+D must be const in order to be put into" + " read-only section by means of %qs", node, reason); + } } } @@ -10966,12 +10966,12 @@ avr_asm_named_section (const char *name, unsigned int flags, tree decl) const char *new_prefix = avr_addrspace[as].section_name; if (startswith (name, old_prefix)) - { - const char *sname = ACONCAT ((new_prefix, - name + strlen (old_prefix), NULL)); - default_elf_asm_named_section (sname, flags, decl); - return; - } + { + const char *sname = ACONCAT ((new_prefix, + name + strlen (old_prefix), NULL)); + default_elf_asm_named_section (sname, flags, decl); + return; + } default_elf_asm_named_section (new_prefix, flags, decl); return; @@ -11015,11 +11015,11 @@ avr_section_type_flags (tree decl, const char *name, int reloc) addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); /* Attribute progmem puts data in generic address space. - Set section flags as if it was in __flash to get the right - section prefix in the remainder. */ + Set section flags as if it was in __flash to get the right + section prefix in the remainder. */ if (ADDR_SPACE_GENERIC_P (as)) - as = ADDR_SPACE_FLASH; + as = ADDR_SPACE_FLASH; flags |= as * SECTION_MACH_DEP; flags &= ~SECTION_WRITE; @@ -11059,7 +11059,7 @@ avr_decl_maybe_lds_p (tree node) while (ARRAY_TYPE == TREE_CODE (node)); return (node != error_mark_node - && !TYPE_READONLY (node)); + && !TYPE_READONLY (node)); } @@ -11080,22 +11080,22 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) && avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) { if (!TREE_READONLY (decl)) - { - // This might happen with C++ if stuff needs constructing. - error ("variable %q+D with dynamic initialization put " - "into program memory area", decl); - } + { + // This might happen with C++ if stuff needs constructing. + error ("variable %q+D with dynamic initialization put " + "into program memory area", decl); + } else if (NULL_TREE == DECL_INITIAL (decl)) - { - // Don't warn for (implicit) aliases like in PR80462. - tree asmname = DECL_ASSEMBLER_NAME (decl); - varpool_node *node = varpool_node::get_for_asmname (asmname); - bool alias_p = node && node->alias; - - if (!alias_p) - warning (OPT_Wuninitialized, "uninitialized variable %q+D put " - "into program memory area", decl); - } + { + // Don't warn for (implicit) aliases like in PR80462. + tree asmname = DECL_ASSEMBLER_NAME (decl); + varpool_node *node = varpool_node::get_for_asmname (asmname); + bool alias_p = node && node->alias; + + if (!alias_p) + warning (OPT_Wuninitialized, "uninitialized variable %q+D put " + "into program memory area", decl); + } } default_encode_section_info (decl, rtl, new_decl_p); @@ -11114,10 +11114,10 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) addr_space_t as = TYPE_ADDR_SPACE (type); /* PSTR strings are in generic space but located in flash: - patch address space. */ + patch address space. */ if (!AVR_TINY && avr_progmem_p (decl, attr) == -1) - as = ADDR_SPACE_FLASH; + as = ADDR_SPACE_FLASH; AVR_SYMBOL_SET_ADDR_SPACE (sym, as); @@ -11136,9 +11136,9 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) if (io_low_attr || (io_attr && addr_attr - && low_io_address_operand - (GEN_INT (TREE_INT_CST_LOW - (TREE_VALUE (TREE_VALUE (addr_attr)))), QImode))) + && low_io_address_operand + (GEN_INT (TREE_INT_CST_LOW + (TREE_VALUE (TREE_VALUE (addr_attr)))), QImode))) SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_IO_LOW; if (io_attr || io_low_attr) SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_IO; @@ -11174,7 +11174,7 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) using that section anyway, also use it in the public case. */ DECL_COMMON (decl) = 1; - set_decl_section_name (decl, (const char*) nullptr); + set_decl_section_name (decl, (const char *) nullptr); set_decl_tls_model (decl, (tls_model) 2); } } @@ -11190,30 +11190,30 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) bool progmem_p = avr_progmem_p (decl, DECL_ATTRIBUTES (decl)) == -1; if (progmem_p) - { - // Tag symbols for addition of 0x4000 (avr_arch->flash_pm_offset). - SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM; - } + { + // Tag symbols for addition of 0x4000 (avr_arch->flash_pm_offset). + SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_PM; + } if (avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl)) - || (TARGET_ABSDATA - && !progmem_p - && !addr_attr - && avr_decl_maybe_lds_p (decl)) - || (addr_attr - // If addr_attr is non-null, it has an argument. Peek into it. - && TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (addr_attr))) < 0xc0)) - { - // May be accessed by LDS / STS. - SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_ABSDATA; - } + || (TARGET_ABSDATA + && !progmem_p + && !addr_attr + && avr_decl_maybe_lds_p (decl)) + || (addr_attr + // If addr_attr is non-null, it has an argument. Peek into it. + && TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (addr_attr))) < 0xc0)) + { + // May be accessed by LDS / STS. + SYMBOL_REF_FLAGS (sym) |= AVR_SYMBOL_FLAG_TINY_ABSDATA; + } if (progmem_p - && avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl))) - { - error ("%q+D has incompatible attributes %qs and %qs", - decl, "progmem", "absdata"); - } + && avr_decl_absdata_p (decl, DECL_ATTRIBUTES (decl))) + { + error ("%q+D has incompatible attributes %qs and %qs", + decl, "progmem", "absdata"); + } } } @@ -11223,7 +11223,7 @@ avr_encode_section_info (tree decl, rtx rtl, int new_decl_p) static section * avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) { - section * sect = default_elf_select_section (decl, reloc, align); + section *sect = default_elf_select_section (decl, reloc, align); if (decl && DECL_P (decl) && avr_progmem_p (decl, DECL_ATTRIBUTES (decl))) @@ -11231,33 +11231,33 @@ avr_asm_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); /* __progmem__ goes in generic space but shall be allocated to - .progmem.data */ + .progmem.data */ if (ADDR_SPACE_GENERIC_P (as)) - as = ADDR_SPACE_FLASH; + as = ADDR_SPACE_FLASH; if (sect->common.flags & SECTION_NAMED) - { - const char * name = sect->named.name; - const char * old_prefix = ".rodata"; - const char * new_prefix = avr_addrspace[as].section_name; + { + const char *name = sect->named.name; + const char *old_prefix = ".rodata"; + const char *new_prefix = avr_addrspace[as].section_name; if (startswith (name, old_prefix)) - { - const char *sname = ACONCAT ((new_prefix, - name + strlen (old_prefix), NULL)); - return get_section (sname, - sect->common.flags & ~SECTION_DECLARED, - sect->named.decl); - } - } + { + const char *sname = ACONCAT ((new_prefix, + name + strlen (old_prefix), NULL)); + return get_section (sname, + sect->common.flags & ~SECTION_DECLARED, + sect->named.decl); + } + } if (!progmem_section[as]) - { - progmem_section[as] - = get_unnamed_section (0, avr_output_progmem_section_asm_op, - avr_addrspace[as].section_name); - } + { + progmem_section[as] + = get_unnamed_section (0, avr_output_progmem_section_asm_op, + avr_addrspace[as].section_name); + } return progmem_section[as]; } @@ -11390,8 +11390,8 @@ avr_adjust_reg_alloc_order (void) so different allocation order should be used. */ const int *order = (TARGET_ORDER_1 ? (AVR_TINY ? tiny_order_1 : order_1) - : TARGET_ORDER_2 ? (AVR_TINY ? tiny_order_0 : order_2) - : (AVR_TINY ? tiny_order_0 : order_0)); + : TARGET_ORDER_2 ? (AVR_TINY ? tiny_order_0 : order_2) + : (AVR_TINY ? tiny_order_0 : order_0)); for (size_t i = 0; i < ARRAY_SIZE (order_0); ++i) reg_alloc_order[i] = order[i]; @@ -11402,11 +11402,11 @@ avr_adjust_reg_alloc_order (void) static int avr_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, - reg_class_t from, reg_class_t to) + reg_class_t from, reg_class_t to) { return (from == STACK_REG ? 6 - : to == STACK_REG ? 12 - : 2); + : to == STACK_REG ? 12 + : 2); } @@ -11414,14 +11414,14 @@ avr_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, static int avr_memory_move_cost (machine_mode mode, - reg_class_t rclass ATTRIBUTE_UNUSED, - bool in ATTRIBUTE_UNUSED) + reg_class_t rclass ATTRIBUTE_UNUSED, + bool in ATTRIBUTE_UNUSED) { return (mode == QImode ? 2 - : mode == HImode ? 4 - : mode == SImode ? 8 - : mode == SFmode ? 8 - : 16); + : mode == HImode ? 4 + : mode == SImode ? 8 + : mode == SFmode ? 8 + : 16); } @@ -11438,14 +11438,14 @@ avr_mul_highpart_cost (rtx x, int) { // This is the wider mode. machine_mode mode = GET_MODE (x); - + // The middle-end might still have PR81444, i.e. it is calling the cost // functions with strange modes. Fix this now by also considering // PSImode (should actually be SImode instead). if (HImode == mode || PSImode == mode || SImode == mode) - { - return COSTS_N_INSNS (2); - } + { + return COSTS_N_INSNS (2); + } } return 10000; @@ -11544,7 +11544,7 @@ avr_operand_rtx_cost (rtx x, machine_mode mode, enum rtx_code outer, static bool avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, - int opno ATTRIBUTE_UNUSED, int *total, bool speed) + int opno ATTRIBUTE_UNUSED, int *total, bool speed) { enum rtx_code code = GET_CODE (x); HOST_WIDE_INT val; @@ -11573,11 +11573,11 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (1); break; - case E_HImode: - case E_PSImode: - case E_SImode: - *total = COSTS_N_INSNS (2 * GET_MODE_SIZE (mode) - 1); - break; + case E_HImode: + case E_PSImode: + case E_SImode: + *total = COSTS_N_INSNS (2 * GET_MODE_SIZE (mode) - 1); + break; default: return false; @@ -11622,37 +11622,37 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, switch (mode) { case E_QImode: - if (AVR_HAVE_MUL - && MULT == GET_CODE (XEXP (x, 0)) - && register_operand (XEXP (x, 1), QImode)) - { - /* multiply-add */ - *total = COSTS_N_INSNS (speed ? 4 : 3); - /* multiply-add with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + if (AVR_HAVE_MUL + && MULT == GET_CODE (XEXP (x, 0)) + && register_operand (XEXP (x, 1), QImode)) + { + /* multiply-add */ + *total = COSTS_N_INSNS (speed ? 4 : 3); + /* multiply-add with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } *total = COSTS_N_INSNS (1); if (!CONST_INT_P (XEXP (x, 1))) *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); break; case E_HImode: - if (AVR_HAVE_MUL - && (MULT == GET_CODE (XEXP (x, 0)) - || ASHIFT == GET_CODE (XEXP (x, 0))) - && register_operand (XEXP (x, 1), HImode) - && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)) - || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)))) - { - /* multiply-add */ - *total = COSTS_N_INSNS (speed ? 5 : 4); - /* multiply-add with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + if (AVR_HAVE_MUL + && (MULT == GET_CODE (XEXP (x, 0)) + || ASHIFT == GET_CODE (XEXP (x, 0))) + && register_operand (XEXP (x, 1), HImode) + && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)) + || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 0), 0)))) + { + /* multiply-add */ + *total = COSTS_N_INSNS (speed ? 5 : 4); + /* multiply-add with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 0), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } if (!CONST_INT_P (XEXP (x, 1))) { *total = COSTS_N_INSNS (2); @@ -11665,18 +11665,18 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (2); break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (3); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, - speed); - } - else if (IN_RANGE (INTVAL (XEXP (x, 1)), -63, 63)) - *total = COSTS_N_INSNS (2); - else - *total = COSTS_N_INSNS (3); - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (3); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + speed); + } + else if (IN_RANGE (INTVAL (XEXP (x, 1)), -63, 63)) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (3); + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -11699,67 +11699,67 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case MINUS: if (AVR_HAVE_MUL - && QImode == mode - && register_operand (XEXP (x, 0), QImode) - && MULT == GET_CODE (XEXP (x, 1))) - { - /* multiply-sub */ - *total = COSTS_N_INSNS (speed ? 4 : 3); - /* multiply-sub with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + && QImode == mode + && register_operand (XEXP (x, 0), QImode) + && MULT == GET_CODE (XEXP (x, 1))) + { + /* multiply-sub */ + *total = COSTS_N_INSNS (speed ? 4 : 3); + /* multiply-sub with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } if (AVR_HAVE_MUL - && HImode == mode - && register_operand (XEXP (x, 0), HImode) - && (MULT == GET_CODE (XEXP (x, 1)) - || ASHIFT == GET_CODE (XEXP (x, 1))) - && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)) - || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)))) - { - /* multiply-sub */ - *total = COSTS_N_INSNS (speed ? 5 : 4); - /* multiply-sub with constant: will be split and load constant. */ - if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) - *total = COSTS_N_INSNS (1) + *total; - return true; - } + && HImode == mode + && register_operand (XEXP (x, 0), HImode) + && (MULT == GET_CODE (XEXP (x, 1)) + || ASHIFT == GET_CODE (XEXP (x, 1))) + && (ZERO_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)) + || SIGN_EXTEND == GET_CODE (XEXP (XEXP (x, 1), 0)))) + { + /* multiply-sub */ + *total = COSTS_N_INSNS (speed ? 5 : 4); + /* multiply-sub with constant: will be split and load constant. */ + if (CONST_INT_P (XEXP (XEXP (x, 1), 1))) + *total = COSTS_N_INSNS (1) + *total; + return true; + } /* FALLTHRU */ case AND: case IOR: if (IOR == code - && HImode == mode - && ASHIFT == GET_CODE (XEXP (x, 0))) - { - *total = COSTS_N_INSNS (2); - // Just a rough estimate. If we see no sign- or zero-extend, - // then increase the cost a little bit. - if (REG_P (XEXP (XEXP (x, 0), 0))) - *total += COSTS_N_INSNS (1); - if (REG_P (XEXP (x, 1))) - *total += COSTS_N_INSNS (1); - return true; - } + && HImode == mode + && ASHIFT == GET_CODE (XEXP (x, 0))) + { + *total = COSTS_N_INSNS (2); + // Just a rough estimate. If we see no sign- or zero-extend, + // then increase the cost a little bit. + if (REG_P (XEXP (XEXP (x, 0), 0))) + *total += COSTS_N_INSNS (1); + if (REG_P (XEXP (x, 1))) + *total += COSTS_N_INSNS (1); + return true; + } if (IOR == code - && AND == GET_CODE (XEXP (x, 0)) - && AND == GET_CODE (XEXP (x, 1)) - && single_zero_operand (XEXP (XEXP (x, 0), 1), mode)) - { - // Open-coded bit transfer. - *total = COSTS_N_INSNS (2); - return true; - } + && AND == GET_CODE (XEXP (x, 0)) + && AND == GET_CODE (XEXP (x, 1)) + && single_zero_operand (XEXP (XEXP (x, 0), 1), mode)) + { + // Open-coded bit transfer. + *total = COSTS_N_INSNS (2); + return true; + } if (AND == code - && single_one_operand (XEXP (x, 1), mode) - && (ASHIFT == GET_CODE (XEXP (x, 0)) - || ASHIFTRT == GET_CODE (XEXP (x, 0)) - || LSHIFTRT == GET_CODE (XEXP (x, 0)))) - { - // "*insv.any_shift.<mode> - *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode)); - return true; - } + && single_one_operand (XEXP (x, 1), mode) + && (ASHIFT == GET_CODE (XEXP (x, 0)) + || ASHIFTRT == GET_CODE (XEXP (x, 0)) + || LSHIFTRT == GET_CODE (XEXP (x, 0)))) + { + // "*insv.any_shift.<mode> + *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode)); + return true; + } *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)); *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed); if (!CONST_INT_P (XEXP (x, 1))) @@ -11786,81 +11786,81 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case E_HImode: if (AVR_HAVE_MUL) - { - rtx op0 = XEXP (x, 0); - rtx op1 = XEXP (x, 1); - enum rtx_code code0 = GET_CODE (op0); - enum rtx_code code1 = GET_CODE (op1); - bool ex0 = SIGN_EXTEND == code0 || ZERO_EXTEND == code0; - bool ex1 = SIGN_EXTEND == code1 || ZERO_EXTEND == code1; - - if (ex0 - && (u8_operand (op1, HImode) - || s8_operand (op1, HImode))) - { - *total = COSTS_N_INSNS (!speed ? 4 : 6); - return true; - } - if (ex0 - && register_operand (op1, HImode)) - { - *total = COSTS_N_INSNS (!speed ? 5 : 8); - return true; - } - else if (ex0 || ex1) - { - *total = COSTS_N_INSNS (!speed ? 3 : 5); - return true; - } - else if (register_operand (op0, HImode) - && (u8_operand (op1, HImode) - || s8_operand (op1, HImode))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 9); - return true; - } - else - *total = COSTS_N_INSNS (!speed ? 7 : 10); - } + { + rtx op0 = XEXP (x, 0); + rtx op1 = XEXP (x, 1); + enum rtx_code code0 = GET_CODE (op0); + enum rtx_code code1 = GET_CODE (op1); + bool ex0 = SIGN_EXTEND == code0 || ZERO_EXTEND == code0; + bool ex1 = SIGN_EXTEND == code1 || ZERO_EXTEND == code1; + + if (ex0 + && (u8_operand (op1, HImode) + || s8_operand (op1, HImode))) + { + *total = COSTS_N_INSNS (!speed ? 4 : 6); + return true; + } + if (ex0 + && register_operand (op1, HImode)) + { + *total = COSTS_N_INSNS (!speed ? 5 : 8); + return true; + } + else if (ex0 || ex1) + { + *total = COSTS_N_INSNS (!speed ? 3 : 5); + return true; + } + else if (register_operand (op0, HImode) + && (u8_operand (op1, HImode) + || s8_operand (op1, HImode))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 9); + return true; + } + else + *total = COSTS_N_INSNS (!speed ? 7 : 10); + } else if (!speed) *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); else return false; break; - case E_PSImode: - if (!speed) - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); - else - *total = 10; - break; + case E_PSImode: + if (!speed) + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); + else + *total = 10; + break; case E_SImode: case E_DImode: if (AVR_HAVE_MUL) - { - if (!speed) - { - /* Add some additional costs besides CALL like moves etc. */ - - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); - } - else - { - /* Just a rough estimate. Even with -O2 we don't want bulky - code expanded inline. */ - - *total = COSTS_N_INSNS (25); - } - } - else - { - if (speed) - *total = COSTS_N_INSNS (300); - else - /* Add some additional costs besides CALL like moves etc. */ - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); - } + { + if (!speed) + { + /* Add some additional costs besides CALL like moves etc. */ + + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); + } + else + { + /* Just a rough estimate. Even with -O2 we don't want bulky + code expanded inline. */ + + *total = COSTS_N_INSNS (25); + } + } + else + { + if (speed) + *total = COSTS_N_INSNS (300); + else + /* Add some additional costs besides CALL like moves etc. */ + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 5 : 4); + } if (mode == DImode) *total *= 2; @@ -11879,14 +11879,14 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case UDIV: case UMOD: if (!speed) - *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); + *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1); else - *total = COSTS_N_INSNS (15 * GET_MODE_SIZE (mode)); + *total = COSTS_N_INSNS (15 * GET_MODE_SIZE (mode)); *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed); /* For div/mod with const-int divisor we have at least the cost of - loading the divisor. */ + loading the divisor. */ if (CONST_INT_P (XEXP (x, 1))) - *total += COSTS_N_INSNS (GET_MODE_SIZE (mode)); + *total += COSTS_N_INSNS (GET_MODE_SIZE (mode)); /* Add some overall penaly for clobbering and moving around registers */ *total += COSTS_N_INSNS (2); return true; @@ -11949,23 +11949,23 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, break; case E_HImode: - if (AVR_HAVE_MUL) - { - if (const_2_to_7_operand (XEXP (x, 1), HImode) - && (SIGN_EXTEND == GET_CODE (XEXP (x, 0)) - || ZERO_EXTEND == GET_CODE (XEXP (x, 0)))) - { - *total = COSTS_N_INSNS (!speed ? 4 : 6); - return true; - } - } - - if (const1_rtx == (XEXP (x, 1)) - && SIGN_EXTEND == GET_CODE (XEXP (x, 0))) - { - *total = COSTS_N_INSNS (2); - return true; - } + if (AVR_HAVE_MUL) + { + if (const_2_to_7_operand (XEXP (x, 1), HImode) + && (SIGN_EXTEND == GET_CODE (XEXP (x, 0)) + || ZERO_EXTEND == GET_CODE (XEXP (x, 0)))) + { + *total = COSTS_N_INSNS (!speed ? 4 : 6); + return true; + } + } + + if (const1_rtx == (XEXP (x, 1)) + && SIGN_EXTEND == GET_CODE (XEXP (x, 0))) + { + *total = COSTS_N_INSNS (2); + return true; + } if (!CONST_INT_P (XEXP (x, 1))) { @@ -12007,36 +12007,36 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (!speed ? 5 : 10); break; default: - *total = COSTS_N_INSNS (!speed ? 5 : 41); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + *total = COSTS_N_INSNS (!speed ? 5 : 41); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); } break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 73); - } - else - switch (INTVAL (XEXP (x, 1))) - { - case 0: - *total = 0; - break; - case 1: - case 8: - case 16: - *total = COSTS_N_INSNS (3); - break; - case 23: - *total = COSTS_N_INSNS (5); - break; - default: - *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); - break; - } - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 73); + } + else + switch (INTVAL (XEXP (x, 1))) + { + case 0: + *total = 0; + break; + case 1: + case 8: + case 16: + *total = COSTS_N_INSNS (3); + break; + case 23: + *total = COSTS_N_INSNS (5); + break; + default: + *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); + break; + } + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -12123,57 +12123,57 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, break; case 2: case 7: - case 8: - case 9: + case 8: + case 9: *total = COSTS_N_INSNS (4); break; - case 10: + case 10: case 14: *total = COSTS_N_INSNS (5); break; - case 11: - *total = COSTS_N_INSNS (!speed ? 5 : 6); + case 11: + *total = COSTS_N_INSNS (!speed ? 5 : 6); break; - case 12: - *total = COSTS_N_INSNS (!speed ? 5 : 7); + case 12: + *total = COSTS_N_INSNS (!speed ? 5 : 7); break; - case 6: + case 6: case 13: - *total = COSTS_N_INSNS (!speed ? 5 : 8); + *total = COSTS_N_INSNS (!speed ? 5 : 8); break; default: - *total = COSTS_N_INSNS (!speed ? 5 : 41); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + *total = COSTS_N_INSNS (!speed ? 5 : 41); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); } break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 73); - } - else - switch (INTVAL (XEXP (x, 1))) - { - case 0: - *total = 0; - break; - case 1: - *total = COSTS_N_INSNS (3); - break; - case 16: - case 8: - *total = COSTS_N_INSNS (5); - break; - case 23: - *total = COSTS_N_INSNS (4); - break; - default: - *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); - break; - } - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 73); + } + else + switch (INTVAL (XEXP (x, 1))) + { + case 0: + *total = 0; + break; + case 1: + *total = COSTS_N_INSNS (3); + break; + case 16: + case 8: + *total = COSTS_N_INSNS (5); + break; + case 23: + *total = COSTS_N_INSNS (4); + break; + default: + *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); + break; + } + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -12217,10 +12217,10 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case LSHIFTRT: if (outer_code == TRUNCATE) - { - *total = avr_mul_highpart_cost (x, speed); - return true; - } + { + *total = avr_mul_highpart_cost (x, speed); + return true; + } switch (mode) { @@ -12269,7 +12269,7 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (4); break; case 7: - case 11: + case 11: *total = COSTS_N_INSNS (5); break; case 3: @@ -12286,36 +12286,36 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, *total = COSTS_N_INSNS (!speed ? 5 : 9); break; default: - *total = COSTS_N_INSNS (!speed ? 5 : 41); - *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, + *total = COSTS_N_INSNS (!speed ? 5 : 41); + *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed); } break; - case E_PSImode: - if (!CONST_INT_P (XEXP (x, 1))) - { - *total = COSTS_N_INSNS (!speed ? 6 : 73); - } - else - switch (INTVAL (XEXP (x, 1))) - { - case 0: - *total = 0; - break; - case 1: - case 8: - case 16: - *total = COSTS_N_INSNS (3); - break; - case 23: - *total = COSTS_N_INSNS (5); - break; - default: - *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); - break; - } - break; + case E_PSImode: + if (!CONST_INT_P (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (!speed ? 6 : 73); + } + else + switch (INTVAL (XEXP (x, 1))) + { + case 0: + *total = 0; + break; + case 1: + case 8: + case 16: + *total = COSTS_N_INSNS (3); + break; + case 23: + *total = COSTS_N_INSNS (5); + break; + default: + *total = COSTS_N_INSNS (!speed ? 5 : 3 * INTVAL (XEXP (x, 1))); + break; + } + break; case E_SImode: if (!CONST_INT_P (XEXP (x, 1))) @@ -12367,29 +12367,29 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, 1, speed); break; - case E_HImode: + case E_HImode: *total = COSTS_N_INSNS (2); if (!CONST_INT_P (XEXP (x, 1))) - *total += avr_operand_rtx_cost (XEXP (x, 1), HImode, code, + *total += avr_operand_rtx_cost (XEXP (x, 1), HImode, code, 1, speed); else if (INTVAL (XEXP (x, 1)) != 0) *total += COSTS_N_INSNS (1); - break; - - case E_PSImode: - *total = COSTS_N_INSNS (3); - if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) != 0) - *total += COSTS_N_INSNS (2); - break; - - case E_SImode: - *total = COSTS_N_INSNS (4); - if (!CONST_INT_P (XEXP (x, 1))) - *total += avr_operand_rtx_cost (XEXP (x, 1), SImode, code, + break; + + case E_PSImode: + *total = COSTS_N_INSNS (3); + if (CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) != 0) + *total += COSTS_N_INSNS (2); + break; + + case E_SImode: + *total = COSTS_N_INSNS (4); + if (!CONST_INT_P (XEXP (x, 1))) + *total += avr_operand_rtx_cost (XEXP (x, 1), SImode, code, 1, speed); else if (INTVAL (XEXP (x, 1)) != 0) *total += COSTS_N_INSNS (3); - break; + break; default: return false; @@ -12400,10 +12400,10 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, case TRUNCATE: if (LSHIFTRT == GET_CODE (XEXP (x, 0))) - { - *total = avr_mul_highpart_cost (XEXP (x, 0), speed); - return true; - } + { + *total = avr_mul_highpart_cost (XEXP (x, 0), speed); + return true; + } break; case IF_THEN_ELSE: @@ -12433,7 +12433,7 @@ avr_rtx_costs (rtx x, machine_mode mode, int outer_code, if (avr_log.rtx_costs) { avr_edump ("\n%?=%b (%s) total=%d, outer=%C:\n%r\n", - done, speed ? "speed" : "size", *total, outer_code, x); + done, speed ? "speed" : "size", *total, outer_code, x); } return done; @@ -12490,27 +12490,27 @@ avr_insn_cost (rtx_insn *insn, bool speed) static int avr_address_cost (rtx x, machine_mode mode ATTRIBUTE_UNUSED, - addr_space_t as ATTRIBUTE_UNUSED, - bool speed ATTRIBUTE_UNUSED) + addr_space_t as ATTRIBUTE_UNUSED, + bool speed ATTRIBUTE_UNUSED) { int cost = 4; if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) && (REG_P (XEXP (x, 0)) - || SUBREG_P (XEXP (x, 0)))) + || SUBREG_P (XEXP (x, 0)))) { if (INTVAL (XEXP (x, 1)) > MAX_LD_OFFSET(mode)) - cost = 18; + cost = 18; } else if (CONSTANT_ADDRESS_P (x)) { if (io_address_operand (x, QImode)) - cost = 2; + cost = 2; if (AVR_TINY - && avr_address_tiny_absdata_p (x, QImode)) - cost = 2; + && avr_address_tiny_absdata_p (x, QImode)) + cost = 2; } if (avr_log.address_cost) @@ -12538,16 +12538,16 @@ extra_constraint_Q (rtx x) int regno = REGNO (xx); ok = (/* allocate pseudos */ - regno >= FIRST_PSEUDO_REGISTER - /* strictly check */ - || regno == REG_Z || regno == REG_Y - /* XXX frame & arg pointer checks */ - || xx == frame_pointer_rtx - || xx == arg_pointer_rtx); + regno >= FIRST_PSEUDO_REGISTER + /* strictly check */ + || regno == REG_Z || regno == REG_Y + /* XXX frame & arg pointer checks */ + || xx == frame_pointer_rtx + || xx == arg_pointer_rtx); if (avr_log.constraints) - avr_edump ("\n%?=%d reload_completed=%d reload_in_progress=%d\n %r\n", - ok, reload_completed, reload_in_progress, x); + avr_edump ("\n%?=%d reload_completed=%d reload_in_progress=%d\n %r\n", + ok, reload_completed, reload_in_progress, x); } return ok; @@ -12615,8 +12615,8 @@ avr_libcall_value (machine_mode mode, static rtx avr_function_value (const_tree type, - const_tree fn_decl_or_type ATTRIBUTE_UNUSED, - bool outgoing ATTRIBUTE_UNUSED) + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) { unsigned int offs; @@ -12668,24 +12668,24 @@ avr_2word_insn_p (rtx_insn *insn) case CODE_FOR_movuqq_insn: case CODE_FOR_movqq_insn: { - rtx set = single_set (insn); - rtx src = SET_SRC (set); - rtx dest = SET_DEST (set); - - /* Factor out LDS and STS from movqi_insn. */ - - if (MEM_P (dest) - && (REG_P (src) || src == CONST0_RTX (GET_MODE (dest)))) - { - return CONSTANT_ADDRESS_P (XEXP (dest, 0)); - } - else if (REG_P (dest) - && MEM_P (src)) - { - return CONSTANT_ADDRESS_P (XEXP (src, 0)); - } - - return false; + rtx set = single_set (insn); + rtx src = SET_SRC (set); + rtx dest = SET_DEST (set); + + /* Factor out LDS and STS from movqi_insn. */ + + if (MEM_P (dest) + && (REG_P (src) || src == CONST0_RTX (GET_MODE (dest)))) + { + return CONSTANT_ADDRESS_P (XEXP (dest, 0)); + } + else if (REG_P (dest) + && MEM_P (src)) + { + return CONSTANT_ADDRESS_P (XEXP (src, 0)); + } + + return false; } case CODE_FOR_call_insn: @@ -12706,8 +12706,8 @@ jump_over_one_insn_p (rtx_insn *insn, rtx dest) int jump_offset = dest_addr - jump_addr - get_attr_length (insn); return (jump_offset == 1 - || (jump_offset == 2 - && avr_2word_insn_p (next_active_insn (insn)))); + || (jump_offset == 2 + && avr_2word_insn_p (next_active_insn (insn)))); } /* Implement TARGET_HARD_REGNO_NREGS. CCmode is four units for historical @@ -12738,12 +12738,12 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) return mode == CCmode; /* NOTE: 8-bit values must not be disallowed for R28 or R29. - Disallowing QI et al. in these regs might lead to code like - (set (subreg:QI (reg:HI 28) n) ...) - which will result in wrong code because reload does not - handle SUBREGs of hard regsisters like this. - This could be fixed in reload. However, it appears - that fixing reload is not wanted by reload people. */ + Disallowing QI et al. in these regs might lead to code like + (set (subreg:QI (reg:HI 28) n) ...) + which will result in wrong code because reload does not + handle SUBREGs of hard regsisters like this. + This could be fixed in reload. However, it appears + that fixing reload is not wanted by reload people. */ /* Any GENERAL_REGS register can hold 8-bit values. */ @@ -12751,9 +12751,9 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) return true; /* FIXME: Ideally, the following test is not needed. - However, it turned out that it can reduce the number - of spill fails. AVR and it's poor endowment with - address registers is extreme stress test for reload. */ + However, it turned out that it can reduce the number + of spill fails. AVR and it's poor endowment with + address registers is extreme stress test for reload. */ if (GET_MODE_SIZE (mode) >= 4 && regno >= REG_X) @@ -12772,9 +12772,9 @@ avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, machine_mode mode) { /* FIXME: This hook gets called with MODE:REGNO combinations that don't - represent valid hard registers like, e.g. HI:29. Returning TRUE - for such registers can lead to performance degradation as mentioned - in PR53595. Thus, report invalid hard registers as FALSE. */ + represent valid hard registers like, e.g. HI:29. Returning TRUE + for such registers can lead to performance degradation as mentioned + in PR53595. Thus, report invalid hard registers as FALSE. */ if (!avr_hard_regno_mode_ok (regno, mode)) return 0; @@ -12783,9 +12783,9 @@ avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, 17/18 or 19/20 (if AVR_TINY), 27/28 and 29/30. */ return ((regno <= LAST_CALLEE_SAVED_REG - && regno + GET_MODE_SIZE (mode) > 1 + LAST_CALLEE_SAVED_REG) - || (regno < REG_Y && regno + GET_MODE_SIZE (mode) > REG_Y) - || (regno < REG_Z && regno + GET_MODE_SIZE (mode) > REG_Z)); + && regno + GET_MODE_SIZE (mode) > 1 + LAST_CALLEE_SAVED_REG) + || (regno < REG_Y && regno + GET_MODE_SIZE (mode) > REG_Y) + || (regno < REG_Z && regno + GET_MODE_SIZE (mode) > REG_Z)); } @@ -12793,8 +12793,8 @@ avr_hard_regno_call_part_clobbered (unsigned, unsigned regno, enum reg_class avr_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED, - addr_space_t as, RTX_CODE outer_code, - RTX_CODE index_code ATTRIBUTE_UNUSED) + addr_space_t as, RTX_CODE outer_code, + RTX_CODE index_code ATTRIBUTE_UNUSED) { if (!ADDR_SPACE_GENERIC_P (as)) { @@ -12812,39 +12812,39 @@ avr_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED, bool avr_regno_mode_code_ok_for_base_p (int regno, - machine_mode mode ATTRIBUTE_UNUSED, - addr_space_t as ATTRIBUTE_UNUSED, - RTX_CODE outer_code, - RTX_CODE index_code ATTRIBUTE_UNUSED) + machine_mode mode ATTRIBUTE_UNUSED, + addr_space_t as ATTRIBUTE_UNUSED, + RTX_CODE outer_code, + RTX_CODE index_code ATTRIBUTE_UNUSED) { bool ok = false; if (!ADDR_SPACE_GENERIC_P (as)) { if (regno < FIRST_PSEUDO_REGISTER - && regno == REG_Z) - { - return true; - } + && regno == REG_Z) + { + return true; + } if (reg_renumber) - { - regno = reg_renumber[regno]; + { + regno = reg_renumber[regno]; - if (regno == REG_Z) - { - return true; - } - } + if (regno == REG_Z) + { + return true; + } + } return false; } if (regno < FIRST_PSEUDO_REGISTER && (regno == REG_X - || regno == REG_Y - || regno == REG_Z - || regno == ARG_POINTER_REGNUM)) + || regno == REG_Y + || regno == REG_Z + || regno == ARG_POINTER_REGNUM)) { ok = true; } @@ -12853,12 +12853,12 @@ avr_regno_mode_code_ok_for_base_p (int regno, regno = reg_renumber[regno]; if (regno == REG_X - || regno == REG_Y - || regno == REG_Z - || regno == ARG_POINTER_REGNUM) - { - ok = true; - } + || regno == REG_Y + || regno == REG_Z + || regno == ARG_POINTER_REGNUM) + { + ok = true; + } } if (avr_strict_X @@ -12877,7 +12877,7 @@ avr_regno_mode_code_ok_for_base_p (int regno, CLOBBER_REG is a QI clobber register or NULL_RTX. LEN == NULL: output instructions. LEN != NULL: set *LEN to the length of the instruction sequence - (in words) printed with LEN = NULL. + (in words) printed with LEN = NULL. If CLEAR_P is true, OP[0] had been cleard to Zero already. If CLEAR_P is false, nothing is known about OP[0]. @@ -12901,7 +12901,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) int n_bytes = GET_MODE_SIZE (mode); gcc_assert (REG_P (dest) - && CONSTANT_P (src)); + && CONSTANT_P (src)); if (len) *len = 0; @@ -12922,11 +12922,11 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) if (NULL_RTX == clobber_reg && !test_hard_reg_class (LD_REGS, dest) && (! (CONST_INT_P (src) || CONST_FIXED_P (src) || CONST_DOUBLE_P (src)) - || !avr_popcount_each_byte (src, n_bytes, - (1 << 0) | (1 << 1) | (1 << 8)))) + || !avr_popcount_each_byte (src, n_bytes, + (1 << 0) | (1 << 1) | (1 << 8)))) { /* We have no clobber register but need one. Cook one up. - That's cheaper than loading from constant pool. */ + That's cheaper than loading from constant pool. */ cooked_clobber_p = true; clobber_reg = all_regs_rtx[REG_Z + 1]; @@ -12947,25 +12947,25 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) ldreg_p = test_hard_reg_class (LD_REGS, xdest[n]); if (!CONST_INT_P (src) - && !CONST_FIXED_P (src) - && !CONST_DOUBLE_P (src)) - { - static const char* const asm_code[][2] = - { - { "ldi %2,lo8(%1)" CR_TAB "mov %0,%2", "ldi %0,lo8(%1)" }, - { "ldi %2,hi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hi8(%1)" }, - { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2", "ldi %0,hlo8(%1)" }, - { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hhi8(%1)" } - }; - - xop[0] = xdest[n]; - xop[1] = src; - xop[2] = clobber_reg; - - avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2); - - continue; - } + && !CONST_FIXED_P (src) + && !CONST_DOUBLE_P (src)) + { + static const char *const asm_code[][2] = + { + { "ldi %2,lo8(%1)" CR_TAB "mov %0,%2", "ldi %0,lo8(%1)" }, + { "ldi %2,hi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hi8(%1)" }, + { "ldi %2,hlo8(%1)" CR_TAB "mov %0,%2", "ldi %0,hlo8(%1)" }, + { "ldi %2,hhi8(%1)" CR_TAB "mov %0,%2", "ldi %0,hhi8(%1)" } + }; + + xop[0] = xdest[n]; + xop[1] = src; + xop[2] = clobber_reg; + + avr_asm_len (asm_code[n][ldreg_p], xop, len, ldreg_p ? 1 : 2); + + continue; + } /* Crop the n-th source byte. */ @@ -12975,107 +12975,107 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) /* Look if we can reuse the low word by means of MOVW. */ if (n == 2 - && n_bytes >= 4 - && AVR_HAVE_MOVW) - { - rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0); - rtx hi16 = simplify_gen_subreg (HImode, src, mode, 2); - - if (INTVAL (lo16) == INTVAL (hi16)) - { + && n_bytes >= 4 + && AVR_HAVE_MOVW) + { + rtx lo16 = simplify_gen_subreg (HImode, src, mode, 0); + rtx hi16 = simplify_gen_subreg (HImode, src, mode, 2); + + if (INTVAL (lo16) == INTVAL (hi16)) + { if (INTVAL (lo16) != 0 || !clear_p) avr_asm_len ("movw %C0,%A0", &op[0], len, 1); - break; - } - } + break; + } + } /* Don't use CLR so that cc0 is set as expected. */ if (ival[n] == 0) - { - if (!clear_p) - avr_asm_len (ldreg_p ? "ldi %0,0" - : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" - : "mov %0,__zero_reg__", - &xdest[n], len, 1); - continue; - } + { + if (!clear_p) + avr_asm_len (ldreg_p ? "ldi %0,0" + : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" + : "mov %0,__zero_reg__", + &xdest[n], len, 1); + continue; + } if (clobber_val == ival[n] - && REGNO (clobber_reg) == REGNO (xdest[n])) - { - continue; - } + && REGNO (clobber_reg) == REGNO (xdest[n])) + { + continue; + } /* LD_REGS can use LDI to move a constant value */ if (ldreg_p) - { - xop[0] = xdest[n]; - xop[1] = xval; - avr_asm_len ("ldi %0,lo8(%1)", xop, len, 1); - continue; - } + { + xop[0] = xdest[n]; + xop[1] = xval; + avr_asm_len ("ldi %0,lo8(%1)", xop, len, 1); + continue; + } /* Try to reuse value already loaded in some lower byte. */ for (int j = 0; j < n; j++) - if (ival[j] == ival[n]) - { - xop[0] = xdest[n]; - xop[1] = xdest[j]; + if (ival[j] == ival[n]) + { + xop[0] = xdest[n]; + xop[1] = xdest[j]; - avr_asm_len ("mov %0,%1", xop, len, 1); - done_byte = true; - break; - } + avr_asm_len ("mov %0,%1", xop, len, 1); + done_byte = true; + break; + } if (done_byte) - continue; + continue; /* Need no clobber reg for -1: Use CLR/DEC */ if (ival[n] == -1) - { - if (!clear_p) - avr_asm_len ("clr %0", &xdest[n], len, 1); + { + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); - avr_asm_len ("dec %0", &xdest[n], len, 1); - continue; - } + avr_asm_len ("dec %0", &xdest[n], len, 1); + continue; + } else if (ival[n] == 1) - { - if (!clear_p) - avr_asm_len ("clr %0", &xdest[n], len, 1); + { + if (!clear_p) + avr_asm_len ("clr %0", &xdest[n], len, 1); - avr_asm_len ("inc %0", &xdest[n], len, 1); - continue; - } + avr_asm_len ("inc %0", &xdest[n], len, 1); + continue; + } /* Use T flag or INC to manage powers of 2 if we have - no clobber reg. */ + no clobber reg. */ if (NULL_RTX == clobber_reg - && single_one_operand (xval, QImode)) - { - xop[0] = xdest[n]; - xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode))); + && single_one_operand (xval, QImode)) + { + xop[0] = xdest[n]; + xop[1] = GEN_INT (exact_log2 (ival[n] & GET_MODE_MASK (QImode))); - gcc_assert (constm1_rtx != xop[1]); + gcc_assert (constm1_rtx != xop[1]); - if (!set_p) - { - set_p = true; - avr_asm_len ("set", xop, len, 1); - } + if (!set_p) + { + set_p = true; + avr_asm_len ("set", xop, len, 1); + } - if (!clear_p) - avr_asm_len ("clr %0", xop, len, 1); + if (!clear_p) + avr_asm_len ("clr %0", xop, len, 1); - avr_asm_len ("bld %0,%1", xop, len, 1); - continue; - } + avr_asm_len ("bld %0,%1", xop, len, 1); + continue; + } /* We actually need the LD_REGS clobber reg. */ @@ -13087,7 +13087,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) clobber_val = ival[n]; avr_asm_len ("ldi %2,lo8(%1)" CR_TAB - "mov %0,%2", xop, len, 2); + "mov %0,%2", xop, len, 2); } /* If we cooked up a clobber reg above, restore it. */ @@ -13106,11 +13106,11 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) PLEN == NULL: Output instructions. PLEN != NULL: Output nothing. Set *PLEN to number of words occupied - by the insns printed. + by the insns printed. Return "". */ -const char* +const char * output_reload_inhi (rtx *op, rtx clobber_reg, int *plen) { output_reload_in_const (op, clobber_reg, plen, false); @@ -13126,7 +13126,7 @@ output_reload_inhi (rtx *op, rtx clobber_reg, int *plen) LEN == NULL: Output instructions. LEN != NULL: Output nothing. Set *LEN to number of words occupied - by the insns printed. + by the insns printed. Return "". */ @@ -13136,41 +13136,41 @@ output_reload_insisf (rtx *op, rtx clobber_reg, int *len) if (AVR_HAVE_MOVW && !test_hard_reg_class (LD_REGS, op[0]) && (CONST_INT_P (op[1]) - || CONST_FIXED_P (op[1]) - || CONST_DOUBLE_P (op[1]))) + || CONST_FIXED_P (op[1]) + || CONST_DOUBLE_P (op[1]))) { int len_clr, len_noclr; /* In some cases it is better to clear the destination beforehand, e.g. - CLR R2 CLR R3 MOVW R4,R2 INC R2 + CLR R2 CLR R3 MOVW R4,R2 INC R2 - is shorther than + is shorther than - CLR R2 INC R2 CLR R3 CLR R4 CLR R5 + CLR R2 INC R2 CLR R3 CLR R4 CLR R5 - We find it too tedious to work that out in the print function. - Instead, we call the print function twice to get the lengths of - both methods and use the shortest one. */ + We find it too tedious to work that out in the print function. + Instead, we call the print function twice to get the lengths of + both methods and use the shortest one. */ output_reload_in_const (op, clobber_reg, &len_clr, true); output_reload_in_const (op, clobber_reg, &len_noclr, false); if (len_noclr - len_clr == 4) - { - /* Default needs 4 CLR instructions: clear register beforehand. */ + { + /* Default needs 4 CLR instructions: clear register beforehand. */ - avr_asm_len ("mov %A0,__zero_reg__" CR_TAB - "mov %B0,__zero_reg__" CR_TAB - "movw %C0,%A0", &op[0], len, 3); + avr_asm_len ("mov %A0,__zero_reg__" CR_TAB + "mov %B0,__zero_reg__" CR_TAB + "movw %C0,%A0", &op[0], len, 3); - output_reload_in_const (op, clobber_reg, len, true); + output_reload_in_const (op, clobber_reg, len, true); - if (len) - *len += 3; + if (len) + *len += 3; - return ""; - } + return ""; + } } /* Default: destination not pre-cleared. */ @@ -13179,7 +13179,7 @@ output_reload_insisf (rtx *op, rtx clobber_reg, int *len) return ""; } -const char* +const char * avr_out_reload_inpsi (rtx *op, rtx clobber_reg, int *len) { output_reload_in_const (op, clobber_reg, len, false); @@ -13237,7 +13237,7 @@ avr_output_addr_vec (rtx_insn *labl, rtx table) sec_name = ACONCAT ((sec_name, ".", fname, NULL)); fprintf (stream, "\t.section\t%s,\"%s\",@progbits\n", sec_name, - AVR_HAVE_JMP_CALL ? "a" : "ax"); + AVR_HAVE_JMP_CALL ? "a" : "ax"); } // Output the label that preceeds the table. @@ -13254,9 +13254,9 @@ avr_output_addr_vec (rtx_insn *labl, rtx table) int value = CODE_LABEL_NUMBER (XEXP (XVECEXP (table, 0, idx), 0)); if (AVR_HAVE_JMP_CALL) - fprintf (stream, "\t.word gs(.L%d)\n", value); + fprintf (stream, "\t.word gs(.L%d)\n", value); else - fprintf (stream, "\trjmp .L%d\n", value); + fprintf (stream, "\trjmp .L%d\n", value); } // Switch back to original section. As we clobbered the section above, @@ -13275,42 +13275,42 @@ avr_conditional_register_usage (void) if (AVR_TINY) { const int tiny_reg_alloc_order[] = { - 24, 25, - 22, 23, - 30, 31, - 26, 27, - 28, 29, - 21, 20, 19, 18, - 16, 17, - 32, 33, 34, 35, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + 24, 25, + 22, 23, + 30, 31, + 26, 27, + 28, 29, + 21, 20, 19, 18, + 16, 17, + 32, 33, 34, 35, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; /* Set R0-R17 as fixed registers. Reset R0-R17 in call used register list - - R0-R15 are not available in Tiny Core devices - - R16 and R17 are fixed registers. */ + - R0-R15 are not available in Tiny Core devices + - R16 and R17 are fixed registers. */ for (size_t i = 0; i <= 17; i++) - { - fixed_regs[i] = 1; - call_used_regs[i] = 1; - } + { + fixed_regs[i] = 1; + call_used_regs[i] = 1; + } /* Set R18 to R21 as callee saved registers - - R18, R19, R20 and R21 are the callee saved registers in - Tiny Core devices */ + - R18, R19, R20 and R21 are the callee saved registers in + Tiny Core devices */ for (size_t i = 18; i <= LAST_CALLEE_SAVED_REG; i++) - { - call_used_regs[i] = 0; - } + { + call_used_regs[i] = 0; + } /* Update register allocation order for Tiny Core devices */ for (size_t i = 0; i < ARRAY_SIZE (tiny_reg_alloc_order); i++) - { - reg_alloc_order[i] = tiny_reg_alloc_order[i]; - } + { + reg_alloc_order[i] = tiny_reg_alloc_order[i]; + } CLEAR_HARD_REG_SET (reg_class_contents[(int) ADDW_REGS]); CLEAR_HARD_REG_SET (reg_class_contents[(int) NO_LD_REGS]); @@ -13366,7 +13366,7 @@ avr_hard_regno_rename_ok (unsigned int old_reg, if ((!reload_completed || frame_pointer_needed) && (old_reg == REG_Y || old_reg == REG_Y + 1 - || new_reg == REG_Y || new_reg == REG_Y + 1)) + || new_reg == REG_Y || new_reg == REG_Y + 1)) { return 0; } @@ -13382,7 +13382,7 @@ avr_hard_regno_rename_ok (unsigned int old_reg, Operand 2: bit number. Operand 3: label to jump to if the test is true. */ -const char* +const char * avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]) { enum rtx_code comp = GET_CODE (operands[0]); @@ -13407,37 +13407,37 @@ avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]) case SYMBOL_REF: if (low_io_address_operand (operands[1], QImode)) - { - if (comp == EQ) - output_asm_insn ("sbis %i1,%2", operands); - else - output_asm_insn ("sbic %i1,%2", operands); - } + { + if (comp == EQ) + output_asm_insn ("sbis %i1,%2", operands); + else + output_asm_insn ("sbic %i1,%2", operands); + } else - { + { gcc_assert (io_address_operand (operands[1], QImode)); - output_asm_insn ("in __tmp_reg__,%i1", operands); - if (comp == EQ) - output_asm_insn ("sbrs __tmp_reg__,%2", operands); - else - output_asm_insn ("sbrc __tmp_reg__,%2", operands); - } + output_asm_insn ("in __tmp_reg__,%i1", operands); + if (comp == EQ) + output_asm_insn ("sbrs __tmp_reg__,%2", operands); + else + output_asm_insn ("sbrc __tmp_reg__,%2", operands); + } break; /* CONST_INT */ case REG: if (comp == EQ) - output_asm_insn ("sbrs %T1%T2", operands); + output_asm_insn ("sbrs %T1%T2", operands); else - output_asm_insn ("sbrc %T1%T2", operands); + output_asm_insn ("sbrc %T1%T2", operands); break; /* REG */ - } /* switch */ + } /* switch */ if (long_jump) return ("rjmp .+4" CR_TAB - "jmp %x3"); + "jmp %x3"); if (!reverse) return "rjmp %x3"; @@ -13570,36 +13570,36 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, case ADDR_SPACE_FLASH5: switch (GET_CODE (x)) - { - case REG: - ok = avr_reg_ok_for_pgm_addr (x, strict); - break; + { + case REG: + ok = avr_reg_ok_for_pgm_addr (x, strict); + break; - case POST_INC: - ok = avr_reg_ok_for_pgm_addr (XEXP (x, 0), strict); - break; + case POST_INC: + ok = avr_reg_ok_for_pgm_addr (XEXP (x, 0), strict); + break; - default: - break; - } + default: + break; + } break; /* FLASH */ case ADDR_SPACE_MEMX: if (REG_P (x)) - ok = (!strict - && can_create_pseudo_p()); + ok = (!strict + && can_create_pseudo_p()); if (LO_SUM == GET_CODE (x)) - { - rtx hi = XEXP (x, 0); - rtx lo = XEXP (x, 1); + { + rtx hi = XEXP (x, 0); + rtx lo = XEXP (x, 1); - ok = (REG_P (hi) - && (!strict || REGNO (hi) < FIRST_PSEUDO_REGISTER) - && REG_P (lo) - && REGNO (lo) == REG_Z); - } + ok = (REG_P (hi) + && (!strict || REGNO (hi) < FIRST_PSEUDO_REGISTER) + && REG_P (lo) + && REGNO (lo) == REG_Z); + } break; /* MEMX */ } @@ -13607,19 +13607,19 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, if (avr_log.legitimate_address_p) { avr_edump ("\n%?: ret=%b, mode=%m strict=%d " - "reload_completed=%d reload_in_progress=%d %s:", - ok, mode, strict, reload_completed, reload_in_progress, - reg_renumber ? "(reg_renumber)" : ""); + "reload_completed=%d reload_in_progress=%d %s:", + ok, mode, strict, reload_completed, reload_in_progress, + reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && CONST_INT_P (XEXP (x, 1)) - && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) - && reg_renumber) - { - avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), - true_regnum (XEXP (x, 0))); - } + && REG_P (XEXP (x, 0)) + && CONST_INT_P (XEXP (x, 1)) + && IN_RANGE (INTVAL (XEXP (x, 1)), 0, MAX_LD_OFFSET (mode)) + && reg_renumber) + { + avr_edump ("(r%d ---> r%d)", REGNO (XEXP (x, 0)), + true_regnum (XEXP (x, 0))); + } avr_edump ("\n%r\n", x); } @@ -13632,7 +13632,7 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, static rtx avr_addr_space_legitimize_address (rtx x, rtx old_x, - machine_mode mode, addr_space_t as) + machine_mode mode, addr_space_t as) { if (ADDR_SPACE_GENERIC_P (as)) return avr_legitimize_address (x, old_x, mode); @@ -13656,7 +13656,7 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) if (avr_log.progmem) avr_edump ("\n%!: op = %r\nfrom = %t\nto = %t\n", - src, type_from, type_to); + src, type_from, type_to); /* Up-casting from 16-bit to 24-bit pointer. */ @@ -13668,31 +13668,31 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) rtx reg = gen_reg_rtx (PSImode); while (CONST == GET_CODE (sym) || PLUS == GET_CODE (sym)) - sym = XEXP (sym, 0); + sym = XEXP (sym, 0); /* Look at symbol flags: avr_encode_section_info set the flags - also if attribute progmem was seen so that we get the right - promotion for, e.g. PSTR-like strings that reside in generic space - but are located in flash. In that case we patch the incoming - address space. */ + also if attribute progmem was seen so that we get the right + promotion for, e.g. PSTR-like strings that reside in generic space + but are located in flash. In that case we patch the incoming + address space. */ if (SYMBOL_REF_P (sym) - && ADDR_SPACE_FLASH == AVR_SYMBOL_GET_ADDR_SPACE (sym)) - { - as_from = ADDR_SPACE_FLASH; - } + && ADDR_SPACE_FLASH == AVR_SYMBOL_GET_ADDR_SPACE (sym)) + { + as_from = ADDR_SPACE_FLASH; + } /* Linearize memory: RAM has bit 23 set. */ msb = ADDR_SPACE_GENERIC_P (as_from) - ? 0x80 - : avr_addrspace[as_from].segment; + ? 0x80 + : avr_addrspace[as_from].segment; src = force_reg (Pmode, src); emit_insn (msb == 0 - ? gen_zero_extendhipsi2 (reg, src) - : gen_n_extendhipsi2 (reg, gen_int_mode (msb, QImode), src)); + ? gen_zero_extendhipsi2 (reg, src) + : gen_n_extendhipsi2 (reg, gen_int_mode (msb, QImode), src)); return reg; } @@ -13707,7 +13707,7 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) src = force_reg (PSImode, src); emit_move_insn (new_src, - simplify_gen_subreg (Pmode, src, PSImode, 0)); + simplify_gen_subreg (Pmode, src, PSImode, 0)); return new_src; } @@ -13719,7 +13719,7 @@ avr_addr_space_convert (rtx src, tree type_from, tree type_to) static bool avr_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED, - addr_space_t superset ATTRIBUTE_UNUSED) + addr_space_t superset ATTRIBUTE_UNUSED) { /* Allow any kind of pointer mess. */ @@ -13737,23 +13737,23 @@ avr_convert_to_type (tree type, tree expr) provided -Waddr-space-convert is on. FIXME: Filter out cases where the target object is known to - be located in the right memory, like in + be located in the right memory, like in - (const __flash*) PSTR ("text") + (const __flash*) PSTR ("text") - Also try to distinguish between explicit casts requested by - the user and implicit casts like + Also try to distinguish between explicit casts requested by + the user and implicit casts like - void f (const __flash char*); + void f (const __flash char*); - void g (const char *p) - { - f ((const __flash*) p); - } + void g (const char *p) + { + f ((const __flash*) p); + } - under the assumption that an explicit casts means that the user - knows what he is doing, e.g. interface with PSTR or old style - code with progmem and pgm_read_xxx. + under the assumption that an explicit casts means that the user + knows what he is doing, e.g. interface with PSTR or old style + code with progmem and pgm_read_xxx. */ if (avr_warn_addr_space_convert @@ -13765,22 +13765,22 @@ avr_convert_to_type (tree type, tree expr) addr_space_t as_new = TYPE_ADDR_SPACE (TREE_TYPE (type)); if (avr_log.progmem) - avr_edump ("%?: type = %t\nexpr = %t\n\n", type, expr); + avr_edump ("%?: type = %t\nexpr = %t\n\n", type, expr); if (as_new != ADDR_SPACE_MEMX - && as_new != as_old) - { - location_t loc = EXPR_LOCATION (expr); - const char *name_old = avr_addrspace[as_old].name; - const char *name_new = avr_addrspace[as_new].name; + && as_new != as_old) + { + location_t loc = EXPR_LOCATION (expr); + const char *name_old = avr_addrspace[as_old].name; + const char *name_new = avr_addrspace[as_new].name; - warning (OPT_Waddr_space_convert, - "conversion from address space %qs to address space %qs", - ADDR_SPACE_GENERIC_P (as_old) ? "generic" : name_old, - ADDR_SPACE_GENERIC_P (as_new) ? "generic" : name_new); + warning (OPT_Waddr_space_convert, + "conversion from address space %qs to address space %qs", + ADDR_SPACE_GENERIC_P (as_old) ? "generic" : name_old, + ADDR_SPACE_GENERIC_P (as_new) ? "generic" : name_new); - return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr); - } + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr); + } } return NULL_TREE; @@ -13803,12 +13803,12 @@ avr_legitimate_combined_insn (rtx_insn *insn) const_rtx op = *iter; if (SUBREG_P (op) - && MEM_P (SUBREG_REG (op)) - && (GET_MODE_SIZE (GET_MODE (op)) - > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))) - { - return false; - } + && MEM_P (SUBREG_REG (op)) + && (GET_MODE_SIZE (GET_MODE (op)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))) + { + return false; + } } return true; @@ -13826,7 +13826,7 @@ avr_legitimate_combined_insn (rtx_insn *insn) replace OP[n] with a newly created pseudo register HREG == 0: Also emit a move insn that copies the contents of that - hard register into the new pseudo. + hard register into the new pseudo. HREG != 0: Also set HREG[n] to the hard register. */ @@ -13838,23 +13838,23 @@ avr_fix_operands (rtx *op, rtx *hreg, unsigned opmask, unsigned rmask) rtx reg = *op; if (hreg) - *hreg = NULL_RTX; + *hreg = NULL_RTX; if ((opmask & 1) - && REG_P (reg) - && REGNO (reg) < FIRST_PSEUDO_REGISTER - // This hard-reg overlaps other prohibited hard regs? - && (rmask & regmask (GET_MODE (reg), REGNO (reg)))) - { - *op = gen_reg_rtx (GET_MODE (reg)); - if (hreg == NULL) - emit_move_insn (*op, reg); - else - *hreg = reg; - } + && REG_P (reg) + && REGNO (reg) < FIRST_PSEUDO_REGISTER + // This hard-reg overlaps other prohibited hard regs? + && (rmask & regmask (GET_MODE (reg), REGNO (reg)))) + { + *op = gen_reg_rtx (GET_MODE (reg)); + if (hreg == NULL) + emit_move_insn (*op, reg); + else + *hreg = reg; + } if (hreg) - hreg++; + hreg++; } } @@ -13875,7 +13875,7 @@ avr_move_fixed_operands (rtx *op, rtx *hreg, unsigned mask) { for (; mask; mask >>= 1, op++, hreg++) if ((mask & 1) - && *hreg) + && *hreg) emit_move_insn (*hreg, *op); return true; @@ -13897,7 +13897,7 @@ avr_move_fixed_operands (rtx *op, rtx *hreg, unsigned mask) bool avr_emit3_fix_outputs (rtx (*gen)(rtx,rtx,rtx), rtx *op, - unsigned opmask, unsigned rmask) + unsigned opmask, unsigned rmask) { const int n = 3; rtx hreg[n]; @@ -13970,15 +13970,15 @@ avr_emit_cpymemhi (rtx *xop) int segment = avr_addrspace[as].segment; if (segment - && avr_n_flash > 1) - { - a_hi8 = GEN_INT (segment); - emit_move_insn (rampz_rtx, a_hi8 = copy_to_mode_reg (QImode, a_hi8)); - } + && avr_n_flash > 1) + { + a_hi8 = GEN_INT (segment); + emit_move_insn (rampz_rtx, a_hi8 = copy_to_mode_reg (QImode, a_hi8)); + } else if (!ADDR_SPACE_GENERIC_P (as)) - { - as = ADDR_SPACE_FLASH; - } + { + as = ADDR_SPACE_FLASH; + } addr1 = a_src; @@ -13989,35 +13989,35 @@ avr_emit_cpymemhi (rtx *xop) xas = GEN_INT (as); /* FIXME: Register allocator might come up with spill fails if it is left - on its own. Thus, we allocate the pointer registers by hand: - Z = source address - X = destination address */ + on its own. Thus, we allocate the pointer registers by hand: + Z = source address + X = destination address */ emit_move_insn (lpm_addr_reg_rtx, addr1); emit_move_insn (gen_rtx_REG (HImode, REG_X), a_dest); /* FIXME: Register allocator does a bad job and might spill address - register(s) inside the loop leading to additional move instruction - to/from stack which could clobber tmp_reg. Thus, do *not* emit - load and store as separate insns. Instead, we perform the copy - by means of one monolithic insn. */ + register(s) inside the loop leading to additional move instruction + to/from stack which could clobber tmp_reg. Thus, do *not* emit + load and store as separate insns. Instead, we perform the copy + by means of one monolithic insn. */ gcc_assert (TMP_REGNO == LPM_REGNO); if (as != ADDR_SPACE_MEMX) { /* Load instruction ([E]LPM or LD) is known at compile time: - Do the copy-loop inline. */ + Do the copy-loop inline. */ rtx (*fun) (rtx, rtx, rtx) - = QImode == loop_mode ? gen_cpymem_qi : gen_cpymem_hi; + = QImode == loop_mode ? gen_cpymem_qi : gen_cpymem_hi; insn = fun (xas, loop_reg, loop_reg); } else { rtx (*fun) (rtx, rtx) - = QImode == loop_mode ? gen_cpymemx_qi : gen_cpymemx_hi; + = QImode == loop_mode ? gen_cpymemx_qi : gen_cpymemx_hi; emit_move_insn (gen_rtx_REG (QImode, 23), a_hi8); @@ -14038,7 +14038,7 @@ avr_emit_cpymemhi (rtx *xop) X : Destination address */ -const char* +const char * avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) { addr_space_t as = (addr_space_t) INTVAL (op[0]); @@ -14072,10 +14072,10 @@ avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) case ADDR_SPACE_FLASH: if (AVR_HAVE_LPMX) - avr_asm_len ("lpm %2,Z+", xop, plen, 1); + avr_asm_len ("lpm %2,Z+", xop, plen, 1); else - avr_asm_len ("lpm" CR_TAB - "adiw r30,1", xop, plen, 2); + avr_asm_len ("lpm" CR_TAB + "adiw r30,1", xop, plen, 2); break; case ADDR_SPACE_FLASH1: @@ -14085,10 +14085,10 @@ avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) case ADDR_SPACE_FLASH5: if (AVR_HAVE_ELPMX) - avr_asm_len ("elpm %2,Z+", xop, plen, 1); + avr_asm_len ("elpm %2,Z+", xop, plen, 1); else - avr_asm_len ("elpm" CR_TAB - "adiw r30,1", xop, plen, 2); + avr_asm_len ("elpm" CR_TAB + "adiw r30,1", xop, plen, 2); break; } @@ -14109,7 +14109,7 @@ avr_out_cpymem (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen) else { avr_asm_len ("subi %A1,1" CR_TAB - "sbci %B1,0", xop, plen, 2); + "sbci %B1,0", xop, plen, 2); } /* Loop until zero */ @@ -14141,7 +14141,7 @@ avr_expand_delay_cycles (rtx operands0) loop_count = ((cycles - 9) / 6) + 1; cycles_used = ((loop_count - 1) * 6) + 9; emit_insn (gen_delay_cycles_4 (gen_int_mode (loop_count, SImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14149,10 +14149,10 @@ avr_expand_delay_cycles (rtx operands0) { loop_count = ((cycles - 7) / 5) + 1; if (loop_count > 0xFFFFFF) - loop_count = 0xFFFFFF; + loop_count = 0xFFFFFF; cycles_used = ((loop_count - 1) * 5) + 7; emit_insn (gen_delay_cycles_3 (gen_int_mode (loop_count, SImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14160,10 +14160,10 @@ avr_expand_delay_cycles (rtx operands0) { loop_count = ((cycles - 5) / 4) + 1; if (loop_count > 0xFFFF) - loop_count = 0xFFFF; + loop_count = 0xFFFF; cycles_used = ((loop_count - 1) * 4) + 5; emit_insn (gen_delay_cycles_2 (gen_int_mode (loop_count, HImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14171,10 +14171,10 @@ avr_expand_delay_cycles (rtx operands0) { loop_count = cycles / 3; if (loop_count > 255) - loop_count = 255; + loop_count = 255; cycles_used = loop_count * 3; emit_insn (gen_delay_cycles_1 (gen_int_mode (loop_count, QImode), - avr_mem_clobber())); + avr_mem_clobber())); cycles -= cycles_used; } @@ -14243,17 +14243,17 @@ avr_map_metric (unsigned int a, int mode) unsigned ai = avr_map (a, i); if (mode == MAP_FIXED_0_7) - metric += ai == i; + metric += ai == i; else if (mode == MAP_NONFIXED_0_7) - metric += ai < 8 && ai != i; + metric += ai < 8 && ai != i; else if (mode == MAP_MASK_FIXED_0_7) - metric |= ((unsigned) (ai == i)) << i; + metric |= ((unsigned) (ai == i)) << i; else if (mode == MAP_PREIMAGE_0_7) - metric += ai < 8; + metric += ai < 8; else if (mode == MAP_MASK_PREIMAGE_F) - metric |= ((unsigned) (ai == 0xf)) << i; + metric |= ((unsigned) (ai == 0xf)) << i; else - gcc_unreachable(); + gcc_unreachable(); } return metric; @@ -14348,14 +14348,14 @@ avr_map_decompose (unsigned int f, const avr_map_op_t *g, bool val_const_p) int x = avr_map (f, i); if (x <= 7) - { - x = avr_map (ginv, x); + { + x = avr_map (ginv, x); - /* The bit is no element of the image of G: no avail (cost = -1) */ + /* The bit is no element of the image of G: no avail (cost = -1) */ - if (x > 7) - return f_ginv; - } + if (x > 7) + return f_ginv; + } f_ginv.map = (f_ginv.map << 4) + x; } @@ -14375,8 +14375,8 @@ avr_map_decompose (unsigned int f, const avr_map_op_t *g, bool val_const_p) rtx xop[4]; /* Get the cost of the insn by calling the output worker with some - fake values. Mimic effect of reloading xop[3]: Unused operands - are mapped to 0 and used operands are reloaded to xop[0]. */ + fake values. Mimic effect of reloading xop[3]: Unused operands + are mapped to 0 and used operands are reloaded to xop[0]. */ xop[0] = all_regs_rtx[24]; xop[1] = gen_int_mode (f_ginv.map, SImode); @@ -14416,28 +14416,28 @@ avr_move_bits (rtx *xop, unsigned int map, bool fixp_p, int *plen) for (int b = 0; b < 8; b++) for (int bit_dest = 0; bit_dest < 8; bit_dest++) { - int bit_src = avr_map (map, bit_dest); + int bit_src = avr_map (map, bit_dest); - if (b != bit_src - || bit_src >= 8 - /* Same position: No need to copy as requested by FIXP_P. */ - || (bit_dest == bit_src && !fixp_p)) - continue; + if (b != bit_src + || bit_src >= 8 + /* Same position: No need to copy as requested by FIXP_P. */ + || (bit_dest == bit_src && !fixp_p)) + continue; - if (t_bit_src != bit_src) - { - /* Source bit is not yet in T: Store it to T. */ + if (t_bit_src != bit_src) + { + /* Source bit is not yet in T: Store it to T. */ - t_bit_src = bit_src; + t_bit_src = bit_src; - xop[3] = GEN_INT (bit_src); - avr_asm_len ("bst %T1%T3", xop, plen, 1); - } + xop[3] = GEN_INT (bit_src); + avr_asm_len ("bst %T1%T3", xop, plen, 1); + } - /* Load destination bit with T. */ + /* Load destination bit with T. */ - xop[3] = GEN_INT (bit_dest); - avr_asm_len ("bld %T0%T3", xop, plen, 1); + xop[3] = GEN_INT (bit_dest); + avr_asm_len ("bld %T0%T3", xop, plen, 1); } } @@ -14447,14 +14447,14 @@ avr_move_bits (rtx *xop, unsigned int map, bool fixp_p, int *plen) OP[0]: Result OP[1]: The mapping composed of nibbles. If nibble no. N is - 0: Bit N of result is copied from bit OP[2].0 - ... ... - 7: Bit N of result is copied from bit OP[2].7 - 0xf: Bit N of result is copied from bit OP[3].N + 0: Bit N of result is copied from bit OP[2].0 + ... ... + 7: Bit N of result is copied from bit OP[2].7 + 0xf: Bit N of result is copied from bit OP[3].N OP[2]: Bits to be inserted OP[3]: Target value */ -const char* +const char * avr_out_insert_bits (rtx *op, int *plen) { unsigned int map = UINTVAL (op[1]) & GET_MODE_MASK (SImode); @@ -14496,30 +14496,30 @@ avr_out_insert_bits (rtx *op, int *plen) gcc_assert (REG_P (xop[2])); /* Get the code size of the bit insertions; once with all bits - moved and once with fixed points omitted. */ + moved and once with fixed points omitted. */ avr_move_bits (xop, map, true, &n_fix); avr_move_bits (xop, map, false, &n_nofix); if (fixp_p && n_fix - n_nofix > 3) - { - xop[3] = gen_int_mode (~mask_fixed, QImode); + { + xop[3] = gen_int_mode (~mask_fixed, QImode); - avr_asm_len ("eor %0,%1" CR_TAB - "andi %0,%3" CR_TAB - "eor %0,%1", xop, plen, 3); - fixp_p = false; - } + avr_asm_len ("eor %0,%1" CR_TAB + "andi %0,%3" CR_TAB + "eor %0,%1", xop, plen, 3); + fixp_p = false; + } } else { /* XOP[2] is unused */ if (fixp_p && mask_fixed) - { - avr_asm_len ("mov %0,%1", xop, plen, 1); - fixp_p = false; - } + { + avr_asm_len ("mov %0,%1", xop, plen, 1); + fixp_p = false; + } } /* Move/insert remaining bits. */ @@ -14597,47 +14597,47 @@ avr_init_builtins (void) = build_function_type_list (void_type_node, NULL_TREE); tree uchar_ftype_uchar = build_function_type_list (unsigned_char_type_node, - unsigned_char_type_node, - NULL_TREE); + unsigned_char_type_node, + NULL_TREE); tree uint_ftype_uchar_uchar = build_function_type_list (unsigned_type_node, - unsigned_char_type_node, - unsigned_char_type_node, - NULL_TREE); + unsigned_char_type_node, + unsigned_char_type_node, + NULL_TREE); tree int_ftype_char_char = build_function_type_list (integer_type_node, - char_type_node, - char_type_node, - NULL_TREE); + char_type_node, + char_type_node, + NULL_TREE); tree int_ftype_char_uchar = build_function_type_list (integer_type_node, - char_type_node, - unsigned_char_type_node, - NULL_TREE); + char_type_node, + unsigned_char_type_node, + NULL_TREE); tree void_ftype_ulong = build_function_type_list (void_type_node, - long_unsigned_type_node, - NULL_TREE); + long_unsigned_type_node, + NULL_TREE); tree uchar_ftype_ulong_uchar_uchar = build_function_type_list (unsigned_char_type_node, - long_unsigned_type_node, - unsigned_char_type_node, - unsigned_char_type_node, - NULL_TREE); + long_unsigned_type_node, + unsigned_char_type_node, + unsigned_char_type_node, + NULL_TREE); tree const_memx_void_node = build_qualified_type (void_type_node, - TYPE_QUAL_CONST - | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_MEMX)); + TYPE_QUAL_CONST + | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_MEMX)); tree const_memx_ptr_type_node = build_pointer_type_for_mode (const_memx_void_node, PSImode, false); tree char_ftype_const_memx_ptr = build_function_type_list (char_type_node, - const_memx_ptr_type_node, - NULL); + const_memx_ptr_type_node, + NULL); #define ITYP(T) \ lang_hooks.types.type_for_size (TYPE_PRECISION (T), TYPE_UNSIGNED (T)) @@ -14755,12 +14755,12 @@ avr_init_builtins (void) { \ int id = AVR_BUILTIN_ ## NAME; \ const char *Name = "__builtin_avr_" #NAME; \ - char *name = (char*) alloca (1 + strlen (Name)); \ + char *name = (char *) alloca (1 + strlen (Name)); \ \ gcc_assert (id < AVR_BUILTIN_COUNT); \ avr_bdesc[id].fndecl \ = add_builtin_function (avr_tolower (name, Name), TYPE, id, \ - BUILT_IN_MD, LIBNAME, NULL_TREE); \ + BUILT_IN_MD, LIBNAME, NULL_TREE); \ } #include "builtins.def" #undef DEF_BUILTIN @@ -14796,18 +14796,18 @@ avr_default_expand_builtin (enum insn_code icode, tree exp, rtx target) machine_mode mode = insn_data[icode].operand[n + 1].mode; if ((opmode == SImode || opmode == VOIDmode) && mode == HImode) - { - opmode = HImode; - op = gen_lowpart (HImode, op); - } + { + opmode = HImode; + op = gen_lowpart (HImode, op); + } /* In case the insn wants input operands in modes different from - the result, abort. */ + the result, abort. */ gcc_assert (opmode == mode || opmode == VOIDmode); if (!insn_data[icode].operand[n + 1].predicate (op, mode)) - op = copy_to_mode_reg (mode, op); + op = copy_to_mode_reg (mode, op); xop[n] = op; } @@ -14840,9 +14840,9 @@ avr_default_expand_builtin (enum insn_code icode, tree exp, rtx target) static rtx avr_expand_builtin (tree exp, rtx target, - rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, - int ignore) + rtx subtarget ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, + int ignore) { tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); const char *bname = IDENTIFIER_POINTER (DECL_NAME (fndecl)); @@ -14861,43 +14861,43 @@ avr_expand_builtin (tree exp, rtx target, case AVR_BUILTIN_DELAY_CYCLES: { - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - if (!CONST_INT_P (op0)) - error ("%s expects a compile time integer constant", bname); - else - avr_expand_delay_cycles (op0); + if (!CONST_INT_P (op0)) + error ("%s expects a compile time integer constant", bname); + else + avr_expand_delay_cycles (op0); - return NULL_RTX; + return NULL_RTX; } case AVR_BUILTIN_NOPS: { - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - if (!CONST_INT_P (op0)) - error ("%s expects a compile time integer constant", bname); - else - avr_expand_nops (op0); + if (!CONST_INT_P (op0)) + error ("%s expects a compile time integer constant", bname); + else + avr_expand_nops (op0); - return NULL_RTX; + return NULL_RTX; } case AVR_BUILTIN_INSERT_BITS: { - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); + arg0 = CALL_EXPR_ARG (exp, 0); + op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL); - if (!CONST_INT_P (op0)) - { - error ("%s expects a compile time long integer constant" - " as first argument", bname); - return target; - } + if (!CONST_INT_P (op0)) + { + error ("%s expects a compile time long integer constant" + " as first argument", bname); + return target; + } - break; + break; } case AVR_BUILTIN_ROUNDHR: case AVR_BUILTIN_ROUNDUHR: @@ -14911,33 +14911,33 @@ avr_expand_builtin (tree exp, rtx target, case AVR_BUILTIN_ROUNDLLK: case AVR_BUILTIN_ROUNDULLK: /* Warn about odd rounding. Rounding points >= FBIT will have - no effect. */ + no effect. */ if (TREE_CODE (CALL_EXPR_ARG (exp, 1)) != INTEGER_CST) - break; + break; int rbit = (int) TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1)); if (rbit >= (int) GET_MODE_FBIT (mode)) - { - warning (OPT_Wextra, "rounding to %d bits has no effect for " - "fixed-point value with %d fractional bits", - rbit, GET_MODE_FBIT (mode)); - - return expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, mode, - EXPAND_NORMAL); - } + { + warning (OPT_Wextra, "rounding to %d bits has no effect for " + "fixed-point value with %d fractional bits", + rbit, GET_MODE_FBIT (mode)); + + return expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, mode, + EXPAND_NORMAL); + } else if (rbit <= - (int) GET_MODE_IBIT (mode)) - { - warning (0, "rounding result will always be 0"); - return CONST0_RTX (mode); - } + { + warning (0, "rounding result will always be 0"); + return CONST0_RTX (mode); + } /* The rounding points RP satisfies now: -IBIT < RP < FBIT. - TR 18037 only specifies results for RP > 0. However, the - remaining cases of -IBIT < RP <= 0 can easily be supported - without any additional overhead. */ + TR 18037 only specifies results for RP > 0. However, the + remaining cases of -IBIT < RP <= 0 can easily be supported + without any additional overhead. */ break; /* round */ } @@ -14996,7 +14996,7 @@ avr_fold_absfx (tree tval) static tree avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, - bool ignore ATTRIBUTE_UNUSED) + bool ignore ATTRIBUTE_UNUSED) { unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl); tree val_type = TREE_TYPE (TREE_TYPE (fndecl)); @@ -15011,8 +15011,8 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, case AVR_BUILTIN_SWAP: { - return fold_build2 (LROTATE_EXPR, val_type, arg[0], - build_int_cst (val_type, 4)); + return fold_build2 (LROTATE_EXPR, val_type, arg[0], + build_int_cst (val_type, 4)); } case AVR_BUILTIN_ABSHR: @@ -15049,139 +15049,139 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, case AVR_BUILTIN_BITSULLK: case AVR_BUILTIN_ULLKBITS: gcc_assert (TYPE_PRECISION (val_type) - == TYPE_PRECISION (TREE_TYPE (arg[0]))); + == TYPE_PRECISION (TREE_TYPE (arg[0]))); return build1 (VIEW_CONVERT_EXPR, val_type, arg[0]); case AVR_BUILTIN_INSERT_BITS: { - tree tbits = arg[1]; - tree tval = arg[2]; - tree tmap; - tree map_type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); - unsigned int map; - bool changed = false; - avr_map_op_t best_g; - - if (TREE_CODE (arg[0]) != INTEGER_CST) - { - /* No constant as first argument: Don't fold this and run into - error in avr_expand_builtin. */ - - break; - } - - tmap = wide_int_to_tree (map_type, wi::to_wide (arg[0])); - map = TREE_INT_CST_LOW (tmap); - - if (TREE_CODE (tval) != INTEGER_CST + tree tbits = arg[1]; + tree tval = arg[2]; + tree tmap; + tree map_type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + unsigned int map; + bool changed = false; + avr_map_op_t best_g; + + if (TREE_CODE (arg[0]) != INTEGER_CST) + { + /* No constant as first argument: Don't fold this and run into + error in avr_expand_builtin. */ + + break; + } + + tmap = wide_int_to_tree (map_type, wi::to_wide (arg[0])); + map = TREE_INT_CST_LOW (tmap); + + if (TREE_CODE (tval) != INTEGER_CST && avr_map_metric (map, MAP_MASK_PREIMAGE_F) == 0) - { - /* There are no F in the map, i.e. 3rd operand is unused. - Replace that argument with some constant to render - respective input unused. */ + { + /* There are no F in the map, i.e. 3rd operand is unused. + Replace that argument with some constant to render + respective input unused. */ - tval = build_int_cst (val_type, 0); - changed = true; - } + tval = build_int_cst (val_type, 0); + changed = true; + } - if (TREE_CODE (tbits) != INTEGER_CST + if (TREE_CODE (tbits) != INTEGER_CST && avr_map_metric (map, MAP_PREIMAGE_0_7) == 0) - { - /* Similar for the bits to be inserted. If they are unused, - we can just as well pass 0. */ + { + /* Similar for the bits to be inserted. If they are unused, + we can just as well pass 0. */ - tbits = build_int_cst (val_type, 0); - } + tbits = build_int_cst (val_type, 0); + } - if (TREE_CODE (tbits) == INTEGER_CST) - { - /* Inserting bits known at compile time is easy and can be - performed by AND and OR with appropriate masks. */ + if (TREE_CODE (tbits) == INTEGER_CST) + { + /* Inserting bits known at compile time is easy and can be + performed by AND and OR with appropriate masks. */ - int bits = TREE_INT_CST_LOW (tbits); - int mask_ior = 0, mask_and = 0xff; + int bits = TREE_INT_CST_LOW (tbits); + int mask_ior = 0, mask_and = 0xff; - for (size_t i = 0; i < 8; i++) - { - int mi = avr_map (map, i); + for (size_t i = 0; i < 8; i++) + { + int mi = avr_map (map, i); - if (mi < 8) - { - if (bits & (1 << mi)) mask_ior |= (1 << i); - else mask_and &= ~(1 << i); - } - } + if (mi < 8) + { + if (bits & (1 << mi)) mask_ior |= (1 << i); + else mask_and &= ~(1 << i); + } + } - tval = fold_build2 (BIT_IOR_EXPR, val_type, tval, - build_int_cst (val_type, mask_ior)); - return fold_build2 (BIT_AND_EXPR, val_type, tval, - build_int_cst (val_type, mask_and)); - } + tval = fold_build2 (BIT_IOR_EXPR, val_type, tval, + build_int_cst (val_type, mask_ior)); + return fold_build2 (BIT_AND_EXPR, val_type, tval, + build_int_cst (val_type, mask_and)); + } - if (changed) - return build_call_expr (fndecl, 3, tmap, tbits, tval); + if (changed) + return build_call_expr (fndecl, 3, tmap, tbits, tval); - /* If bits don't change their position, we can use vanilla logic - to merge the two arguments... */ + /* If bits don't change their position, we can use vanilla logic + to merge the two arguments... */ - if (avr_map_metric (map, MAP_NONFIXED_0_7) == 0 - // ...except when we are copying just one bit. In that - // case, BLD/BST is better than XOR/AND/XOR, see PR90622. - && avr_map_metric (map, MAP_FIXED_0_7) != 1) - { - int mask_f = avr_map_metric (map, MAP_MASK_PREIMAGE_F); - tree tres, tmask = build_int_cst (val_type, mask_f ^ 0xff); + if (avr_map_metric (map, MAP_NONFIXED_0_7) == 0 + // ...except when we are copying just one bit. In that + // case, BLD/BST is better than XOR/AND/XOR, see PR90622. + && avr_map_metric (map, MAP_FIXED_0_7) != 1) + { + int mask_f = avr_map_metric (map, MAP_MASK_PREIMAGE_F); + tree tres, tmask = build_int_cst (val_type, mask_f ^ 0xff); - tres = fold_build2 (BIT_XOR_EXPR, val_type, tbits, tval); - tres = fold_build2 (BIT_AND_EXPR, val_type, tres, tmask); - return fold_build2 (BIT_XOR_EXPR, val_type, tres, tval); - } + tres = fold_build2 (BIT_XOR_EXPR, val_type, tbits, tval); + tres = fold_build2 (BIT_AND_EXPR, val_type, tres, tmask); + return fold_build2 (BIT_XOR_EXPR, val_type, tres, tval); + } - /* Try to decomposing map to reduce overall cost. */ + /* Try to decomposing map to reduce overall cost. */ - if (avr_log.builtin) - avr_edump ("\n%?: %x\n%?: ROL cost: ", map); + if (avr_log.builtin) + avr_edump ("\n%?: %x\n%?: ROL cost: ", map); - best_g = avr_map_op[0]; - best_g.cost = 1000; + best_g = avr_map_op[0]; + best_g.cost = 1000; - for (size_t i = 0; i < ARRAY_SIZE (avr_map_op); i++) - { - avr_map_op_t g - = avr_map_decompose (map, avr_map_op + i, - TREE_CODE (tval) == INTEGER_CST); + for (size_t i = 0; i < ARRAY_SIZE (avr_map_op); i++) + { + avr_map_op_t g + = avr_map_decompose (map, avr_map_op + i, + TREE_CODE (tval) == INTEGER_CST); - if (g.cost >= 0 && g.cost < best_g.cost) - best_g = g; - } + if (g.cost >= 0 && g.cost < best_g.cost) + best_g = g; + } - if (avr_log.builtin) - avr_edump ("\n"); + if (avr_log.builtin) + avr_edump ("\n"); - if (best_g.arg == 0) - /* No optimization found */ - break; + if (best_g.arg == 0) + /* No optimization found */ + break; - /* Apply operation G to the 2nd argument. */ + /* Apply operation G to the 2nd argument. */ - if (avr_log.builtin) - avr_edump ("%?: using OP(%s%d, %x) cost %d\n", - best_g.str, best_g.arg, best_g.map, best_g.cost); + if (avr_log.builtin) + avr_edump ("%?: using OP(%s%d, %x) cost %d\n", + best_g.str, best_g.arg, best_g.map, best_g.cost); - /* Do right-shifts arithmetically: They copy the MSB instead of - shifting in a non-usable value (0) as with logic right-shift. */ + /* Do right-shifts arithmetically: They copy the MSB instead of + shifting in a non-usable value (0) as with logic right-shift. */ - tbits = fold_convert (signed_char_type_node, tbits); - tbits = fold_build2 (best_g.code, signed_char_type_node, tbits, - build_int_cst (val_type, best_g.arg)); - tbits = fold_convert (val_type, tbits); + tbits = fold_convert (signed_char_type_node, tbits); + tbits = fold_build2 (best_g.code, signed_char_type_node, tbits, + build_int_cst (val_type, best_g.arg)); + tbits = fold_convert (val_type, tbits); - /* Use map o G^-1 instead of original map to undo the effect of G. */ + /* Use map o G^-1 instead of original map to undo the effect of G. */ - tmap = wide_int_to_tree (map_type, best_g.map); + tmap = wide_int_to_tree (map_type, best_g.map); - return build_call_expr (fndecl, 3, tmap, tbits, tval); + return build_call_expr (fndecl, 3, tmap, tbits, tval); } /* AVR_BUILTIN_INSERT_BITS */ } @@ -15194,10 +15194,10 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, static rtx_insn * avr_md_asm_adjust (vec<rtx> &/*outputs*/, vec<rtx> &/*inputs*/, - vec<machine_mode> & /*input_modes*/, - vec<const char *> &/*constraints*/, + vec<machine_mode> & /*input_modes*/, + vec<const char *> &/*constraints*/, vec<rtx> &/*uses*/, - vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs, + vec<rtx> &clobbers, HARD_REG_SET &clobbered_regs, location_t /*loc*/) { clobbers.safe_push (cc_reg_rtx); diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index e80de2c..20be455 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -6585,15 +6585,15 @@ gcn_hsa_declare_function_name (FILE *file, const char *name, /* Determine count of sgpr/vgpr registers by looking for last one used. */ - for (sgpr = 101; sgpr >= 0; sgpr--) + for (sgpr = LAST_SGPR_REG - FIRST_SGPR_REG; sgpr >= 0; sgpr--) if (df_regs_ever_live_p (FIRST_SGPR_REG + sgpr)) break; sgpr++; - for (vgpr = 255; vgpr >= 0; vgpr--) + for (vgpr = LAST_VGPR_REG - FIRST_VGPR_REG; vgpr >= 0; vgpr--) if (df_regs_ever_live_p (FIRST_VGPR_REG + vgpr)) break; vgpr++; - for (avgpr = 255; avgpr >= 0; avgpr--) + for (avgpr = LAST_AVGPR_REG - FIRST_AVGPR_REG; avgpr >= 0; avgpr--) if (df_regs_ever_live_p (FIRST_AVGPR_REG + avgpr)) break; avgpr++; diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index c2afb5e..a17f16a 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -146,14 +146,23 @@ #define EXEC_HI_REG 127 #define EXECZ_REG 128 #define SCC_REG 129 + /* 132-159 are reserved to simplify masks. */ + #define FIRST_VGPR_REG 160 #define VGPR_REGNO(N) ((N)+FIRST_VGPR_REG) #define LAST_VGPR_REG 415 + #define FIRST_AVGPR_REG 416 #define AVGPR_REGNO(N) ((N)+FIRST_AVGPR_REG) #define LAST_AVGPR_REG 671 +#ifndef USED_FOR_TARGET +STATIC_ASSERT (LAST_SGPR_REG + 1 - FIRST_SGPR_REG == 102); +STATIC_ASSERT (LAST_VGPR_REG + 1 - FIRST_VGPR_REG == 256); +STATIC_ASSERT (LAST_AVGPR_REG + 1 - FIRST_AVGPR_REG == 256); +#endif /* USED_FOR_TARGET */ + /* Frame Registers, and other registers */ #define HARD_FRAME_POINTER_REGNUM 14 @@ -180,10 +189,9 @@ #define HARD_FRAME_POINTER_IS_ARG_POINTER 0 #define HARD_FRAME_POINTER_IS_FRAME_POINTER 0 -#define SGPR_OR_VGPR_REGNO_P(N) ((N)>=FIRST_VGPR_REG && (N) <= LAST_SGPR_REG) -#define SGPR_REGNO_P(N) ((N) <= LAST_SGPR_REG) -#define VGPR_REGNO_P(N) ((N)>=FIRST_VGPR_REG && (N) <= LAST_VGPR_REG) -#define AVGPR_REGNO_P(N) ((N)>=FIRST_AVGPR_REG && (N) <= LAST_AVGPR_REG) +#define SGPR_REGNO_P(N) ((N) >= FIRST_SGPR_REG && (N) <= LAST_SGPR_REG) +#define VGPR_REGNO_P(N) ((N) >= FIRST_VGPR_REG && (N) <= LAST_VGPR_REG) +#define AVGPR_REGNO_P(N) ((N) >= FIRST_AVGPR_REG && (N) <= LAST_AVGPR_REG) #define SSRC_REGNO_P(N) ((N) <= SCC_REG && (N) != VCCZ_REG) #define SDST_REGNO_P(N) ((N) <= EXEC_HI_REG && (N) != VCCZ_REG) #define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 1f3c692..3b51453 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -23,9 +23,7 @@ ; Named registers (define_constants - [(FIRST_SGPR_REG 0) - (CC_SAVE_REG 22) - (LAST_SGPR_REG 101) + [(CC_SAVE_REG 22) (FLAT_SCRATCH_REG 102) (FLAT_SCRATCH_LO_REG 102) (FLAT_SCRATCH_HI_REG 103) @@ -49,11 +47,7 @@ (EXEC_LO_REG 126) (EXEC_HI_REG 127) (EXECZ_REG 128) - (SCC_REG 129) - (FIRST_VGPR_REG 160) - (LAST_VGPR_REG 415) - (FIRST_AVGPR_REG 416) - (LAST_AVGPR_REG 671)]) + (SCC_REG 129)]) (define_constants [(SP_REGNUM 16) @@ -2074,7 +2068,12 @@ (match_operand:SIDI 3 "register_operand" " v")] UNSPECV_ATOMIC))] "" - "ds_cmpst_rtn_b<bitsize> %0, %1, %2, %3\;s_waitcnt\tlgkmcnt(0)" + { + if (TARGET_RDNA3) + return "ds_cmpstore_rtn_b<bitsize> %0, %1, %3, %2\;s_waitcnt\tlgkmcnt(0)"; + else + return "ds_cmpst_rtn_b<bitsize> %0, %1, %2, %3\;s_waitcnt\tlgkmcnt(0)"; + } [(set_attr "type" "ds") (set_attr "length" "12")]) diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index 0c6e662..280e4c8 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -348,6 +348,10 @@ to double word size." (match_operand 0 "x86_64_dwzext_immediate_operand")) +(define_constraint "Ws" + "A symbolic reference or label reference." + (match_code "const,symbol_ref,label_ref")) + (define_constraint "Z" "32-bit unsigned integer constant, or a symbolic reference known to fit that range (for immediate operands in zero-extending x86-64 diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 5706220..50f9fe2 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -8429,7 +8429,7 @@ expand_set_or_cpymem_prologue_epilogue_by_misaligned_moves (rtx destmem, rtx src /* See how many bytes we skipped. */ saveddest = expand_simple_binop (GET_MODE (*destptr), MINUS, saveddest, *destptr, - saveddest, 1, OPTAB_DIRECT); + NULL_RTX, 1, OPTAB_DIRECT); /* Adjust srcptr and count. */ if (!issetmem) *srcptr = expand_simple_binop (GET_MODE (*srcptr), MINUS, *srcptr, diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index 4020b27..e0b9615 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -2664,6 +2664,32 @@ rest_of_handle_insert_vzeroupper (void) /* Call optimize_mode_switching. */ g->get_passes ()->execute_pass_mode_switching (); + /* LRA removes all REG_DEAD/REG_UNUSED notes and normally they + reappear in the IL only at the start of pass_rtl_dse2, which does + df_note_add_problem (); df_analyze (); + The vzeroupper is scheduled after postreload_cse pass and mode + switching computes the notes as well, the problem is that e.g. + pass_gcse2 doesn't maintain the notes, see PR113059 and + PR112760. Remove the notes now to restore status quo ante + until we figure out how to maintain the notes or what else + to do. */ + basic_block bb; + rtx_insn *insn; + FOR_EACH_BB_FN (bb, cfun) + FOR_BB_INSNS (bb, insn) + if (NONDEBUG_INSN_P (insn)) + { + rtx *pnote = ®_NOTES (insn); + while (*pnote != 0) + { + if (REG_NOTE_KIND (*pnote) == REG_DEAD + || REG_NOTE_KIND (*pnote) == REG_UNUSED) + *pnote = XEXP (*pnote, 1); + else + pnote = &XEXP (*pnote, 1); + } + } + df_analyze (); return 0; } diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index b3e7c74..10bd534 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -22749,6 +22749,48 @@ current_fentry_section (const char **name) return true; } +/* Return a caller-saved register which isn't live or a callee-saved + register which has been saved on stack in the prologue at entry for + profile. */ + +static int +x86_64_select_profile_regnum (bool r11_ok ATTRIBUTE_UNUSED) +{ + /* Use %r10 if the profiler is emitted before the prologue or it isn't + used by DRAP. */ + if (ix86_profile_before_prologue () + || !crtl->drap_reg + || REGNO (crtl->drap_reg) != R10_REG) + return R10_REG; + + /* The profiler is emitted after the prologue. If there is a + caller-saved register which isn't live or a callee-saved + register saved on stack in the prologue, use it. */ + + bitmap reg_live = df_get_live_out (ENTRY_BLOCK_PTR_FOR_FN (cfun)); + + int i; + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) + if (GENERAL_REGNO_P (i) + && i != R10_REG +#ifdef NO_PROFILE_COUNTERS + && (r11_ok || i != R11_REG) +#else + && i != R11_REG +#endif + && TEST_HARD_REG_BIT (accessible_reg_set, i) + && (ix86_save_reg (i, true, true) + || (call_used_regs[i] + && !fixed_regs[i] + && !REGNO_REG_SET_P (reg_live, i)))) + return i; + + sorry ("no register available for profiling %<-mcmodel=large%s%>", + ix86_cmodel == CM_LARGE_PIC ? " -fPIC" : ""); + + return R10_REG; +} + /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ void @@ -22783,42 +22825,61 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) fprintf (file, "\tleaq\t%sP%d(%%rip), %%r11\n", LPREFIX, labelno); #endif + int scratch; + const char *reg; + char legacy_reg[4] = { 0 }; + if (!TARGET_PECOFF) { switch (ix86_cmodel) { case CM_LARGE: - /* NB: R10 is caller-saved. Although it can be used as a - static chain register, it is preserved when calling - mcount for nested functions. */ + scratch = x86_64_select_profile_regnum (true); + reg = hi_reg_name[scratch]; + if (LEGACY_INT_REGNO_P (scratch)) + { + legacy_reg[0] = 'r'; + legacy_reg[1] = reg[0]; + legacy_reg[2] = reg[1]; + reg = legacy_reg; + } if (ASSEMBLER_DIALECT == ASM_INTEL) - fprintf (file, "1:\tmovabs\tr10, OFFSET FLAT:%s\n" - "\tcall\tr10\n", mcount_name); + fprintf (file, "1:\tmovabs\t%s, OFFSET FLAT:%s\n" + "\tcall\t%s\n", reg, mcount_name, reg); else - fprintf (file, "1:\tmovabsq\t$%s, %%r10\n\tcall\t*%%r10\n", - mcount_name); + fprintf (file, "1:\tmovabsq\t$%s, %%%s\n\tcall\t*%%%s\n", + mcount_name, reg, reg); break; case CM_LARGE_PIC: #ifdef NO_PROFILE_COUNTERS + scratch = x86_64_select_profile_regnum (false); + reg = hi_reg_name[scratch]; + if (LEGACY_INT_REGNO_P (scratch)) + { + legacy_reg[0] = 'r'; + legacy_reg[1] = reg[0]; + legacy_reg[2] = reg[1]; + reg = legacy_reg; + } if (ASSEMBLER_DIALECT == ASM_INTEL) { fprintf (file, "1:movabs\tr11, " "OFFSET FLAT:_GLOBAL_OFFSET_TABLE_-1b\n"); - fprintf (file, "\tlea\tr10, 1b[rip]\n"); - fprintf (file, "\tadd\tr10, r11\n"); + fprintf (file, "\tlea\t%s, 1b[rip]\n", reg); + fprintf (file, "\tadd\t%s, r11\n", reg); fprintf (file, "\tmovabs\tr11, OFFSET FLAT:%s@PLTOFF\n", mcount_name); - fprintf (file, "\tadd\tr10, r11\n"); - fprintf (file, "\tcall\tr10\n"); + fprintf (file, "\tadd\t%s, r11\n", reg); + fprintf (file, "\tcall\t%s\n", reg); break; } fprintf (file, "1:\tmovabsq\t$_GLOBAL_OFFSET_TABLE_-1b, %%r11\n"); - fprintf (file, "\tleaq\t1b(%%rip), %%r10\n"); - fprintf (file, "\taddq\t%%r11, %%r10\n"); + fprintf (file, "\tleaq\t1b(%%rip), %%%s\n", reg); + fprintf (file, "\taddq\t%%r11, %%%s\n", reg); fprintf (file, "\tmovabsq\t$%s@PLTOFF, %%r11\n", mcount_name); - fprintf (file, "\taddq\t%%r11, %%r10\n"); - fprintf (file, "\tcall\t*%%r10\n"); + fprintf (file, "\taddq\t%%r11, %%%s\n", reg); + fprintf (file, "\tcall\t*%%%s\n", reg); #else sorry ("profiling %<-mcmodel=large%> with PIC is not supported"); #endif diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bac0a6a..a82f2e4 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1632,10 +1632,6 @@ (set (match_dup 4) (ior:DWIH (match_dup 4) (match_dup 5)))])] { split_double_mode (<DWI>mode, &operands[0], 2, &operands[0], &operands[2]); - /* Placing the SUBREG pieces in pseudos helps reload. */ - for (int i = 0; i < 4; i++) - if (SUBREG_P (operands[i])) - operands[i] = force_reg (<MODE>mode, operands[i]); operands[4] = gen_reg_rtx (<MODE>mode); diff --git a/gcc/config/loongarch/larchintrin.h b/gcc/config/loongarch/larchintrin.h index 7692415..ff2c9f4 100644 --- a/gcc/config/loongarch/larchintrin.h +++ b/gcc/config/loongarch/larchintrin.h @@ -336,38 +336,38 @@ __iocsrwr_d (unsigned long int _1, unsigned int _2) #ifdef __loongarch_frecipe /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: SF, SF. */ -extern __inline void +extern __inline float __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frecipe_s (float _1) { - __builtin_loongarch_frecipe_s ((float) _1); + return (float) __builtin_loongarch_frecipe_s ((float) _1); } /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: DF, DF. */ -extern __inline void +extern __inline double __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frecipe_d (double _1) { - __builtin_loongarch_frecipe_d ((double) _1); + return (double) __builtin_loongarch_frecipe_d ((double) _1); } /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: SF, SF. */ -extern __inline void +extern __inline float __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frsqrte_s (float _1) { - __builtin_loongarch_frsqrte_s ((float) _1); + return (float) __builtin_loongarch_frsqrte_s ((float) _1); } /* Assembly instruction format: fd, fj. */ /* Data types in instruction templates: DF, DF. */ -extern __inline void +extern __inline double __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) __frsqrte_d (double _1) { - __builtin_loongarch_frsqrte_d ((double) _1); + return (double) __builtin_loongarch_frsqrte_d ((double) _1); } #endif diff --git a/gcc/config/loongarch/lasx.md b/gcc/config/loongarch/lasx.md index e2115ff..ac84db7 100644 --- a/gcc/config/loongarch/lasx.md +++ b/gcc/config/loongarch/lasx.md @@ -3028,22 +3028,6 @@ [(set_attr "type" "simd_logic") (set_attr "mode" "V8SF")]) -(define_insn "negv4df2" - [(set (match_operand:V4DF 0 "register_operand" "=f") - (neg:V4DF (match_operand:V4DF 1 "register_operand" "f")))] - "ISA_HAS_LASX" - "xvbitrevi.d\t%u0,%u1,63" - [(set_attr "type" "simd_logic") - (set_attr "mode" "V4DF")]) - -(define_insn "negv8sf2" - [(set (match_operand:V8SF 0 "register_operand" "=f") - (neg:V8SF (match_operand:V8SF 1 "register_operand" "f")))] - "ISA_HAS_LASX" - "xvbitrevi.w\t%u0,%u1,31" - [(set_attr "type" "simd_logic") - (set_attr "mode" "V8SF")]) - (define_insn "xvfmadd<mode>4" [(set (match_operand:FLASX 0 "register_operand" "=f") (fma:FLASX (match_operand:FLASX 1 "register_operand" "f") diff --git a/gcc/config/loongarch/loongarch-def.h b/gcc/config/loongarch/loongarch-def.h index a1237ec..2dbf006 100644 --- a/gcc/config/loongarch/loongarch-def.h +++ b/gcc/config/loongarch/loongarch-def.h @@ -203,5 +203,8 @@ extern loongarch_def_array<loongarch_align, N_TUNE_TYPES> loongarch_cpu_align; extern loongarch_def_array<loongarch_rtx_cost_data, N_TUNE_TYPES> loongarch_cpu_rtx_cost_data; +extern loongarch_def_array< + loongarch_def_array<loongarch_isa, N_ABI_EXT_TYPES>, + N_ABI_BASE_TYPES> abi_minimal_isa; #endif /* LOONGARCH_DEF_H */ diff --git a/gcc/config/loongarch/loongarch-opts.cc b/gcc/config/loongarch/loongarch-opts.cc index b872995..7eeac43 100644 --- a/gcc/config/loongarch/loongarch-opts.cc +++ b/gcc/config/loongarch/loongarch-opts.cc @@ -53,8 +53,6 @@ static const int tm_multilib_list[] = { TM_MULTILIB_LIST }; static int enabled_abi_types[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES] = { 0 }; #define isa_required(ABI) (abi_minimal_isa[(ABI).base][(ABI).ext]) -extern "C" const struct loongarch_isa -abi_minimal_isa[N_ABI_BASE_TYPES][N_ABI_EXT_TYPES]; static inline int is_multilib_enabled (struct loongarch_abi abi) diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h index 9ffc92a..1fdfda9 100644 --- a/gcc/config/loongarch/loongarch-protos.h +++ b/gcc/config/loongarch/loongarch-protos.h @@ -222,4 +222,5 @@ extern rtx loongarch_build_signbit_mask (machine_mode, bool, bool); extern void loongarch_emit_swrsqrtsf (rtx, rtx, machine_mode, bool); extern void loongarch_emit_swdivsf (rtx, rtx, rtx, machine_mode); extern bool loongarch_explicit_relocs_p (enum loongarch_symbol_type); +extern bool loongarch_symbol_extreme_p (enum loongarch_symbol_type); #endif /* ! GCC_LOONGARCH_PROTOS_H */ diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index b494040..0428b6e 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -1935,8 +1935,13 @@ loongarch_symbolic_constant_p (rtx x, enum loongarch_symbol_type *symbol_type) relocations. */ switch (*symbol_type) { - case SYMBOL_PCREL: case SYMBOL_PCREL64: + /* When the code model is extreme, the non-zero offset situation + has not been handled well, so it is disabled here now. */ + if (!loongarch_explicit_relocs_p (SYMBOL_PCREL64)) + return false; + /* fall through */ + case SYMBOL_PCREL: /* GAS rejects offsets outside the range [-2^31, 2^31-1]. */ return sext_hwi (INTVAL (offset), 32) == INTVAL (offset); @@ -1966,6 +1971,10 @@ loongarch_explicit_relocs_p (enum loongarch_symbol_type type) if (la_opt_explicit_relocs != EXPLICIT_RELOCS_AUTO) return la_opt_explicit_relocs == EXPLICIT_RELOCS_ALWAYS; + /* The linker don't know how to relax accesses in extreme code model. */ + if (loongarch_symbol_extreme_p (type)) + return true; + switch (type) { case SYMBOL_TLS_IE: @@ -1977,11 +1986,6 @@ loongarch_explicit_relocs_p (enum loongarch_symbol_type type) does not relax 64-bit pc-relative accesses as at now. */ return true; case SYMBOL_GOT_DISP: - /* The linker don't know how to relax GOT accesses in extreme - code model. */ - if (TARGET_CMODEL_EXTREME) - return true; - /* If we are performing LTO for a final link, and we have the linker plugin so we know the resolution of the symbols, then all GOT references are binding to external symbols or @@ -2003,7 +2007,8 @@ loongarch_symbol_insns (enum loongarch_symbol_type type, machine_mode mode) { /* LSX LD.* and ST.* cannot support loading symbols via an immediate operand. */ - if (LSX_SUPPORTED_MODE_P (mode) || LASX_SUPPORTED_MODE_P (mode)) + if (mode != MAX_MACHINE_MODE + && (LSX_SUPPORTED_MODE_P (mode) || LASX_SUPPORTED_MODE_P (mode))) return 0; switch (type) @@ -2733,39 +2738,21 @@ loongarch_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset) return plus_constant (Pmode, reg, offset); } -/* The __tls_get_attr symbol. */ +/* The __tls_get_addr symbol. */ static GTY (()) rtx loongarch_tls_symbol; -/* Load an entry from the GOT for a TLS GD access. */ +/* Load an entry for a TLS access. */ static rtx -loongarch_got_load_tls_gd (rtx dest, rtx sym) +loongarch_load_tls (rtx dest, rtx sym, enum loongarch_symbol_type type) { - return gen_got_load_tls_gd (Pmode, dest, sym); -} + /* TLS LE gets a 32 or 64 bit offset here, so one register can do it. */ + if (type == SYMBOL_TLS_LE) + return gen_load_tls (Pmode, dest, sym); -/* Load an entry from the GOT for a TLS LD access. */ - -static rtx -loongarch_got_load_tls_ld (rtx dest, rtx sym) -{ - return gen_got_load_tls_ld (Pmode, dest, sym); -} - -/* Load an entry from the GOT for a TLS IE access. */ - -static rtx -loongarch_got_load_tls_ie (rtx dest, rtx sym) -{ - return gen_got_load_tls_ie (Pmode, dest, sym); -} - -/* Add in the thread pointer for a TLS LE access. */ - -static rtx -loongarch_got_load_tls_le (rtx dest, rtx sym) -{ - return gen_got_load_tls_le (Pmode, dest, sym); + return loongarch_symbol_extreme_p (type) + ? gen_movdi_symbolic_off64 (dest, sym, gen_reg_rtx (DImode)) + : gen_load_tls (Pmode, dest, sym); } /* Return an instruction sequence that calls __tls_get_addr. SYM is @@ -2789,34 +2776,27 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) start_sequence (); - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_ALWAYS) + if (loongarch_explicit_relocs_p (type)) { - /* Split tls symbol to high and low. */ - rtx high = gen_rtx_HIGH (Pmode, copy_rtx (loc)); - high = loongarch_force_temporary (tmp, high); - if (TARGET_CMODEL_EXTREME) { - gcc_assert (TARGET_EXPLICIT_RELOCS); + rtx part1 = gen_reg_rtx (Pmode); + rtx part2 = gen_reg_rtx (Pmode); - rtx tmp1 = gen_reg_rtx (Pmode); - emit_insn (gen_tls_low (Pmode, tmp1, gen_rtx_REG (Pmode, 0), loc)); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loc)); - emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loc)); - emit_move_insn (a0, gen_rtx_PLUS (Pmode, high, tmp1)); + emit_insn (gen_la_pcrel64_two_parts (part1, part2, loc)); + emit_move_insn (a0, gen_rtx_PLUS (Pmode, part1, part2)); } else - emit_insn (gen_tls_low (Pmode, a0, high, loc)); + { + /* Split tls symbol to high and low. */ + rtx high = gen_rtx_HIGH (Pmode, copy_rtx (loc)); + + high = loongarch_force_temporary (tmp, high); + emit_insn (gen_tls_low (Pmode, a0, high, loc)); + } } else - { - if (type == SYMBOL_TLSLDM) - emit_insn (loongarch_got_load_tls_ld (a0, loc)); - else if (type == SYMBOL_TLSGD) - emit_insn (loongarch_got_load_tls_gd (a0, loc)); - else - gcc_unreachable (); - } + emit_insn (loongarch_load_tls (a0, loc, type)); if (flag_plt) { @@ -2830,17 +2810,27 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_MEDIUM: { - rtx reg = gen_reg_rtx (Pmode); - if (TARGET_EXPLICIT_RELOCS) + if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) { - emit_insn (gen_pcalau12i (Pmode, reg, loongarch_tls_symbol)); - rtx call = gen_call_value_internal_1 (Pmode, v0, reg, - loongarch_tls_symbol, - const0_rtx); - insn = emit_call_insn (call); + rtx call; + + if (HAVE_AS_SUPPORT_CALL36) + call = gen_call_value_internal (v0, loongarch_tls_symbol, + const0_rtx); + else + { + rtx reg = gen_reg_rtx (Pmode); + emit_insn (gen_pcalau12i (Pmode, reg, + loongarch_tls_symbol)); + call = gen_call_value_internal_1 (Pmode, v0, reg, + loongarch_tls_symbol, + const0_rtx); + } + insn = emit_call_insn (call); } else { + rtx reg = gen_reg_rtx (Pmode); emit_move_insn (reg, loongarch_tls_symbol); insn = emit_call_insn (gen_call_value_internal (v0, reg, @@ -2867,7 +2857,7 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_NORMAL: case CMODEL_MEDIUM: { - if (TARGET_EXPLICIT_RELOCS) + if (loongarch_explicit_relocs_p (SYMBOL_GOT_DISP)) { rtx high = gen_reg_rtx (Pmode); loongarch_emit_move (high, @@ -2883,22 +2873,34 @@ loongarch_call_tls_get_addr (rtx sym, enum loongarch_symbol_type type, rtx v0) case CMODEL_EXTREME: { - gcc_assert (TARGET_EXPLICIT_RELOCS); - - rtx tmp1 = gen_reg_rtx (Pmode); - rtx high = gen_reg_rtx (Pmode); - - loongarch_emit_move (high, - gen_rtx_HIGH (Pmode, loongarch_tls_symbol)); - loongarch_emit_move (tmp1, gen_rtx_LO_SUM (Pmode, - gen_rtx_REG (Pmode, 0), - loongarch_tls_symbol)); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, loongarch_tls_symbol)); - emit_insn (gen_lui_h_hi12 (tmp1, tmp1, loongarch_tls_symbol)); - loongarch_emit_move (dest, - gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, - high, tmp1))); + if (loongarch_explicit_relocs_p (SYMBOL_GOT_DISP)) + { + gcc_assert (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE); + + rtx part1 = gen_reg_rtx (Pmode); + rtx part2 = gen_reg_rtx (Pmode); + + emit_insn (gen_la_pcrel64_two_parts (part1, part2, + loongarch_tls_symbol)); + loongarch_emit_move ( + dest, + gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, + part1, + part2))); + + /* Put an REG_EQUAL note here to allow CSE (storing + part1 + part2, i.e. the address of tls_get_addr into + a saved register and use it for multiple TLS + accesses). */ + rtx sum = gen_rtx_UNSPEC ( + Pmode, gen_rtvec (1, loongarch_tls_symbol), + UNSPEC_ADDRESS_FIRST + + loongarch_classify_symbol (loongarch_tls_symbol)); + set_unique_reg_note (get_last_insn (), REG_EQUAL, sum); + } + else + emit_insn (gen_movdi_symbolic_off64 (dest, loongarch_tls_symbol, + gen_reg_rtx (DImode))); } break; @@ -2953,33 +2955,37 @@ loongarch_legitimize_tls_address (rtx loc) /* la.tls.ie; tp-relative add. */ tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM); tmp1 = gen_reg_rtx (Pmode); + tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_IE); dest = gen_reg_rtx (Pmode); - if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) + if (loongarch_explicit_relocs_p (SYMBOL_TLS_IE)) { - tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_IE); - tmp3 = gen_reg_rtx (Pmode); - rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); - high = loongarch_force_temporary (tmp3, high); - if (TARGET_CMODEL_EXTREME) { - gcc_assert (TARGET_EXPLICIT_RELOCS); + gcc_assert (la_opt_explicit_relocs + != EXPLICIT_RELOCS_NONE); + + rtx part1 = gen_reg_rtx (Pmode); + rtx part2 = gen_reg_rtx (Pmode); - rtx tmp3 = gen_reg_rtx (Pmode); - emit_insn (gen_tls_low (Pmode, tmp3, - gen_rtx_REG (Pmode, 0), tmp2)); - emit_insn (gen_lui_h_lo20 (tmp3, tmp3, tmp2)); - emit_insn (gen_lui_h_hi12 (tmp3, tmp3, tmp2)); + emit_insn (gen_la_pcrel64_two_parts (part1, part2, + tmp2)); emit_move_insn (tmp1, gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, - high, tmp3))); + part1, + part2))); } else - emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2)); + { + tmp3 = gen_reg_rtx (Pmode); + rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); + + high = loongarch_force_temporary (tmp3, high); + emit_insn (gen_ld_from_got (Pmode, tmp1, high, tmp2)); + } } else - emit_insn (loongarch_got_load_tls_ie (tmp1, loc)); + emit_insn (loongarch_load_tls (tmp1, tmp2, SYMBOL_TLS_IE)); emit_insn (gen_add3_insn (dest, tmp1, tp)); } break; @@ -3011,11 +3017,11 @@ loongarch_legitimize_tls_address (rtx loc) tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM); tmp1 = gen_reg_rtx (Pmode); + tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_LE); dest = gen_reg_rtx (Pmode); - if (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE) + if (loongarch_explicit_relocs_p (SYMBOL_TLS_LE)) { - tmp2 = loongarch_unspec_address (loc, SYMBOL_TLS_LE); tmp3 = gen_reg_rtx (Pmode); rtx high = gen_rtx_HIGH (Pmode, copy_rtx (tmp2)); high = loongarch_force_temporary (tmp3, high); @@ -3036,14 +3042,12 @@ loongarch_legitimize_tls_address (rtx loc) if (TARGET_CMODEL_EXTREME) { - gcc_assert (TARGET_EXPLICIT_RELOCS); - emit_insn (gen_lui_h_lo20 (tmp1, tmp1, tmp2)); emit_insn (gen_lui_h_hi12 (tmp1, tmp1, tmp2)); } } else - emit_insn (loongarch_got_load_tls_le (tmp1, loc)); + emit_insn (loongarch_load_tls (tmp1, tmp2, SYMBOL_TLS_LE)); emit_insn (gen_add3_insn (dest, tmp1, tp)); } break; @@ -3116,7 +3120,7 @@ loongarch_force_address (rtx x, machine_mode mode) return x; } -static bool +bool loongarch_symbol_extreme_p (enum loongarch_symbol_type type) { switch (type) @@ -3157,24 +3161,23 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) || !loongarch_split_symbol_type (symbol_type)) return false; - rtx high, temp1 = NULL; + rtx high; if (temp == NULL) temp = gen_reg_rtx (Pmode); - /* Get the 12-31 bits of the address. */ - high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); - high = loongarch_force_temporary (temp, high); - if (loongarch_symbol_extreme_p (symbol_type) && can_create_pseudo_p ()) { gcc_assert (la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE); - temp1 = gen_reg_rtx (Pmode); - emit_move_insn (temp1, gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, 0), - addr)); - emit_insn (gen_lui_h_lo20 (temp1, temp1, addr)); - emit_insn (gen_lui_h_hi12 (temp1, temp1, addr)); + high = gen_reg_rtx (Pmode); + emit_insn (gen_la_pcrel64_two_parts (high, temp, addr)); + } + else + { + /* Get the 12-31 bits of the address. */ + high = gen_rtx_HIGH (Pmode, copy_rtx (addr)); + high = loongarch_force_temporary (temp, high); } if (low_out) @@ -3183,7 +3186,7 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) case SYMBOL_PCREL64: if (can_create_pseudo_p ()) { - *low_out = gen_rtx_PLUS (Pmode, high, temp1); + *low_out = gen_rtx_PLUS (Pmode, high, temp); break; } /* fall through */ @@ -3195,7 +3198,8 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) /* SYMBOL_GOT_DISP symbols are loaded from the GOT. */ { if (TARGET_CMODEL_EXTREME && can_create_pseudo_p ()) - *low_out = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, high, temp1)); + *low_out = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, high, + temp)); else { rtx low = gen_rtx_LO_SUM (Pmode, high, addr); @@ -3219,6 +3223,22 @@ loongarch_split_symbol (rtx temp, rtx addr, machine_mode mode, rtx *low_out) return true; } +/* Helper loongarch_legitimize_address. Given X, return true if it + is a left shift by 1, 2 or 3 positions or a multiply by 2, 4 or 8. + + This respectively represent canonical shift-add rtxs or scaled + memory addresses. */ +static bool +mem_shadd_or_shadd_rtx_p (rtx x) +{ + return ((GET_CODE (x) == ASHIFT + || GET_CODE (x) == MULT) + && CONST_INT_P (XEXP (x, 1)) + && ((GET_CODE (x) == ASHIFT && IN_RANGE (INTVAL (XEXP (x, 1)), 1, 3)) + || (GET_CODE (x) == MULT + && IN_RANGE (exact_log2 (INTVAL (XEXP (x, 1))), 1, 3)))); +} + /* This function is used to implement LEGITIMIZE_ADDRESS. If X can be legitimized in a way that the generic machinery might not expect, return a new address, otherwise return NULL. MODE is the mode of @@ -3242,6 +3262,33 @@ loongarch_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, loongarch_split_plus (x, &base, &offset); if (offset != 0) { + /* Handle (plus (plus (mult (a) (mem_shadd_constant)) (fp)) (C)) case. */ + if (GET_CODE (base) == PLUS && mem_shadd_or_shadd_rtx_p (XEXP (base, 0)) + && IMM12_OPERAND (offset)) + { + rtx index = XEXP (base, 0); + rtx fp = XEXP (base, 1); + + if (REG_P (fp) && REGNO (fp) == VIRTUAL_STACK_VARS_REGNUM) + { + /* If we were given a MULT, we must fix the constant + as we're going to create the ASHIFT form. */ + int shift_val = INTVAL (XEXP (index, 1)); + if (GET_CODE (index) == MULT) + shift_val = exact_log2 (shift_val); + + rtx reg1 = gen_reg_rtx (Pmode); + rtx reg3 = gen_reg_rtx (Pmode); + loongarch_emit_binary (PLUS, reg1, fp, GEN_INT (offset)); + loongarch_emit_binary (PLUS, reg3, + gen_rtx_ASHIFT (Pmode, XEXP (index, 0), + GEN_INT (shift_val)), + reg1); + + return reg3; + } + } + if (!loongarch_valid_base_register_p (base, mode, false)) base = copy_to_mode_reg (Pmode, base); addr = loongarch_add_offset (NULL, base, offset); @@ -3394,6 +3441,21 @@ loongarch_legitimize_move (machine_mode mode, rtx dest, rtx src) return true; } + /* Obtain the address of the symbol through the macro instruction + of two registers. */ + enum loongarch_symbol_type symbol_type; + if (TARGET_64BIT && register_operand (dest, mode) + && loongarch_symbolic_constant_p (src, &symbol_type) + && loongarch_symbol_extreme_p (symbol_type)) + { + gcc_assert (can_create_pseudo_p ()); + rtx tmp_reg = gen_reg_rtx (DImode); + emit_insn (gen_movdi_symbolic_off64 (dest, src, tmp_reg)); + set_unique_reg_note (get_last_insn (), REG_UNUSED, tmp_reg); + set_unique_reg_note (get_last_insn (), REG_EQUAL, src); + return true; + } + return false; } @@ -4096,6 +4158,37 @@ loongarch_vector_costs::determine_suggested_unroll_factor (loop_vec_info loop_vi return 1 << ceil_log2 (uf); } +/* Check if assign stmt rhs op comes from a multiply-add operation. */ +static bool +loongarch_multiply_add_p (vec_info *vinfo, stmt_vec_info stmt_info) +{ + gassign *assign = dyn_cast<gassign *> (stmt_info->stmt); + if (!assign) + return false; + tree_code code = gimple_assign_rhs_code (assign); + if (code != PLUS_EXPR && code != MINUS_EXPR) + return false; + + auto is_mul_result = [&](int i) + { + tree rhs = gimple_op (assign, i); + if (TREE_CODE (rhs) != SSA_NAME) + return false; + + stmt_vec_info def_stmt_info = vinfo->lookup_def (rhs); + if (!def_stmt_info + || STMT_VINFO_DEF_TYPE (def_stmt_info) != vect_internal_def) + return false; + gassign *rhs_assign = dyn_cast<gassign *> (def_stmt_info->stmt); + if (!rhs_assign || gimple_assign_rhs_code (rhs_assign) != MULT_EXPR) + return false; + + return true; + }; + + return is_mul_result (1) || is_mul_result (2); +} + unsigned loongarch_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, stmt_vec_info stmt_info, slp_tree, @@ -4108,6 +4201,23 @@ loongarch_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind, { int stmt_cost = loongarch_builtin_vectorization_cost (kind, vectype, misalign); + if (vectype && stmt_info) + { + gassign *assign = dyn_cast<gassign *> (STMT_VINFO_STMT (stmt_info)); + machine_mode mode = TYPE_MODE (vectype); + + /* We found through testing that this strategy (the stmt that + matches the multiply-add pattern) has positive returns only + when applied to the 128-bit vector stmt, so this restriction + is currently made. */ + if (kind == vector_stmt && GET_MODE_SIZE (mode) == 16 && assign) + { + if (!vect_is_reduction (stmt_info) + && loongarch_multiply_add_p (m_vinfo, stmt_info)) + stmt_cost = 0; + } + } + retval = adjust_cost_for_freq (stmt_info, where, count * stmt_cost); m_costs[where] += retval; @@ -7450,12 +7560,25 @@ loongarch_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, allowed, otherwise load the address into a register first. */ if (use_sibcall_p) { + /* If TARGET_CMODEL_EXTREME, we cannot do a direct jump at all + and const_call_insn_operand should have returned false. */ + gcc_assert (!TARGET_CMODEL_EXTREME); + insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx)); SIBLING_CALL_P (insn) = 1; } else { - loongarch_emit_move (temp1, fnaddr); + if (!TARGET_CMODEL_EXTREME) + loongarch_emit_move (temp1, fnaddr); + else if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) + emit_insn (gen_movdi_symbolic_off64 (temp1, fnaddr, temp2)); + else + { + emit_insn (gen_la_pcrel64_two_parts (temp1, temp2, fnaddr)); + emit_move_insn (temp1, gen_rtx_PLUS (Pmode, temp1, temp2)); + } + emit_jump_insn (gen_indirect_jump (temp1)); } @@ -7560,10 +7683,6 @@ loongarch_option_override_internal (struct gcc_options *opts, switch (la_target.cmodel) { case CMODEL_EXTREME: - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) - error ("code model %qs is not compatible with %s", - "extreme", "-mexplicit-relocs=none"); - if (opts->x_flag_plt) { if (global_options_set.x_flag_plt) @@ -7911,7 +8030,8 @@ struct expand_vec_perm_d static bool loongarch_expand_vselect (rtx target, rtx op0, - const unsigned char *perm, unsigned nelt) + const unsigned char *perm, unsigned nelt, + bool testing_p) { rtx rperm[MAX_VECT_LEN], x; rtx_insn *insn; @@ -7930,6 +8050,9 @@ loongarch_expand_vselect (rtx target, rtx op0, remove_insn (insn); return false; } + + if (testing_p) + remove_insn (insn); return true; } @@ -7937,7 +8060,8 @@ loongarch_expand_vselect (rtx target, rtx op0, static bool loongarch_expand_vselect_vconcat (rtx target, rtx op0, rtx op1, - const unsigned char *perm, unsigned nelt) + const unsigned char *perm, unsigned nelt, + bool testing_p) { machine_mode v2mode; rtx x; @@ -7945,7 +8069,7 @@ loongarch_expand_vselect_vconcat (rtx target, rtx op0, rtx op1, if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode)) return false; x = gen_rtx_VEC_CONCAT (v2mode, op0, op1); - return loongarch_expand_vselect (target, x, perm, nelt); + return loongarch_expand_vselect (target, x, perm, nelt, testing_p); } static tree @@ -7981,14 +8105,6 @@ loongarch_handle_model_attribute (tree *node, tree name, tree arg, int, *no_add_attrs = true; return NULL_TREE; } - if (la_opt_explicit_relocs == EXPLICIT_RELOCS_NONE) - { - error_at (DECL_SOURCE_LOCATION (decl), - "%qE attribute is not compatible with %s", name, - "-mexplicit-relocs=none"); - *no_add_attrs = true; - return NULL_TREE; - } arg = TREE_VALUE (arg); if (TREE_CODE (arg) != STRING_CST) @@ -8207,11 +8323,87 @@ loongarch_set_handled_components (sbitmap components) #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" #undef TARGET_ASM_ALIGNED_DI_OP #define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t" + +/* Use the vshuf instruction to implement all 128-bit constant vector + permuatation. */ + +static bool +loongarch_try_expand_lsx_vshuf_const (struct expand_vec_perm_d *d) +{ + int i; + rtx target, op0, op1, sel, tmp; + rtx rperm[MAX_VECT_LEN]; + + if (GET_MODE_SIZE (d->vmode) == 16) + { + target = d->target; + op0 = d->op0; + op1 = d->one_vector_p ? d->op0 : d->op1; + + if (GET_MODE (op0) != GET_MODE (op1) + || GET_MODE (op0) != GET_MODE (target)) + return false; + + if (d->testing_p) + return true; + + for (i = 0; i < d->nelt; i += 1) + rperm[i] = GEN_INT (d->perm[i]); + + if (d->vmode == E_V2DFmode) + { + sel = gen_rtx_CONST_VECTOR (E_V2DImode, gen_rtvec_v (d->nelt, rperm)); + tmp = simplify_gen_subreg (E_V2DImode, d->target, d->vmode, 0); + emit_move_insn (tmp, sel); + } + else if (d->vmode == E_V4SFmode) + { + sel = gen_rtx_CONST_VECTOR (E_V4SImode, gen_rtvec_v (d->nelt, rperm)); + tmp = simplify_gen_subreg (E_V4SImode, d->target, d->vmode, 0); + emit_move_insn (tmp, sel); + } + else + { + sel = gen_rtx_CONST_VECTOR (d->vmode, gen_rtvec_v (d->nelt, rperm)); + emit_move_insn (d->target, sel); + } + + switch (d->vmode) + { + case E_V2DFmode: + emit_insn (gen_lsx_vshuf_d_f (target, target, op1, op0)); + break; + case E_V2DImode: + emit_insn (gen_lsx_vshuf_d (target, target, op1, op0)); + break; + case E_V4SFmode: + emit_insn (gen_lsx_vshuf_w_f (target, target, op1, op0)); + break; + case E_V4SImode: + emit_insn (gen_lsx_vshuf_w (target, target, op1, op0)); + break; + case E_V8HImode: + emit_insn (gen_lsx_vshuf_h (target, target, op1, op0)); + break; + case E_V16QImode: + emit_insn (gen_lsx_vshuf_b (target, op1, op0, target)); + break; + default: + break; + } + + return true; + } + return false; +} + /* Construct (set target (vec_select op0 (parallel selector))) and - return true if that's a valid instruction in the active ISA. */ + return true if that's a valid instruction in the active ISA. + In fact, it matches the special constant vector with repeated + 4-element sets. */ static bool -loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) +loongarch_is_imm_set_shuffle (struct expand_vec_perm_d *d) { rtx x, elts[MAX_VECT_LEN]; rtvec v; @@ -8230,6 +8422,9 @@ loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) if (!loongarch_const_vector_shuffle_set_p (x, d->vmode)) return false; + if (d->testing_p) + return true; + x = gen_rtx_VEC_SELECT (d->vmode, d->op0, x); x = gen_rtx_SET (d->target, x); @@ -8242,6 +8437,27 @@ loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) return true; } +static bool +loongarch_expand_vec_perm_even_odd (struct expand_vec_perm_d *); + +/* Try to match and expand all kinds of 128-bit const vector permutation + cases. */ + +static bool +loongarch_expand_lsx_shuffle (struct expand_vec_perm_d *d) +{ + if (!ISA_HAS_LSX && GET_MODE_SIZE (d->vmode) != 16) + return false; + + if (loongarch_is_imm_set_shuffle (d)) + return true; + + if (loongarch_expand_vec_perm_even_odd (d)) + return true; + + return loongarch_try_expand_lsx_vshuf_const (d); +} + /* Try to simplify a two vector permutation using 2 intra-lane interleave insns and cross-lane shuffle for 32-byte vectors. */ @@ -8334,7 +8550,7 @@ loongarch_expand_vec_perm_interleave (struct expand_vec_perm_d *d) return true; } -/* Implement extract-even and extract-odd permutations. */ +/* Implement 128-bit and 256-bit extract-even and extract-odd permutations. */ static bool loongarch_expand_vec_perm_even_odd_1 (struct expand_vec_perm_d *d, unsigned odd) @@ -8349,6 +8565,50 @@ loongarch_expand_vec_perm_even_odd_1 (struct expand_vec_perm_d *d, unsigned odd) switch (d->vmode) { + /* 128 bit. */ + case E_V2DFmode: + if (odd) + emit_insn (gen_lsx_vilvh_d_f (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vilvl_d_f (d->target, d->op0, d->op1)); + break; + + case E_V2DImode: + if (odd) + emit_insn (gen_lsx_vilvh_d (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vilvl_d (d->target, d->op0, d->op1)); + break; + + case E_V4SFmode: + if (odd) + emit_insn (gen_lsx_vpickod_w_f (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_w_f (d->target, d->op0, d->op1)); + break; + + case E_V4SImode: + if (odd) + emit_insn (gen_lsx_vpickod_w (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_w (d->target, d->op0, d->op1)); + break; + + case E_V8HImode: + if (odd) + emit_insn (gen_lsx_vpickod_h (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_h (d->target, d->op0, d->op1)); + break; + + case E_V16QImode: + if (odd) + emit_insn (gen_lsx_vpickod_b (d->target, d->op0, d->op1)); + else + emit_insn (gen_lsx_vpickev_b (d->target, d->op0, d->op1)); + break; + + /* 256 bit. */ case E_V4DFmode: /* Shuffle the lanes around into { 0 4 2 6 } and { 1 5 3 7 }. */ if (odd) @@ -8423,7 +8683,7 @@ static bool loongarch_expand_vec_perm_even_odd (struct expand_vec_perm_d *d) { unsigned i, odd, nelt = d->nelt; - if (!ISA_HAS_LASX) + if (!ISA_HAS_LASX && !ISA_HAS_LSX) return false; odd = d->perm[0]; @@ -8887,44 +9147,6 @@ loongarch_is_quad_duplicate (struct expand_vec_perm_d *d) } static bool -loongarch_is_odd_extraction (struct expand_vec_perm_d *d) -{ - bool result = true; - unsigned char buf = 1; - - for (int i = 0; i < d->nelt; i += 1) - { - if (buf != d->perm[i]) - { - result = false; - break; - } - buf += 2; - } - - return result; -} - -static bool -loongarch_is_even_extraction (struct expand_vec_perm_d *d) -{ - bool result = true; - unsigned char buf = 0; - - for (int i = 0; i < d->nelt; i += 1) - { - if (buf != d->perm[i]) - { - result = false; - break; - } - buf += 2; - } - - return result; -} - -static bool loongarch_is_extraction_permutation (struct expand_vec_perm_d *d) { bool result = true; @@ -9180,32 +9402,29 @@ loongarch_expand_vec_perm_const (struct expand_vec_perm_d *d) for (i = 1; i < d->nelt; i += 2) perm2[i] += d->nelt; if (loongarch_expand_vselect_vconcat (d->target, d->op0, d->op1, - perm2, d->nelt)) + perm2, d->nelt, d->testing_p)) return true; } else { if (loongarch_expand_vselect_vconcat (d->target, d->op0, d->op1, - d->perm, d->nelt)) + d->perm, d->nelt, + d->testing_p)) return true; /* Try again with swapped operands. */ for (i = 0; i < d->nelt; ++i) perm2[i] = (d->perm[i] + d->nelt) & (2 * d->nelt - 1); if (loongarch_expand_vselect_vconcat (d->target, d->op1, d->op0, - perm2, d->nelt)) + perm2, d->nelt, d->testing_p)) return true; } - if (loongarch_expand_lsx_shuffle (d)) + if (loongarch_is_imm_set_shuffle (d)) return true; - if (loongarch_is_odd_extraction (d) - || loongarch_is_even_extraction (d)) - { - if (loongarch_expand_vec_perm_even_odd (d)) - return true; - } + if (loongarch_expand_vec_perm_even_odd (d)) + return true; if (loongarch_is_lasx_lowpart_interleave (d) || loongarch_is_lasx_lowpart_interleave_2 (d) diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index dda3cdf..dffa41b 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -51,10 +51,7 @@ UNSPEC_BITREV_8B ;; TLS - UNSPEC_TLS_GD - UNSPEC_TLS_LD - UNSPEC_TLS_LE - UNSPEC_TLS_IE + UNSPEC_TLS ;; Stack tie UNSPEC_TIE @@ -85,6 +82,10 @@ UNSPEC_SIBCALL_VALUE_MULTIPLE_INTERNAL_1 UNSPEC_CALL_VALUE_MULTIPLE_INTERNAL_1 + + UNSPEC_LOAD_SYMBOL_OFFSET64 + UNSPEC_LA_PCREL_64_PART1 + UNSPEC_LA_PCREL_64_PART2 ]) (define_c_enum "unspecv" [ @@ -2185,6 +2186,64 @@ [(set_attr "move_type" "move,const,load,store,mgtf,fpload,mftg,fpstore") (set_attr "mode" "DI")]) +;; Use two registers to get the global symbol address from the got table. +;; la.global rd, rt, sym + +(define_insn_and_split "movdi_symbolic_off64" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (match_operand:DI 1 "symbolic_off64_or_reg_operand" "Yd,r")) + (unspec:DI [(const_int 0)] + UNSPEC_LOAD_SYMBOL_OFFSET64) + (clobber (match_operand:DI 2 "register_operand" "=&r,r"))] + "TARGET_64BIT && TARGET_CMODEL_EXTREME" +{ + if (which_alternative == 1) + return "#"; + + enum loongarch_symbol_type symbol_type; + gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type)); + + switch (symbol_type) + { + case SYMBOL_PCREL64: + return "la.local\t%0,%2,%1"; + case SYMBOL_GOT_DISP: + return "la.global\t%0,%2,%1"; + case SYMBOL_TLS_IE: + return "la.tls.ie\t%0,%2,%1"; + case SYMBOL_TLSGD: + return "la.tls.gd\t%0,%2,%1"; + case SYMBOL_TLSLDM: + return "la.tls.ld\t%0,%2,%1"; + + default: + gcc_unreachable (); + } +} + "&& REG_P (operands[1]) && find_reg_note (insn, REG_UNUSED, operands[2]) != 0" + [(set (match_dup 0) (match_dup 1))] + "" + [(set_attr "mode" "DI") + (set_attr "insn_count" "5")]) + +;; The 64-bit PC-relative part of address loading. +;; Note that the psABI does not allow splitting it. +(define_insn "la_pcrel64_two_parts" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 2 "") (pc)] UNSPEC_LA_PCREL_64_PART1)) + (set (match_operand:DI 1 "register_operand" "=r") + (unspec:DI [(match_dup 2) (pc)] UNSPEC_LA_PCREL_64_PART2))] + "TARGET_ABI_LP64 && la_opt_explicit_relocs != EXPLICIT_RELOCS_NONE" + { + return "pcalau12i\t%0,%r2\n\t" + "addi.d\t%1,$r0,%L2\n\t" + "lu32i.d\t%1,%R2\n\t" + "lu52i.d\t%1,%1,%H2"; + } + [(set_attr "move_type" "move") + (set_attr "mode" "DI") + (set_attr "length" "16")]) + ;; 32-bit Integer moves (define_expand "movsi" @@ -2701,45 +2760,37 @@ ;; Thread-Local Storage -(define_insn "@got_load_tls_gd<mode>" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P - [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_GD))] - "" - "la.tls.gd\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) - -(define_insn "@got_load_tls_ld<mode>" +(define_insn "@load_tls<mode>" [(set (match_operand:P 0 "register_operand" "=r") (unspec:P [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_LD))] + UNSPEC_TLS))] "" - "la.tls.ld\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) +{ + enum loongarch_symbol_type symbol_type; + gcc_assert (loongarch_symbolic_constant_p (operands[1], &symbol_type)); -(define_insn "@got_load_tls_le<mode>" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P - [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_LE))] - "" - "la.tls.le\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) + switch (symbol_type) + { + case SYMBOL_TLS_LE: + return "la.tls.le\t%0,%1"; + case SYMBOL_TLS_IE: + return "la.tls.ie\t%0,%1"; + case SYMBOL_TLSLDM: + return "la.tls.ld\t%0,%1"; + case SYMBOL_TLSGD: + return "la.tls.gd\t%0,%1"; -(define_insn "@got_load_tls_ie<mode>" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P - [(match_operand:P 1 "symbolic_operand" "")] - UNSPEC_TLS_IE))] - "" - "la.tls.ie\t%0,%1" - [(set_attr "got" "load") - (set_attr "mode" "<MODE>")]) + default: + gcc_unreachable (); + } +} + [(set_attr "mode" "<MODE>") + (set (attr "insn_count") + (if_then_else + (match_test "TARGET_CMODEL_EXTREME") + (const_int 4) + (const_int 2)))]) ;; Move operand 1 to the high word of operand 0 using movgr2frh.w, preserving the ;; value in the low word. diff --git a/gcc/config/loongarch/lsx.md b/gcc/config/loongarch/lsx.md index 7002eda..b9b94b9 100644 --- a/gcc/config/loongarch/lsx.md +++ b/gcc/config/loongarch/lsx.md @@ -728,17 +728,6 @@ DONE; }) -(define_expand "neg<mode>2" - [(set (match_operand:FLSX 0 "register_operand") - (neg:FLSX (match_operand:FLSX 1 "register_operand")))] - "ISA_HAS_LSX" -{ - rtx reg = gen_reg_rtx (<MODE>mode); - emit_move_insn (reg, CONST0_RTX (<MODE>mode)); - emit_insn (gen_sub<mode>3 (operands[0], reg, operands[1])); - DONE; -}) - (define_expand "lsx_vrepli<mode>" [(match_operand:ILSX 0 "register_operand") (match_operand 1 "const_imm10_operand")] diff --git a/gcc/config/loongarch/predicates.md b/gcc/config/loongarch/predicates.md index 01aad8d..eba7f24 100644 --- a/gcc/config/loongarch/predicates.md +++ b/gcc/config/loongarch/predicates.md @@ -576,6 +576,18 @@ || symbolic_pcrel_offset_operand (op, Pmode)); }) +(define_predicate "symbolic_off64_operand" + (match_code "const,symbol_ref,label_ref") +{ + enum loongarch_symbol_type type; + return loongarch_symbolic_constant_p (op, &type) + && loongarch_symbol_extreme_p (type); +}) + +(define_predicate "symbolic_off64_or_reg_operand" + (ior (match_operand 0 "register_operand") + (match_operand 0 "symbolic_off64_operand"))) + (define_predicate "equality_operator" (match_code "eq,ne")) diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md index cb0a194..00ff282 100644 --- a/gcc/config/loongarch/simd.md +++ b/gcc/config/loongarch/simd.md @@ -85,12 +85,21 @@ (define_mode_attr simdifmt_for_f [(V2DF "l") (V4DF "l") (V4SF "w") (V8SF "w")]) +;; Suffix for integer mode in LSX or LASX instructions to operating FP +;; vectors using integer vector operations. +(define_mode_attr simdfmt_as_i [(V2DF "d") (V4DF "d") + (V4SF "w") (V8SF "w")]) + ;; Size of vector elements in bits. (define_mode_attr elmbits [(V2DI "64") (V4DI "64") (V4SI "32") (V8SI "32") (V8HI "16") (V16HI "16") (V16QI "8") (V32QI "8")]) +;; The index of sign bit in FP vector elements. +(define_mode_attr elmsgnbit [(V2DF "63") (V4DF "63") + (V4SF "31") (V8SF "31")]) + ;; This attribute is used to form an immediate operand constraint using ;; "const_<bitimm>_operand". (define_mode_attr bitimm [(V16QI "uimm3") (V32QI "uimm3") @@ -457,6 +466,15 @@ DONE; }) +;; FP negation. +(define_insn "neg<mode>2" + [(set (match_operand:FVEC 0 "register_operand" "=f") + (neg:FVEC (match_operand:FVEC 1 "register_operand" "f")))] + "" + "<x>vbitrevi.<simdfmt_as_i>\t%<wu>0,%<wu>1,<elmsgnbit>" + [(set_attr "type" "simd_logic") + (set_attr "mode" "<MODE>")]) + ; The LoongArch SX Instructions. (include "lsx.md") diff --git a/gcc/config/mips/mips-msa.md b/gcc/config/mips/mips-msa.md index 83d9a08..779157f 100644 --- a/gcc/config/mips/mips-msa.md +++ b/gcc/config/mips/mips-msa.md @@ -231,6 +231,10 @@ (V4SI "uimm5") (V2DI "uimm6")]) +;; The index of sign bit in FP vector elements. +(define_mode_attr elmsgnbit [(V2DF "63") (V4DF "63") + (V4SF "31") (V8SF "31")]) + (define_expand "vec_init<mode><unitmode>" [(match_operand:MSA 0 "register_operand") (match_operand:MSA 1 "")] @@ -597,9 +601,9 @@ }) (define_expand "neg<mode>2" - [(set (match_operand:MSA 0 "register_operand") - (minus:MSA (match_dup 2) - (match_operand:MSA 1 "register_operand")))] + [(set (match_operand:IMSA 0 "register_operand") + (minus:IMSA (match_dup 2) + (match_operand:IMSA 1 "register_operand")))] "ISA_HAS_MSA" { rtx reg = gen_reg_rtx (<MODE>mode); @@ -607,6 +611,14 @@ operands[2] = reg; }) +(define_insn "neg<mode>2" + [(set (match_operand:FMSA 0 "register_operand" "=f") + (neg:FMSA (match_operand:FMSA 1 "register_operand" "f")))] + "ISA_HAS_MSA" + "bnegi.<msafmt>\t%w0,%w1,<elmsgnbit>" + [(set_attr "type" "simd_bit") + (set_attr "mode" "<MODE>")]) + (define_expand "msa_ldi<mode>" [(match_operand:IMSA 0 "register_operand") (match_operand 1 "const_imm10_operand")] diff --git a/gcc/config/pa/pa.cc b/gcc/config/pa/pa.cc index c58b0a0..694123e 100644 --- a/gcc/config/pa/pa.cc +++ b/gcc/config/pa/pa.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "rtl.h" #include "tree.h" +#include "gimple.h" #include "df.h" #include "tm_p.h" #include "stringpool.h" @@ -142,6 +143,7 @@ static void pa_asm_out_destructor (rtx, int); #endif static void pa_init_builtins (void); static rtx pa_expand_builtin (tree, rtx, rtx, machine_mode mode, int); +static tree pa_builtin_decl (unsigned, bool); static rtx hppa_builtin_saveregs (void); static void hppa_va_start (tree, rtx); static tree hppa_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); @@ -205,6 +207,7 @@ static bool pa_modes_tieable_p (machine_mode, machine_mode); static bool pa_can_change_mode_class (machine_mode, machine_mode, reg_class_t); static HOST_WIDE_INT pa_starting_frame_offset (void); static section* pa_elf_select_rtx_section(machine_mode, rtx, unsigned HOST_WIDE_INT) ATTRIBUTE_UNUSED; +static void pa_atomic_assign_expand_fenv (tree *, tree *, tree *); /* The following extra sections are only used for SOM. */ static GTY(()) section *som_readonly_data_section; @@ -314,9 +317,10 @@ static size_t n_deferred_plabels = 0; #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS pa_init_builtins - #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN pa_expand_builtin +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL pa_builtin_decl #undef TARGET_REGISTER_MOVE_COST #define TARGET_REGISTER_MOVE_COST hppa_register_move_cost @@ -426,6 +430,9 @@ static size_t n_deferred_plabels = 0; #undef TARGET_HAVE_SPECULATION_SAFE_VALUE #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed +#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV +#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV pa_atomic_assign_expand_fenv + struct gcc_target targetm = TARGET_INITIALIZER; /* Parse the -mfixed-range= option string. */ @@ -592,6 +599,10 @@ pa_option_override (void) enum pa_builtins { + /* FPU builtins. */ + PA_BUILTIN_GET_FPSR, + PA_BUILTIN_SET_FPSR, + PA_BUILTIN_COPYSIGNQ, PA_BUILTIN_FABSQ, PA_BUILTIN_INFQ, @@ -600,10 +611,48 @@ enum pa_builtins }; static GTY(()) tree pa_builtins[(int) PA_BUILTIN_max]; +static GTY(()) enum insn_code pa_builtins_icode[(int) PA_BUILTIN_max]; + +/* Add a PA builtin function with NAME, ICODE, CODE and TYPE. Return the + function decl or NULL_TREE if the builtin was not added. */ + +static tree +def_builtin (const char *name, enum insn_code icode, enum pa_builtins code, + tree type) +{ + tree t + = add_builtin_function (name, type, code, BUILT_IN_MD, NULL, NULL_TREE); + + if (t) + { + pa_builtins[code] = t; + pa_builtins_icode[code] = icode; + } + + return t; +} + +/* Create builtin functions for FPU instructions. */ + +static void +pa_fpu_init_builtins (void) +{ + tree ftype; + + ftype = build_function_type_list (unsigned_type_node, 0); + def_builtin ("__builtin_get_fpsr", CODE_FOR_get_fpsr, + PA_BUILTIN_GET_FPSR, ftype); + ftype = build_function_type_list (void_type_node, unsigned_type_node, 0); + def_builtin ("__builtin_set_fpsr", CODE_FOR_set_fpsr, + PA_BUILTIN_SET_FPSR, ftype); +} static void pa_init_builtins (void) { + if (!TARGET_SOFT_FLOAT) + pa_fpu_init_builtins (); + #ifdef DONT_HAVE_FPUTC_UNLOCKED { tree decl = builtin_decl_explicit (BUILT_IN_PUTC_UNLOCKED); @@ -663,6 +712,92 @@ pa_init_builtins (void) } } +/* Implement TARGET_BUILTIN_DECL. */ + +static tree +pa_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= PA_BUILTIN_max) + return error_mark_node; + return pa_builtins[code]; +} + +static rtx +pa_expand_builtin_1 (tree exp, rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + machine_mode tmode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + enum pa_builtins code + = (enum pa_builtins) DECL_MD_FUNCTION_CODE (fndecl); + enum insn_code icode = pa_builtins_icode[code]; + bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; + call_expr_arg_iterator iter; + int arg_count = 0; + rtx pat, op[4]; + tree arg; + + if (nonvoid) + { + machine_mode tmode = insn_data[icode].operand[0].mode; + if (!target + || GET_MODE (target) != tmode + || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) + op[0] = gen_reg_rtx (tmode); + else + op[0] = target; + } + else + op[0] = NULL_RTX; + + FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) + { + const struct insn_operand_data *insn_op; + int idx; + + if (arg == error_mark_node) + return NULL_RTX; + + arg_count++; + idx = arg_count - !nonvoid; + insn_op = &insn_data[icode].operand[idx]; + op[arg_count] = expand_normal (arg); + + if (! (*insn_data[icode].operand[idx].predicate) (op[arg_count], + insn_op->mode)) + op[arg_count] = copy_to_mode_reg (insn_op->mode, op[arg_count]); + } + + switch (arg_count) + { + case 0: + pat = GEN_FCN (icode) (op[0]); + break; + case 1: + if (nonvoid) + pat = GEN_FCN (icode) (op[0], op[1]); + else + pat = GEN_FCN (icode) (op[1]); + break; + case 2: + pat = GEN_FCN (icode) (op[0], op[1], op[2]); + break; + case 3: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); + break; + default: + gcc_unreachable (); + } + + if (!pat) + return NULL_RTX; + + emit_insn (pat); + + return (nonvoid ? op[0] : const0_rtx); +} + static rtx pa_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, machine_mode mode ATTRIBUTE_UNUSED, @@ -673,6 +808,10 @@ pa_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, switch (fcode) { + case PA_BUILTIN_GET_FPSR: + case PA_BUILTIN_SET_FPSR: + return pa_expand_builtin_1 (exp, target, subtarget, mode, ignore); + case PA_BUILTIN_FABSQ: case PA_BUILTIN_COPYSIGNQ: return expand_call (exp, target, ignore); @@ -11099,4 +11238,78 @@ pa_function_arg_size (machine_mode mode, const_tree type) return (int) CEIL (size, UNITS_PER_WORD); } +/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */ + +static void +pa_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) +{ + const unsigned PA_FE_INEXACT = 1; + const unsigned PA_FE_UNDERFLOW = 2; + const unsigned PA_FE_OVERFLOW = 4; + const unsigned PA_FE_DIVBYZERO = 8; + const unsigned PA_FE_INVALID = 16; + const unsigned HOST_WIDE_INT PA_FE_ALL_EXCEPT = (PA_FE_INVALID + | PA_FE_DIVBYZERO + | PA_FE_OVERFLOW + | PA_FE_UNDERFLOW + | PA_FE_INEXACT); + const unsigned HOST_WIDE_INT PA_FE_EXCEPT_SHIFT = 27; + tree fenv_var, get_fpsr, set_fpsr, mask, ld_fenv, masked_fenv; + tree hold_all, new_fenv_var, reload_fenv, restore_fnenv; + tree get_fpsr_call, set_fpsr_call, update_call, atomic_feraiseexcept; + + if (TARGET_SOFT_FLOAT) + return; + + /* Generate the equivalent of : + unsigned int fenv_var; + fenv_var = __builtin_get_fpsr (); + + unsigned int masked_fenv; + masked_fenv = fenv_var & mask; + + __builtin_set_fpsr (masked_fenv); */ + + fenv_var = create_tmp_var_raw (unsigned_type_node); + get_fpsr = pa_builtins[PA_BUILTIN_GET_FPSR]; + set_fpsr = pa_builtins[PA_BUILTIN_SET_FPSR]; + mask = build_int_cst (unsigned_type_node, + ~((PA_FE_ALL_EXCEPT << PA_FE_EXCEPT_SHIFT) + | PA_FE_ALL_EXCEPT)); + + get_fpsr_call = build_call_expr (get_fpsr, 0); + ld_fenv = build4 (TARGET_EXPR, unsigned_type_node, + fenv_var, get_fpsr_call, + NULL_TREE, NULL_TREE); + masked_fenv = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_var, mask); + hold_all = build2 (COMPOUND_EXPR, void_type_node, masked_fenv, ld_fenv); + set_fpsr_call = build_call_expr (set_fpsr, 1, masked_fenv); + *hold = build2 (COMPOUND_EXPR, void_type_node, hold_all, set_fpsr_call); + + /* Store the value of masked_fenv to clear the exceptions: + __builtin_set_fpsr (masked_fenv); */ + + *clear = set_fpsr_call; + + /* Generate the equivalent of : + unsigned int new_fenv_var; + new_fenv_var = __builtin_get_fpsr (); + + __builtin_set_fpsr (fenv_var); + + __atomic_feraiseexcept (new_fenv_var); */ + + new_fenv_var = create_tmp_var_raw (unsigned_type_node); + reload_fenv = build4 (TARGET_EXPR, unsigned_type_node, new_fenv_var, + get_fpsr_call, NULL_TREE, NULL_TREE); + restore_fnenv = build_call_expr (set_fpsr, 1, fenv_var); + atomic_feraiseexcept = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT); + update_call = build_call_expr (atomic_feraiseexcept, 1, + fold_convert (integer_type_node, + new_fenv_var)); + *update = build2 (COMPOUND_EXPR, void_type_node, + build2 (COMPOUND_EXPR, void_type_node, + reload_fenv, restore_fnenv), update_call); +} + #include "gt-pa.h" diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index 52ad0c3..b0f29a4 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -96,6 +96,8 @@ UNSPECV_OPC ; outline_prologue_call UNSPECV_OEC ; outline_epilogue_call UNSPECV_LONGJMP ; builtin_longjmp + UNSPECV_GET_FPSR ; get floating-point status register + UNSPECV_SET_FPSR ; set floating-point status register ]) ;; Maximum pc-relative branch offsets. @@ -10723,13 +10725,13 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" (define_insn "atomic_storedi_1" [(set (mem:DI (match_operand:SI 0 "register_operand" "r,r")) (match_operand:DI 1 "reg_or_0_operand" "M,r")) - (clobber (match_scratch:DI 2 "=X,f"))] + (clobber (match_scratch:DI 2 "=f,f"))] "!TARGET_64BIT && !TARGET_SOFT_FLOAT" "@ - {fstds|fstd} %%fr0,0(%0) + fcpy,dbl %%fr0,%2\n\t{fstds|fstd} %2,0(%0) {stws|stw} %1,-16(%%sp)\n\t{stws|stw} %R1,-12(%%sp)\n\t{fldds|fldd} -16(%%sp),%2\n\t{fstds|fstd} %2,0(%0)" [(set_attr "type" "move,move") - (set_attr "length" "4,16")]) + (set_attr "length" "8,16")]) ;; PA 2.0 hardware supports out-of-order execution of loads and stores, so ;; we need memory barriers to enforce program order for memory references @@ -10784,3 +10786,85 @@ add,l %2,%3,%3\;bv,n %%r0(%3)" "ldo 15(%%sp),%1\n\t{dep|depw} %%r0,31,3,%1\n\t{ldcw|ldcw,co} 0(%1),%1" [(set_attr "type" "binary") (set_attr "length" "12")]) + +;; Get floating-point status register. + +(define_expand "get_fpsr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR))] + "" +{ + if (TARGET_SOFT_FLOAT) + FAIL; + + if (TARGET_64BIT) + emit_insn (gen_get_fpsr_64 (operands[0])); + else + emit_insn (gen_get_fpsr_32 (operands[0])); + DONE; +}) + +;; The floating-point status register is stored to an unused slot in +;; the frame marker and then loaded to register operand 0. The final +;; floating-point load restores the T bit in the status register. + +;; The final load might be avoided if a word mode store was used to +;; store the status register. It is unclear why we need a double-word +;; store. I suspect PA 1.0 didn't support single-word stores of the +;; status register. + +(define_insn "get_fpsr_32" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR))] + "!TARGET_SOFT_FLOAT && !TARGET_64BIT" + "{fstds|fstd} %%fr0,-16(%%sp)\n\tldw -16(%%sp),%0\n\t{fldds|fldd} -16(%%sp),%%fr0" + [(set_attr "type" "fpstore_load") + (set_attr "length" "12")]) + +;; The 64-bit pattern is similar to the 32-bit pattern except we need +;; compute the address of the frame location as long displacements aren't +;; supported on Linux targets. + +(define_insn "get_fpsr_64" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPECV_GET_FPSR)) + (clobber (match_scratch:DI 1 "=&r"))] + "!TARGET_SOFT_FLOAT && TARGET_64BIT" + "ldo -40(%%sp),%1\n\tfstd %%fr0,0(%1)\n\tldw 0(%1),%0\n\tfldd 0(%1),%%fr0" + [(set_attr "type" "fpstore_load") + (set_attr "length" "16")]) + +;; Set floating-point status register. + +(define_expand "set_fpsr" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR)] + "" +{ + if (TARGET_SOFT_FLOAT) + FAIL; + + if (TARGET_64BIT) + emit_insn (gen_set_fpsr_64 (operands[0])); + else + emit_insn (gen_set_fpsr_32 (operands[0])); + DONE; +}) + +;; The old T bit is extracted and stored in the new status register. + +(define_insn "set_fpsr_32" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR) + (clobber (match_scratch:SI 1 "=&r"))] + "!TARGET_SOFT_FLOAT && !TARGET_64BIT" + "{fstds|fstd} %%fr0,-16(%%sp)\n\tldw -16(%%sp),%1\n\t{extru|extrw,u} %1,25,1,%1\n\t{dep|depw} %1,25,1,%0\n\tstw %0,-16(%%sp)\n\t{fldds|fldd} -16(%%sp),%%fr0" + [(set_attr "type" "store_fpload") + (set_attr "length" "24")]) + +(define_insn "set_fpsr_64" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] UNSPECV_SET_FPSR) + (clobber (match_scratch:DI 1 "=&r")) + (clobber (match_scratch:SI 2 "=&r"))] + "!TARGET_SOFT_FLOAT && TARGET_64BIT" + "ldo -40(%%sp),%1\n\tfstd %%fr0,0(%1)\n\tldw 0(%1),%2\n\textrw,u %2,25,1,%2\n\tdepw %2,25,1,%0\n\tstw %0,0(%1)\n\tfldd 0(%1),%%fr0" + [(set_attr "type" "store_fpload") + (set_attr "length" "28")]) diff --git a/gcc/config/riscv/generic-ooo.md b/gcc/config/riscv/generic-ooo.md index 421a7bb9..a22f8a3 100644 --- a/gcc/config/riscv/generic-ooo.md +++ b/gcc/config/riscv/generic-ooo.md @@ -127,7 +127,7 @@ (define_insn_reservation "generic_ooo_fcvt" 3 (and (eq_attr "tune" "generic_ooo") - (eq_attr "type" "fcvt")) + (eq_attr "type" "fcvt,fcvt_i2f,fcvt_f2i")) "generic_ooo_issue,generic_ooo_fxu") (define_insn_reservation "generic_ooo_fcmp" 2 diff --git a/gcc/config/riscv/generic.md b/gcc/config/riscv/generic.md index b99ae34..3f0eaa2 100644 --- a/gcc/config/riscv/generic.md +++ b/gcc/config/riscv/generic.md @@ -42,7 +42,7 @@ (define_insn_reservation "generic_xfer" 3 (and (eq_attr "tune" "generic") - (eq_attr "type" "mfc,mtc,fcvt,fmove,fcmp")) + (eq_attr "type" "mfc,mtc,fcvt,fcvt_i2f,fcvt_f2i,fmove,fcmp")) "alu") (define_insn_reservation "generic_branch" 1 diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 2e30605..94c3871 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -250,7 +250,8 @@ riscv_resolve_overloaded_builtin (unsigned int uncast_location, tree fndecl, case RISCV_BUILTIN_GENERAL: break; case RISCV_BUILTIN_VECTOR: - new_fndecl = riscv_vector::resolve_overloaded_builtin (subcode, arglist); + new_fndecl = riscv_vector::resolve_overloaded_builtin (loc, subcode, + fndecl, arglist); break; default: gcc_unreachable (); diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def index b30f4df..57928bc 100644 --- a/gcc/config/riscv/riscv-cores.def +++ b/gcc/config/riscv/riscv-cores.def @@ -37,6 +37,8 @@ RISCV_TUNE("rocket", generic, rocket_tune_info) RISCV_TUNE("sifive-3-series", generic, rocket_tune_info) RISCV_TUNE("sifive-5-series", generic, rocket_tune_info) RISCV_TUNE("sifive-7-series", sifive_7, sifive_7_tune_info) +RISCV_TUNE("sifive-p400-series", sifive_p400, sifive_p400_tune_info) +RISCV_TUNE("sifive-p600-series", sifive_p600, sifive_p600_tune_info) RISCV_TUNE("thead-c906", generic, thead_c906_tune_info) RISCV_TUNE("generic-ooo", generic_ooo, generic_ooo_tune_info) RISCV_TUNE("size", generic, optimize_size_tune_info) @@ -74,6 +76,15 @@ RISCV_CORE("sifive-s76", "rv64imafdc", "sifive-7-series") RISCV_CORE("sifive-u54", "rv64imafdc", "sifive-5-series") RISCV_CORE("sifive-u74", "rv64imafdc", "sifive-7-series") RISCV_CORE("sifive-x280", "rv64imafdcv_zfh_zba_zbb_zvfh_zvl512b", "sifive-7-series") +RISCV_CORE("sifive-p450", "rv64imafdc_za64rs_zic64b_zicbom_zicbop_zicboz_" + "ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_" + "zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs", + "sifive-p400-series") +RISCV_CORE("sifive-p670", "rv64imafdcv_za64rs_zic64b_zicbom_zicbop_zicboz_" + "ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_" + "zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs_" + "zvl128b_zvbb_zvknc_zvkng_zvksc_zvksg", + "sifive-p600-series") RISCV_CORE("thead-c906", "rv64imafdc_xtheadba_xtheadbb_xtheadbs_xtheadcmo_" "xtheadcondmov_xtheadfmemidx_xtheadmac_" diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 1500f88..4edddba 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -55,6 +55,8 @@ extern enum riscv_isa_spec_class riscv_isa_spec; enum riscv_microarchitecture_type { generic, sifive_7, + sifive_p400, + sifive_p600, generic_ooo }; extern enum riscv_microarchitecture_type riscv_microarchitecture; diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index b3f0bdb..ae16858 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -560,7 +560,7 @@ gimple *gimple_fold_builtin (unsigned int, gimple_stmt_iterator *, gcall *); rtx expand_builtin (unsigned int, tree, rtx); bool check_builtin_call (location_t, vec<location_t>, unsigned int, tree, unsigned int, tree *); -tree resolve_overloaded_builtin (unsigned int, vec<tree, va_gc> *); +tree resolve_overloaded_builtin (location_t, unsigned int, tree, vec<tree, va_gc> *); bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT); bool legitimize_move (rtx, rtx *); void emit_vlmax_vsetvl (machine_mode, rtx); diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 4bacb7f..0cfbd21 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -4151,13 +4151,15 @@ expand_reduction (unsigned unspec, unsigned insn_flags, rtx *ops, rtx init) rtx m1_tmp = gen_reg_rtx (m1_mode); rtx scalar_move_ops[] = {m1_tmp, init}; - emit_nonvlmax_insn (code_for_pred_broadcast (m1_mode), SCALAR_MOVE_OP, - scalar_move_ops, - need_mask_operand_p (insn_flags) ? ops[3] - : CONST1_RTX (Pmode)); + insn_code icode = code_for_pred_broadcast (m1_mode); + if (need_mask_operand_p (insn_flags)) + emit_nonvlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops, ops[3]); + else + emit_vlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops); + rtx m1_tmp2 = gen_reg_rtx (m1_mode); rtx reduc_ops[] = {m1_tmp2, vector_src, m1_tmp}; - insn_code icode = code_for_pred (unspec, vmode); + icode = code_for_pred (unspec, vmode); if (need_mask_operand_p (insn_flags)) { diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc index 403e102..efcdc8f 100644 --- a/gcc/config/riscv/riscv-vector-builtins.cc +++ b/gcc/config/riscv/riscv-vector-builtins.cc @@ -4606,7 +4606,8 @@ check_builtin_call (location_t location, vec<location_t>, unsigned int code, } tree -resolve_overloaded_builtin (unsigned int code, vec<tree, va_gc> *arglist) +resolve_overloaded_builtin (location_t loc, unsigned int code, tree fndecl, + vec<tree, va_gc> *arglist) { if (code >= vec_safe_length (registered_functions)) return NULL_TREE; @@ -4616,12 +4617,26 @@ resolve_overloaded_builtin (unsigned int code, vec<tree, va_gc> *arglist) if (!rfun || !rfun->overloaded_p) return NULL_TREE; + /* According to the rvv intrinisc doc, we have no such overloaded function + with empty args. Unfortunately, we register the empty args function as + overloaded for avoiding conflict. Thus, there will actual one register + function after return NULL_TREE back to the middle-end, and finally result + in ICE when expanding. For example: + + 1. First we registered void __riscv_vfredmax () as the overloaded function. + 2. Then resolve_overloaded_builtin (this func) return NULL_TREE. + 3. The functions register in step 1 bypass the args check as empty args. + 4. Finally, fall into expand_builtin with empty args and meet ICE. + + Here we report error when overloaded function with empty args. */ + if (rfun->overloaded_p && arglist->length () == 0) + error_at (loc, "no matching function call to %qE with empty args", fndecl); + hashval_t hash = rfun->overloaded_hash (*arglist); registered_function *rfn = non_overloaded_function_table->find_with_hash (rfun, hash); - if (rfn) - return rfn->decl; - return NULL_TREE; + + return rfn ? rfn->decl : NULL_TREE; } function_instance diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc index d7b40a5..32f262d 100644 --- a/gcc/config/riscv/riscv-vsetvl.cc +++ b/gcc/config/riscv/riscv-vsetvl.cc @@ -315,6 +315,48 @@ vsetvl_insn_p (rtx_insn *rinsn) || INSN_CODE (rinsn) == CODE_FOR_vsetvlsi); } +/* Return true if it is the bogus vsetvl_pre instruction: + + (define_insn "@vlmax_avl<mode>" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec:P [(match_operand:P 1 "const_int_operand" "i")] UNSPEC_VLMAX))] + "TARGET_VECTOR" + "" + [(set_attr "type" "vsetvl_pre")]) + + As described above, it's the bogus instruction which doesn't any assembler + and should be removed eventually. It's used for occupying a scalar register + for VLMAX avl RVV instruction before register allocation. + + Before RA: + + ... + vsetvl_pre (set r136) + vadd.vv (use r136 with VLMAX avl) + ... + + After RA: + + ... + vsetvl_pre (set a5) + vadd.vv (use r136 with VLMAX avl) + ... + + VSETVL PASS: + + ... + vsetvl_pre (set a5) ---> removed. + vsetvl a5,zero,... ---> Inserted. + vadd.vv + ... +*/ +static bool +vsetvl_pre_insn_p (rtx_insn *rinsn) +{ + return recog_memoized (rinsn) >= 0 + && get_attr_type (rinsn) == TYPE_VSETVL_PRE; +} + /* Return true if it is vsetvl zero, rs1. */ static bool vsetvl_discard_result_insn_p (rtx_insn *rinsn) @@ -599,14 +641,6 @@ extract_single_source (set_info *set) return first_insn; } -static insn_info * -extract_single_source (def_info *def) -{ - if (!def) - return nullptr; - return extract_single_source (dyn_cast<set_info *> (def)); -} - static bool same_equiv_note_p (set_info *set1, set_info *set2) { @@ -2247,9 +2281,8 @@ private: } } - void remove_vsetvl_insn (const vsetvl_info &info) + void remove_vsetvl_insn (rtx_insn *rinsn) { - rtx_insn *rinsn = info.get_insn ()->rtl (); if (dump_file) { fprintf (dump_file, " Eliminate insn %d:\n", INSN_UID (rinsn)); @@ -2374,6 +2407,7 @@ public: } void compute_vsetvl_def_data (); + void compute_transparent (const bb_info *); void compute_lcm_local_properties (); void fuse_local_vsetvl_info (); @@ -2383,6 +2417,7 @@ public: void cleaup (); void remove_avl_operand (); void remove_unused_dest_operand (); + void remove_vsetvl_pre_insns (); void dump (FILE *file, const char *title) const { @@ -2452,20 +2487,16 @@ pre_vsetvl::compute_vsetvl_def_data () { for (unsigned i = 0; i < m_vsetvl_def_exprs.length (); i += 1) { - const vsetvl_info &info = *m_vsetvl_def_exprs[i]; - if (!info.has_nonvlmax_reg_avl ()) - continue; - unsigned int regno; - sbitmap_iterator sbi; - EXECUTE_IF_SET_IN_BITMAP (m_reg_def_loc[bb->index ()], 0, regno, - sbi) - if (regno == REGNO (info.get_avl ())) - { - bitmap_set_bit (m_kill[bb->index ()], i); - bitmap_set_bit (def_loc[bb->index ()], - get_expr_index (m_vsetvl_def_exprs, - m_unknow_info)); - } + auto *info = m_vsetvl_def_exprs[i]; + if (info->has_nonvlmax_reg_avl () + && bitmap_bit_p (m_reg_def_loc[bb->index ()], + REGNO (info->get_avl ()))) + { + bitmap_set_bit (m_kill[bb->index ()], i); + bitmap_set_bit (def_loc[bb->index ()], + get_expr_index (m_vsetvl_def_exprs, + m_unknow_info)); + } } continue; } @@ -2516,6 +2547,36 @@ pre_vsetvl::compute_vsetvl_def_data () sbitmap_vector_free (m_kill); } +/* Subroutine of compute_lcm_local_properties which Compute local transparent + BB. Note that the compile time is very sensitive to compute_transparent and + compute_lcm_local_properties, any change of these 2 functions should be + aware of the compile time changing of the program which has a large number of + blocks, e.g SPEC 2017 wrf. + + Current compile time profile of SPEC 2017 wrf: + + 1. scheduling - 27% + 2. machine dep reorg (VSETVL PASS) - 18% + + VSETVL pass should not spend more time than scheduling in compilation. */ +void +pre_vsetvl::compute_transparent (const bb_info *bb) +{ + int num_exprs = m_exprs.length (); + unsigned bb_index = bb->index (); + for (int i = 0; i < num_exprs; i++) + { + auto *info = m_exprs[i]; + if (info->has_nonvlmax_reg_avl () + && bitmap_bit_p (m_reg_def_loc[bb_index], REGNO (info->get_avl ()))) + bitmap_clear_bit (m_transp[bb_index], i); + else if (info->has_vl () + && bitmap_bit_p (m_reg_def_loc[bb_index], + REGNO (info->get_vl ()))) + bitmap_clear_bit (m_transp[bb_index], i); + } +} + /* Compute the local properties of each recorded expression. Local properties are those that are defined by the block, irrespective of @@ -2572,7 +2633,7 @@ pre_vsetvl::compute_lcm_local_properties () bitmap_vector_clear (m_avloc, last_basic_block_for_fn (cfun)); bitmap_vector_clear (m_antloc, last_basic_block_for_fn (cfun)); - bitmap_vector_clear (m_transp, last_basic_block_for_fn (cfun)); + bitmap_vector_ones (m_transp, last_basic_block_for_fn (cfun)); /* - If T is locally available at the end of a block, then T' must be available at the end of the same block. Since some optimization has @@ -2598,117 +2659,34 @@ pre_vsetvl::compute_lcm_local_properties () /* Compute m_transp */ if (block_info.empty_p ()) + compute_transparent (bb); + else { - bitmap_ones (m_transp[bb_index]); - for (int i = 0; i < num_exprs; i += 1) - { - const vsetvl_info &info = *m_exprs[i]; - if (!info.has_nonvlmax_reg_avl () && !info.has_vl ()) - continue; - - if (info.has_nonvlmax_reg_avl ()) - { - unsigned int regno; - sbitmap_iterator sbi; - EXECUTE_IF_SET_IN_BITMAP (m_reg_def_loc[bb->index ()], 0, - regno, sbi) - { - if (regno == REGNO (info.get_avl ())) - bitmap_clear_bit (m_transp[bb->index ()], i); - } - } - - for (insn_info *insn : bb->real_nondebug_insns ()) - { - if (info.has_nonvlmax_reg_avl () - && find_access (insn->defs (), REGNO (info.get_avl ()))) - { - bitmap_clear_bit (m_transp[bb_index], i); - break; - } - - if (info.has_vl () - && reg_mentioned_p (info.get_vl (), insn->rtl ())) - { - if (find_access (insn->defs (), REGNO (info.get_vl ()))) - /* We can't fuse vsetvl into the blocks that modify the - VL operand since successors of such blocks will need - the value of those blocks are defining. - - bb 4: def a5 - / \ - bb 5:use a5 bb 6:vsetvl a5, 5 - - The example above shows that we can't fuse vsetvl - from bb 6 into bb 4 since the successor bb 5 is using - the value defined in bb 4. */ - ; - else - { - /* We can't fuse vsetvl into the blocks that use the - VL operand which has different value from the - vsetvl info. - - bb 4: def a5 - | - bb 5: use a5 - | - bb 6: def a5 - | - bb 7: use a5 - - The example above shows that we can't fuse vsetvl - from bb 6 into bb 5 since their value is different. - */ - resource_info resource - = full_register (REGNO (info.get_vl ())); - def_lookup dl = crtl->ssa->find_def (resource, insn); - def_info *def - = dl.matching_set_or_last_def_of_prev_group (); - insn_info *def_insn = extract_single_source (def); - if (def_insn && vsetvl_insn_p (def_insn->rtl ())) - { - vsetvl_info def_info = vsetvl_info (def_insn); - if (m_dem.compatible_p (def_info, info)) - continue; - } - } + bitmap_clear (m_transp[bb_index]); + vsetvl_info &header_info = block_info.get_entry_info (); + vsetvl_info &footer_info = block_info.get_exit_info (); - bitmap_clear_bit (m_transp[bb_index], i); - break; - } - } - } + if (header_info.valid_p () && anticipated_exp_p (header_info)) + bitmap_set_bit (m_antloc[bb_index], + get_expr_index (m_exprs, header_info)); - continue; + if (footer_info.valid_p ()) + for (int i = 0; i < num_exprs; i += 1) + { + const vsetvl_info &info = *m_exprs[i]; + if (!info.valid_p ()) + continue; + if (available_exp_p (footer_info, info)) + bitmap_set_bit (m_avloc[bb_index], i); + } } - vsetvl_info &header_info = block_info.get_entry_info (); - vsetvl_info &footer_info = block_info.get_exit_info (); - - if (header_info.valid_p () && anticipated_exp_p (header_info)) - bitmap_set_bit (m_antloc[bb_index], - get_expr_index (m_exprs, header_info)); - - if (footer_info.valid_p ()) - for (int i = 0; i < num_exprs; i += 1) - { - const vsetvl_info &info = *m_exprs[i]; - if (!info.valid_p ()) - continue; - if (available_exp_p (footer_info, info)) - bitmap_set_bit (m_avloc[bb_index], i); - } - } - - for (const bb_info *bb : crtl->ssa->bbs ()) - { - unsigned bb_index = bb->index (); if (invalid_opt_bb_p (bb->cfg_bb ())) { bitmap_clear (m_antloc[bb_index]); bitmap_clear (m_transp[bb_index]); } + /* Compute ae_kill for each basic block using: ~(TRANSP | COMP) @@ -3252,7 +3230,7 @@ pre_vsetvl::emit_vsetvl () if (curr_info.delete_p ()) { if (vsetvl_insn_p (insn->rtl ())) - remove_vsetvl_insn (curr_info); + remove_vsetvl_insn (curr_info.get_insn ()->rtl ()); continue; } else if (curr_info.valid_p ()) @@ -3290,7 +3268,7 @@ pre_vsetvl::emit_vsetvl () for (const vsetvl_info &item : m_delete_list) { gcc_assert (vsetvl_insn_p (item.get_insn ()->rtl ())); - remove_vsetvl_insn (item); + remove_vsetvl_insn (item.get_insn ()->rtl ()); } /* Insert vsetvl info that was not deleted after lift up. */ @@ -3371,6 +3349,7 @@ pre_vsetvl::cleaup () { remove_avl_operand (); remove_unused_dest_operand (); + remove_vsetvl_pre_insns (); } void @@ -3438,6 +3417,26 @@ pre_vsetvl::remove_unused_dest_operand () } } +/* Remove all bogus vsetvl_pre instructions. */ +void +pre_vsetvl::remove_vsetvl_pre_insns () +{ + basic_block cfg_bb; + rtx_insn *rinsn; + FOR_ALL_BB_FN (cfg_bb, cfun) + FOR_BB_INSNS (cfg_bb, rinsn) + if (NONDEBUG_INSN_P (rinsn) && vsetvl_pre_insn_p (rinsn)) + { + if (dump_file) + { + fprintf (dump_file, " Eliminate vsetvl_pre insn %d:\n", + INSN_UID (rinsn)); + print_rtl_single (dump_file, rinsn); + } + remove_vsetvl_insn (rinsn); + } +} + const pass_data pass_data_vsetvl = { RTL_PASS, /* type */ "vsetvl", /* name */ diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 7b6111a..799d791 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -447,6 +447,40 @@ static const struct riscv_tune_param sifive_7_tune_info = { NULL, /* vector cost */ }; +/* Costs to use when optimizing for Sifive p400 Series. */ +static const struct riscv_tune_param sifive_p400_tune_info = { + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_add */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_mul */ + {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ + {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ + 3, /* issue_rate */ + 4, /* branch_cost */ + 3, /* memory_cost */ + 4, /* fmv_cost */ + true, /* slow_unaligned_access */ + false, /* use_divmod_expansion */ + RISCV_FUSE_LUI_ADDI | RISCV_FUSE_AUIPC_ADDI, /* fusible_ops */ + &generic_vector_cost, /* vector cost */ +}; + +/* Costs to use when optimizing for Sifive p600 Series. */ +static const struct riscv_tune_param sifive_p600_tune_info = { + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_add */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* fp_mul */ + {COSTS_N_INSNS (20), COSTS_N_INSNS (20)}, /* fp_div */ + {COSTS_N_INSNS (4), COSTS_N_INSNS (4)}, /* int_mul */ + {COSTS_N_INSNS (6), COSTS_N_INSNS (6)}, /* int_div */ + 4, /* issue_rate */ + 4, /* branch_cost */ + 3, /* memory_cost */ + 4, /* fmv_cost */ + true, /* slow_unaligned_access */ + false, /* use_divmod_expansion */ + RISCV_FUSE_LUI_ADDI | RISCV_FUSE_AUIPC_ADDI, /* fusible_ops */ + &generic_vector_cost, /* vector cost */ +}; + /* Costs to use when optimizing for T-HEAD c906. */ static const struct riscv_tune_param thead_c906_tune_info = { {COSTS_N_INSNS (4), COSTS_N_INSNS (5)}, /* fp_add */ @@ -1382,6 +1416,41 @@ riscv_v_ext_mode_p (machine_mode mode) || riscv_v_ext_vls_mode_p (mode); } +static unsigned +riscv_v_vls_mode_aggregate_gpr_count (unsigned vls_unit_size, + unsigned scalar_unit_size) +{ + gcc_assert (vls_unit_size != 0 && scalar_unit_size != 0); + + if (vls_unit_size < scalar_unit_size) + return 1; + + /* Ensure the vls mode is exact_div by scalar_unit_size. */ + gcc_assert ((vls_unit_size % scalar_unit_size) == 0); + + return vls_unit_size / scalar_unit_size; +} + +static machine_mode +riscv_v_vls_to_gpr_mode (unsigned vls_mode_size) +{ + switch (vls_mode_size) + { + case 16: + return TImode; + case 8: + return DImode; + case 4: + return SImode; + case 2: + return HImode; + case 1: + return QImode; + default: + gcc_unreachable (); + } +} + /* Call from ADJUST_NUNITS in riscv-modes.def. Return the correct NUNITS size for corresponding machine_mode. */ @@ -3003,7 +3072,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN case SET: /* If we are called for an INSN that's a simple set of a register, then cost based on the SET_SRC alone. */ - if (outer_code == INSN && REG_P (SET_DEST (x))) + if (outer_code == INSN + && register_operand (SET_DEST (x), GET_MODE (SET_DEST (x)))) { riscv_rtx_costs (SET_SRC (x), mode, outer_code, opno, total, speed); return true; @@ -3120,7 +3190,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN rtx and_rhs = XEXP (x, 1); rtx ashift_lhs = XEXP (XEXP (x, 0), 0); rtx ashift_rhs = XEXP (XEXP (x, 0), 1); - if (REG_P (ashift_lhs) + if (register_operand (ashift_lhs, GET_MODE (ashift_lhs)) && CONST_INT_P (ashift_rhs) && CONST_INT_P (and_rhs) && ((INTVAL (and_rhs) >> INTVAL (ashift_rhs)) == 0xffffffff)) @@ -3136,7 +3206,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN } /* bclr pattern for zbs. */ if (TARGET_ZBS - && REG_P (XEXP (x, 1)) + && register_operand (XEXP (x, 1), GET_MODE (XEXP (x, 1))) && GET_CODE (XEXP (x, 0)) == ROTATE && CONST_INT_P (XEXP ((XEXP (x, 0)), 0)) && INTVAL (XEXP ((XEXP (x, 0)), 0)) == -2) @@ -3292,7 +3362,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (TARGET_ZBA && (TARGET_64BIT && (mode == DImode)) && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND - && REG_P (XEXP (XEXP (x, 0), 0)) + && register_operand (XEXP (XEXP (x, 0), 0), + GET_MODE (XEXP (XEXP (x, 0), 0))) && GET_MODE (XEXP (XEXP (x, 0), 0)) == SImode) { *total = COSTS_N_INSNS (1); @@ -3303,7 +3374,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN && ((!TARGET_64BIT && (mode == SImode)) || (TARGET_64BIT && (mode == DImode))) && (GET_CODE (XEXP (x, 0)) == ASHIFT) - && REG_P (XEXP (XEXP (x, 0), 0)) + && register_operand (XEXP (XEXP (x, 0), 0), + GET_MODE (XEXP (XEXP (x, 0), 0))) && CONST_INT_P (XEXP (XEXP (x, 0), 1)) && IN_RANGE (INTVAL (XEXP (XEXP (x, 0), 1)), 1, 3)) { @@ -3316,7 +3388,8 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (TARGET_ZBA && mode == word_mode && GET_CODE (XEXP (x, 0)) == MULT - && REG_P (XEXP (XEXP (x, 0), 0)) + && register_operand (XEXP (XEXP (x, 0), 0), + GET_MODE (XEXP (XEXP (x, 0), 0))) && CONST_INT_P (XEXP (XEXP (x, 0), 1)) && pow2p_hwi (INTVAL (XEXP (XEXP (x, 0), 1))) && IN_RANGE (exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1))), 1, 3)) @@ -3338,7 +3411,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN if (TARGET_ZBA && (TARGET_64BIT && (mode == DImode)) && (GET_CODE (XEXP (x, 0)) == AND) - && (REG_P (XEXP (x, 1)))) + && register_operand (XEXP (x, 1), GET_MODE (XEXP (x, 1)))) { do { rtx and_lhs = XEXP (XEXP (x, 0), 0); @@ -4868,6 +4941,41 @@ riscv_pass_fpr_pair (machine_mode mode, unsigned regno1, GEN_INT (offset2)))); } +static rtx +riscv_pass_vls_aggregate_in_gpr (struct riscv_arg_info *info, machine_mode mode, + unsigned gpr_base) +{ + gcc_assert (riscv_v_ext_vls_mode_p (mode)); + + unsigned count = 0; + unsigned regnum = 0; + machine_mode gpr_mode = VOIDmode; + unsigned vls_size = GET_MODE_SIZE (mode).to_constant (); + unsigned gpr_size = GET_MODE_SIZE (Xmode); + + if (IN_RANGE (vls_size, 0, gpr_size * 2)) + { + count = riscv_v_vls_mode_aggregate_gpr_count (vls_size, gpr_size); + + if (count + info->gpr_offset <= MAX_ARGS_IN_REGISTERS) + { + regnum = gpr_base + info->gpr_offset; + info->num_gprs = count; + gpr_mode = riscv_v_vls_to_gpr_mode (vls_size); + } + } + + if (!regnum) + return NULL_RTX; /* Return NULL_RTX if we cannot find a suitable reg. */ + + gcc_assert (gpr_mode != VOIDmode); + + rtx reg = gen_rtx_REG (gpr_mode, regnum); + rtx x = gen_rtx_EXPR_LIST (VOIDmode, reg, CONST0_RTX (gpr_mode)); + + return gen_rtx_PARALLEL (mode, gen_rtvec (1, x)); +} + /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ @@ -4997,8 +5105,7 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, info->gpr_offset = cum->num_gprs; info->fpr_offset = cum->num_fprs; - /* When disable vector_abi or scalable vector argument is anonymous, this - argument is passed by reference. */ + /* Passed by reference when the scalable vector argument is anonymous. */ if (riscv_v_ext_mode_p (mode) && !named) return NULL_RTX; @@ -5067,6 +5174,10 @@ riscv_get_arg_info (struct riscv_arg_info *info, const CUMULATIVE_ARGS *cum, /* For scalable vector argument. */ if (riscv_vector_type_p (type) && riscv_v_ext_mode_p (mode)) return riscv_get_vector_arg (info, cum, mode, return_p); + + /* For vls mode aggregated in gpr. */ + if (riscv_v_ext_vls_mode_p (mode)) + return riscv_pass_vls_aggregate_in_gpr (info, mode, gpr_base); } /* Work out the size of the argument. */ @@ -5191,19 +5302,24 @@ riscv_pass_by_reference (cumulative_args_t cum_v, const function_arg_info &arg) so we can avoid the call to riscv_get_arg_info in this case. */ if (cum != NULL) { - /* Don't pass by reference if we can use a floating-point register. */ riscv_get_arg_info (&info, cum, arg.mode, arg.type, arg.named, false); + + /* Don't pass by reference if we can use a floating-point register. */ if (info.num_fprs) return false; + /* Don't pass by reference if we can use general register(s) for vls. */ + if (info.num_gprs && riscv_v_ext_vls_mode_p (arg.mode)) + return false; + /* Don't pass by reference if we can use vector register groups. */ if (info.num_vrs > 0 || info.num_mrs > 0) return false; } - /* When vector abi disabled(without --param=riscv-vector-abi option) or - scalable vector argument is anonymous or cannot be passed through vector - registers, this argument is passed by reference. */ + /* Passed by reference when: + 1. The scalable vector argument is anonymous. + 2. Args cannot be passed through vector registers. */ if (riscv_v_ext_mode_p (arg.mode)) return true; @@ -5314,12 +5430,9 @@ riscv_arguments_is_vector_type_p (const_tree fntype) static const predefined_function_abi & riscv_fntype_abi (const_tree fntype) { - /* Implementing an experimental vector calling convention, the proposal - can be viewed at the bellow link: - https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 - - You can enable this feature via the `--param=riscv-vector-abi` compiler - option. */ + /* Implement the vector calling convention. For more details please + reference the below link. + https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/389 */ if (riscv_return_value_is_vector_type_p (fntype) || riscv_arguments_is_vector_type_p (fntype)) return riscv_v_abi (); diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 627eba1..669308c 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -896,7 +896,10 @@ extern enum riscv_cc get_riscv_cc (const rtx use); SLT[I][U], AND[I], XOR[I], OR[I], LUI, AUIPC, and their compressed counterparts, including C.MV and C.LI) can be in the branch shadow. */ -#define TARGET_SFB_ALU (riscv_microarchitecture == sifive_7) +#define TARGET_SFB_ALU \ + ((riscv_microarchitecture == sifive_7) \ + || (riscv_microarchitecture == sifive_p400) \ + || (riscv_microarchitecture == sifive_p600)) #define LOGICAL_OP_NON_SHORT_CIRCUIT 0 diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index b320ad0..39b2979 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -314,6 +314,8 @@ ;; fdiv floating point divide ;; fcmp floating point compare ;; fcvt floating point convert +;; fcvt_i2f integer to floating point convert +;; fcvt_f2i floating point to integer convert ;; fsqrt floating point square root ;; multi multiword sequence (or user asm statements) ;; auipc integer addition to PC @@ -466,8 +468,8 @@ (define_attr "type" "unknown,branch,jump,jalr,ret,call,load,fpload,store,fpstore, mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul, - fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,trap,ghost,bitmanip, - rotate,clmul,min,max,minu,maxu,clz,ctz,cpop, + fmadd,fdiv,fcmp,fcvt,fcvt_i2f,fcvt_f2i,fsqrt,multi,auipc,sfb_alu,nop,trap, + ghost,bitmanip,rotate,clmul,min,max,minu,maxu,clz,ctz,cpop, atomic,condmove,cbo,crypto,pushpop,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm, rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts, vldux,vldox,vstux,vstox,vldff,vldr,vstr, @@ -685,7 +687,7 @@ ;; Microarchitectures we know how to tune for. ;; Keep this in sync with enum riscv_microarchitecture. (define_attr "tune" - "generic,sifive_7,generic_ooo" + "generic,sifive_7,sifive_p400,sifive_p600,generic_ooo" (const (symbol_ref "((enum attr_tune) riscv_microarchitecture)"))) ;; Describe a user's asm statement. @@ -1973,7 +1975,7 @@ (match_operand:ANYF 1 "register_operand" " f")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<GPR:ifmt>.<ANYF:fmt> %0,%1,rtz" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_f2i") (set_attr "mode" "<ANYF:MODE>")]) (define_insn "fixuns_trunc<ANYF:mode><GPR:mode>2" @@ -1982,7 +1984,7 @@ (match_operand:ANYF 1 "register_operand" " f")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<GPR:ifmt>u.<ANYF:fmt> %0,%1,rtz" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_f2i") (set_attr "mode" "<ANYF:MODE>")]) (define_insn "float<GPR:mode><ANYF:mode>2" @@ -1991,7 +1993,7 @@ (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<ANYF:fmt>.<GPR:ifmt>\t%0,%z1" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_i2f") (set_attr "mode" "<ANYF:MODE>")]) (define_insn "floatuns<GPR:mode><ANYF:mode>2" @@ -2000,7 +2002,7 @@ (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<ANYF:fmt>.<GPR:ifmt>u\t%0,%z1" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_i2f") (set_attr "mode" "<ANYF:MODE>")]) (define_insn "l<rint_pattern><ANYF:mode><GPR:mode>2" @@ -2010,7 +2012,7 @@ RINT))] "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<GPR:ifmt>.<ANYF:fmt> %0,%1,<rint_rm>" - [(set_attr "type" "fcvt") + [(set_attr "type" "fcvt_f2i") (set_attr "mode" "<ANYF:MODE>")]) (define_insn "<round_pattern><ANYF:mode>2" @@ -3848,6 +3850,8 @@ (include "pic.md") (include "generic.md") (include "sifive-7.md") +(include "sifive-p400.md") +(include "sifive-p600.md") (include "thead.md") (include "generic-ooo.md") (include "vector.md") diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index b6d8e9a..f6ff70b 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -225,11 +225,25 @@ Mask(ZIHINTPAUSE) Var(riscv_zi_subext) Mask(ZICOND) Var(riscv_zi_subext) +Mask(ZIC64B) Var(riscv_zi_subext) + +Mask(ZICCAMOA) Var(riscv_zi_subext) + +Mask(ZICCIF) Var(riscv_zi_subext) + +Mask(ZICCLSM) Var(riscv_zi_subext) + +Mask(ZICCRSE) Var(riscv_zi_subext) + TargetVariable int riscv_za_subext Mask(ZAWRS) Var(riscv_za_subext) +Mask(ZA64RS) Var(riscv_za_subext) + +Mask(ZA128RS) Var(riscv_za_subext) + TargetVariable int riscv_zb_subext diff --git a/gcc/config/riscv/sifive-7.md b/gcc/config/riscv/sifive-7.md index a63394c..48bdba4 100644 --- a/gcc/config/riscv/sifive-7.md +++ b/gcc/config/riscv/sifive-7.md @@ -81,7 +81,7 @@ (define_insn_reservation "sifive_7_fp_other" 3 (and (eq_attr "tune" "sifive_7") - (eq_attr "type" "fcvt,fcmp,fmove")) + (eq_attr "type" "fcvt,fcvt_i2f,fcvt_f2i,fcmp,fmove")) "sifive_7_B") (define_insn_reservation "sifive_7_fdiv_s" 27 diff --git a/gcc/config/riscv/sifive-p400.md b/gcc/config/riscv/sifive-p400.md new file mode 100644 index 0000000..cc244d3 --- /dev/null +++ b/gcc/config/riscv/sifive-p400.md @@ -0,0 +1,174 @@ +;; Scheduling description for Sifive p400. + +;; Sifive p400 series is a triple-issue, superscalar, out-of-order processor. + +;; CPU execution units: +;; ialu Integer Units: all arithmetic and logic. +;; +;; bru Branch Resolution Unit: all branches. +;; +;; st Memory Write Unit: all writes to memory. +;; +;; ld Memory Read Unit: all reads from memory. +;; +;; imul Integer Multiply Unit +;; +;; idiv Integer Divide Unit +;; +;; system System Unit: all coprocessor accesses. +;; +;; fpu Floating Point Unit +;; +;; fmul Floating Point Multiply Unit +;; +;; fdiv Floating Point Divide Unit + +;; Four automata are defined to reduce number of states +;; which a single large automaton will have. +(define_automaton "sifive_p400_iex,sifive_p400_fex,sifive_p400_mem,sifive_p400_div") + +;; The Sifive p400 has six pipelines: +;; A-pipe Load, Store +;; B-pipe ALU, Branch +;; M-pipe ALU, MUL, DIV and I2F(integer to float instruction) +;; C-pipe ALU, Conditional move and system for coprocessor accesses +;; F-pipe FPU, MUL, F2I(float to integer instruction) +;; FM-pipe FPU, MUL, DIV + +(define_cpu_unit "sifive_p400_A" "sifive_p400_mem") +(define_cpu_unit "sifive_p400_B" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_M" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_C" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_F" "sifive_p400_fex") +(define_cpu_unit "sifive_p400_FM" "sifive_p400_fex") + +;; Load and store unit. +(define_cpu_unit "sifive_p400_ld" "sifive_p400_mem") +(define_cpu_unit "sifive_p400_st" "sifive_p400_mem") + +;; Branch unit. +(define_cpu_unit "sifive_p400_bru" "sifive_p400_iex") + +;; Integer and multiply unit. +(define_cpu_unit "sifive_p400_ialu" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_imul" "sifive_p400_iex") +(define_cpu_unit "sifive_p400_system" "sifive_p400_iex") + +;; Divide unit. +(define_cpu_unit "sifive_p400_idiv" "sifive_p400_div") +(define_cpu_unit "sifive_p400_fdiv" "sifive_p400_div") + +;; Float and multiply unit. +(define_cpu_unit "sifive_p400_fmul" "sifive_p400_fex") +(define_cpu_unit "sifive_p400_fpu" "sifive_p400_fex") + +;; ALU instruction can use pipeline C, B and M. +(define_reservation "p400_int_pipe" "(sifive_p400_C|sifive_p400_B|sifive_p400_M)") +;; FPU instruction can use pipeline F and FM. +(define_reservation "p400_float_pipe" "(sifive_p400_F|sifive_p400_FM)") + +(define_insn_reservation "sifive_p400_load" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "load")) + "sifive_p400_A,sifive_p400_ld*2") + +(define_insn_reservation "sifive_p400_fpload" 4 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fpload")) + "sifive_p400_A,sifive_p400_ld*3") + +(define_insn_reservation "sifive_p400_store" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "store")) + "sifive_p400_A+sifive_p400_st") + +(define_insn_reservation "sifive_p400_fpstore" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fpstore")) + "sifive_p400_A+sifive_p400_st") + +(define_insn_reservation "sifive_p400_branch" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "branch,jump,call")) + "sifive_p400_B+sifive_p400_bru") + +(define_insn_reservation "sifive_p400_sfb_alu" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "sfb_alu")) + "sifive_p400_C+sifive_p400_bru+sifive_p400_ialu") + +(define_insn_reservation "sifive_p400_atomic" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "atomic")) + "sifive_p400_C,sifive_p400_system*2") + +(define_insn_reservation "sifive_p400_mul" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "imul")) + "sifive_p400_M,sifive_p400_imul*2") + +(define_insn_reservation "sifive_p400_div" 31 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "idiv")) + "sifive_p400_M, sifive_p400_idiv*5") + +(define_insn_reservation "sifive_p400_alu" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "unknown,arith,logical,shift,slt,multi,bitmanip,clz,ctz,rotate")) + "p400_int_pipe+sifive_p400_ialu") + +(define_insn_reservation "sifive_p400_cpop" 3 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "cpop")) + "p400_int_pipe,sifive_p400_ialu*2") + +(define_insn_reservation "sifive_p400_load_immediate" 1 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "nop,const,auipc,move")) + "p400_int_pipe") + +(define_insn_reservation "sifive_p400_fma" 4 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fadd,fmul,fmadd")) + "p400_float_pipe,sifive_p400_fmul*3") + +(define_insn_reservation "sifive_p400_i2f" 2 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "mtc,fcvt_i2f")) + "sifive_p400_M,sifive_p400_ialu") + +(define_insn_reservation "sifive_p400_f2i" 2 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "mfc,fcmp,fcvt_f2i")) + "sifive_p400_F,sifive_p400_fpu") + +(define_insn_reservation "sifive_p400_fmove" 2 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fmove,fcvt")) + "p400_float_pipe,sifive_p400_fpu") + +(define_insn_reservation "sifive_p400_fdiv_s" 18 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "SF")) + "sifive_p400_FM, sifive_p400_fdiv*5") + +(define_insn_reservation "sifive_p400_fdiv_d" 31 + (and (eq_attr "tune" "sifive_p400") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "DF")) + "sifive_p400_FM, sifive_p400_fdiv*5") + +(define_bypass 1 "sifive_p400_load,sifive_p400_alu,sifive_p400_mul,sifive_p400_sfb_alu" + "sifive_p400_alu,sifive_p400_branch") + +(define_bypass 1 "sifive_p400_load,sifive_p400_alu,sifive_p400_mul, + sifive_p400_f2i,sifive_p400_fmove,sifive_p400_sfb_alu" + "sifive_p400_store" "riscv_store_data_bypass_p") + +(define_bypass 1 "sifive_p400_i2f" + "sifive_p400_fma,sifive_p400_f2i,sifive_p400_fmove,sifive_p400_fdiv_s,sifive_p400_fdiv_d") + +(define_bypass 1 "sifive_p400_f2i" + "sifive_p400_branch,sifive_p400_sfb_alu,sifive_p400_mul, + sifive_p400_div,sifive_p400_alu,sifive_p400_cpop") diff --git a/gcc/config/riscv/sifive-p600.md b/gcc/config/riscv/sifive-p600.md new file mode 100644 index 0000000..c048649 --- /dev/null +++ b/gcc/config/riscv/sifive-p600.md @@ -0,0 +1,178 @@ +;; Scheduling description for Sifive p600 series. + +;; Sifive p600 series is a quad-issue, superscalar, out-of-order processor. + +;; CPU execution units: +;; ialu Integer Units: all arithmetic and logic. +;; +;; bru Branch Resolution Unit: all branches. +;; +;; st Memory Write Unit: all writes to memory. +;; +;; ld Memory Read Unit: all reads from memory. +;; +;; imul Integer Multiply Unit +;; +;; idiv Integer Divide Unit +;; +;; system System Unit: all coprocessor accesses. +;; +;; fpu Floating Point Unit +;; +;; fmul Floating Point Multiply Unit +;; +;; fdiv Floating Point Divide Unit + +;; Four automata are defined to reduce number of states +;; which a single large automaton will have. +(define_automaton "sifive_p600_iex,sifive_p600_fex,sifive_p600_mem,sifive_p600_div") + +;; The Sifive p600 has 7 pipelines: +;; A-pipe Load, Store +;; B1-pipe ALU, Branch +;; B2-pipe ALU, Branch +;; M-pipe ALU, MUL, DIV and I2F(integer to float instruction) +;; C-pipe ALU, Conditional move and system for coprocessor accesses +;; F-pipe FPU, MUL, F2I(float to integer instruction) +;; FM-pipe FPU, MUL, DIV + +(define_cpu_unit "sifive_p600_A" "sifive_p600_mem") +(define_cpu_unit "sifive_p600_B1" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_B2" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_M" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_C" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_F" "sifive_p600_fex") +(define_cpu_unit "sifive_p600_FM" "sifive_p600_fex") + +;; Load and store unit. +(define_cpu_unit "sifive_p600_ld" "sifive_p600_mem") +(define_cpu_unit "sifive_p600_st" "sifive_p600_mem") + +;; Branch unit. +(define_cpu_unit "sifive_p600_bru" "sifive_p600_iex") + +;; Integer and multiply unit. +(define_cpu_unit "sifive_p600_ialu" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_imul" "sifive_p600_iex") +(define_cpu_unit "sifive_p600_system" "sifive_p600_iex") + +;; Divide unit. +(define_cpu_unit "sifive_p600_idiv" "sifive_p600_div") +(define_cpu_unit "sifive_p600_fdiv" "sifive_p600_div") + +;; Float and multiply unit. +(define_cpu_unit "sifive_p600_fmul" "sifive_p600_fex") +(define_cpu_unit "sifive_p600_fpu" "sifive_p600_fex") + +;; ALU instruction can use pipeline C, B1, B2 and M. +(define_reservation "int_pipe" "(sifive_p600_C|sifive_p600_B1|sifive_p600_B2|sifive_p600_M)") +;; FPU instruction can use pipeline F and FM. +(define_reservation "float_pipe" "(sifive_p600_F|sifive_p600_FM)") +;; Branch instruction can use pipeline B1 and B2. +(define_reservation "branch_pipe" "(sifive_p600_B1|sifive_p600_B2)") + +(define_insn_reservation "sifive_p600_load" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "load")) + "sifive_p600_A,sifive_p600_ld*2") + +(define_insn_reservation "sifive_p600_fpload" 4 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fpload")) + "sifive_p600_A,sifive_p600_ld*3") + +(define_insn_reservation "sifive_p600_store" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "store")) + "sifive_p600_A+sifive_p600_st") + +(define_insn_reservation "sifive_p600_fpstore" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fpstore")) + "sifive_p600_A+sifive_p600_st") + +(define_insn_reservation "sifive_p600_branch" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "branch,jump,call")) + "branch_pipe+sifive_p600_bru") + +(define_insn_reservation "sifive_p600_sfb_alu" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "sfb_alu")) + "sifive_p600_C+sifive_p600_bru+sifive_p600_ialu") + +(define_insn_reservation "sifive_p600_atomic" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "atomic")) + "sifive_p600_C,sifive_p600_system*2") + +(define_insn_reservation "sifive_p600_mul" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "imul")) + "sifive_p600_M,sifive_p600_imul*2") + +(define_insn_reservation "sifive_p600_div" 16 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "idiv")) + "sifive_p600_M, sifive_p600_idiv*4") + +(define_insn_reservation "sifive_p600_alu" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "unknown,arith,logical,shift,slt,multi,bitmanip,clz,ctz,rotate")) + "int_pipe+sifive_p600_ialu") + +(define_insn_reservation "sifive_p600_cpop" 3 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "cpop")) + "int_pipe,sifive_p600_ialu*2") + +(define_insn_reservation "sifive_p600_load_immediate" 1 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "nop,const,auipc,move")) + "int_pipe") + +(define_insn_reservation "sifive_p600_fma" 4 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fadd,fmul,fmadd")) + "float_pipe,sifive_p600_fmul*3") + +(define_insn_reservation "sifive_p600_i2f" 2 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "mtc,fcvt_i2f")) + "sifive_p600_M,sifive_p600_ialu") + +(define_insn_reservation "sifive_p600_f2i" 2 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "mfc,fcmp,fcvt_f2i")) + "sifive_p600_F,sifive_p600_fpu") + +(define_insn_reservation "sifive_p600_fmove" 2 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fmove,fcvt")) + "float_pipe,sifive_p600_fpu") + +(define_insn_reservation "sifive_p600_fdiv_s" 11 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "SF")) + "sifive_p600_FM, sifive_p600_fdiv*5") + +(define_insn_reservation "sifive_p600_fdiv_d" 19 + (and (eq_attr "tune" "sifive_p600") + (eq_attr "type" "fdiv,fsqrt") + (eq_attr "mode" "DF")) + "sifive_p600_FM, sifive_p600_fdiv*5") + +(define_bypass 1 "sifive_p600_load,sifive_p600_alu,sifive_p600_mul,sifive_p600_sfb_alu" + "sifive_p600_alu,sifive_p600_branch") + +(define_bypass 1 "sifive_p600_load,sifive_p600_alu,sifive_p600_mul, + sifive_p600_f2i,sifive_p600_fmove,sifive_p600_sfb_alu" + "sifive_p600_store" "riscv_store_data_bypass_p") + +(define_bypass 1 "sifive_p600_i2f" + "sifive_p600_fma,sifive_p600_f2i,sifive_p600_fmove,sifive_p600_fdiv_s,sifive_p600_fdiv_d") + +(define_bypass 1 "sifive_p600_f2i" + "sifive_p600_branch,sifive_p600_sfb_alu,sifive_p600_mul, + sifive_p600_div,sifive_p600_alu,sifive_p600_cpop") diff --git a/gcc/config/riscv/thead.cc b/gcc/config/riscv/thead.cc index e4b8c37..951b608 100644 --- a/gcc/config/riscv/thead.cc +++ b/gcc/config/riscv/thead.cc @@ -1141,7 +1141,8 @@ th_print_operand_address (FILE *file, machine_mode mode, rtx x) return true; case ADDRESS_REG_WB: - fprintf (file, "(%s),"HOST_WIDE_INT_PRINT_DEC",%u", reg_names[REGNO (addr.reg)], + fprintf (file, "(%s)," HOST_WIDE_INT_PRINT_DEC ",%u", + reg_names[REGNO (addr.reg)], INTVAL (addr.offset) >> addr.shift, addr.shift); return true; diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h index 5b1d337..85c1f9d 100644 --- a/gcc/config/sol2.h +++ b/gcc/config/sol2.h @@ -255,7 +255,7 @@ along with GCC; see the file COPYING3. If not see " %{!shared:libasan_preinit%O%s} \ %{static-libasan:%{!shared: -Bstatic "\ LD_WHOLE_ARCHIVE_OPTION " -lasan " LD_NO_WHOLE_ARCHIVE_OPTION \ - "-Bdynamic}}%{!static-libasan:-lasan}" + " -Bdynamic}}%{!static-libasan:-z now -lasan}" /* Error out on -fsanitize=thread|leak. */ #define LIBTSAN_EARLY_SPEC "\ diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index fc064a9..fb07480 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -734,6 +734,13 @@ along with GCC; see the file COPYING3. If not see parameter regs. */ #define STACK_POINTER_OFFSET (FIRST_PARM_OFFSET(0) + SPARC_STACK_BIAS) +/* Unbias the stack pointer if needed, and move past the register save area, + that is never in use while a function is active, so that it is regarded as a + callee save area rather than as part of the function's own stack area. This + enables __strub_leave() to do a better job of clearing the stack frame of a + previously-called sibling. */ +#define STACK_ADDRESS_OFFSET STACK_POINTER_OFFSET + /* Base register for access to local variables of the function. */ #define HARD_FRAME_POINTER_REGNUM 30 diff --git a/gcc/config/xtensa/constraints.md b/gcc/config/xtensa/constraints.md index 27fd496..d855fb8 100644 --- a/gcc/config/xtensa/constraints.md +++ b/gcc/config/xtensa/constraints.md @@ -123,29 +123,19 @@ (and (match_code "const_int") (match_test "! xtensa_split1_finished_p ()")))) -;; Memory constraints. Do not use define_memory_constraint here. Doing so -;; causes reload to force some constants into the constant pool, but since -;; the Xtensa constant pool can only be accessed with L32R instructions, it -;; is always better to just copy a constant into a register. Instead, use -;; regular constraints but add a check to allow pseudos during reload. +;; Memory constraints. -(define_constraint "R" +(define_memory_constraint "R" "Memory that can be accessed with a 4-bit unsigned offset from a register." - (ior (and (match_code "mem") - (match_test "smalloffset_mem_p (op)")) - (and (match_code "reg") - (match_test "reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER")))) + (and (match_code "mem") + (match_test "smalloffset_mem_p (op)"))) -(define_constraint "T" +(define_memory_constraint "T" "Memory in a literal pool (addressable with an L32R instruction)." (and (match_code "mem") (match_test "!TARGET_CONST16 && constantpool_mem_p (op)"))) -(define_constraint "U" +(define_memory_constraint "U" "Memory that is not in a literal pool." - (ior (and (match_code "mem") - (match_test "! constantpool_mem_p (op)")) - (and (match_code "reg") - (match_test "reload_in_progress - && REGNO (op) >= FIRST_PSEUDO_REGISTER")))) + (and (match_code "mem") + (match_test "! constantpool_mem_p (op)"))) diff --git a/gcc/config/xtensa/predicates.md b/gcc/config/xtensa/predicates.md index a3dd1a9..a296c7e 100644 --- a/gcc/config/xtensa/predicates.md +++ b/gcc/config/xtensa/predicates.md @@ -143,17 +143,14 @@ (define_predicate "move_operand" (ior (ior (match_operand 0 "register_operand") - (and (match_operand 0 "memory_operand") - (match_test "!constantpool_mem_p (op) - || GET_MODE_SIZE (mode) % UNITS_PER_WORD == 0"))) + (match_operand 0 "memory_operand")) (ior (and (match_code "const_int") (match_test "(GET_MODE_CLASS (mode) == MODE_INT && xtensa_simm12b (INTVAL (op))) || ! xtensa_split1_finished_p ()")) (and (match_code "const_int,const_double,const,symbol_ref,label_ref") (match_test "(TARGET_CONST16 || TARGET_AUTO_LITPOOLS) - && CONSTANT_P (op) - && GET_MODE_SIZE (mode) % UNITS_PER_WORD == 0"))))) + && CONSTANT_P (op)"))))) ;; Accept the floating point constant 1 in the appropriate mode. (define_predicate "const_float_1_operand" diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 12677af..9beac93 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -115,7 +115,6 @@ static enum internal_test map_test_to_internal_test (enum rtx_code); static rtx gen_int_relational (enum rtx_code, rtx, rtx); static rtx gen_float_relational (enum rtx_code, rtx, rtx); static rtx gen_conditional_move (enum rtx_code, machine_mode, rtx, rtx); -static rtx fixup_subreg_mem (rtx); static struct machine_function * xtensa_init_machine_status (void); static rtx xtensa_legitimize_tls_address (rtx); static rtx xtensa_legitimize_address (rtx, rtx, machine_mode); @@ -192,7 +191,6 @@ static void xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, tree function); -static bool xtensa_lra_p (void); static rtx xtensa_delegitimize_address (rtx); @@ -286,9 +284,6 @@ static rtx xtensa_delegitimize_address (rtx); #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM xtensa_cannot_force_const_mem -#undef TARGET_LRA_P -#define TARGET_LRA_P xtensa_lra_p - #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P xtensa_legitimate_address_p @@ -1333,35 +1328,10 @@ xtensa_emit_move_sequence (rtx *operands, machine_mode mode) operands[1] = xtensa_copy_incoming_a7 (operands[1]); - /* During reload we don't want to emit (subreg:X (mem:Y)) since that - instruction won't be recognized after reload, so we remove the - subreg and adjust mem accordingly. */ - if (reload_in_progress) - { - operands[0] = fixup_subreg_mem (operands[0]); - operands[1] = fixup_subreg_mem (operands[1]); - } return 0; } -static rtx -fixup_subreg_mem (rtx x) -{ - if (GET_CODE (x) == SUBREG - && GET_CODE (SUBREG_REG (x)) == REG - && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER) - { - rtx temp = - gen_rtx_SUBREG (GET_MODE (x), - reg_equiv_mem (REGNO (SUBREG_REG (x))), - SUBREG_BYTE (x)); - x = alter_subreg (&temp, true); - } - return x; -} - - /* Check if an incoming argument in a7 is expected to be used soon and if OPND is a register or register pair that includes a7. If so, create a new pseudo and copy a7 into that pseudo at the very @@ -2355,7 +2325,7 @@ xtensa_legitimate_address_p (machine_mode mode, rtx addr, bool strict, code_helper) { /* Allow constant pool addresses. */ - if (mode != BLKmode && GET_MODE_SIZE (mode) >= UNITS_PER_WORD + if (mode != BLKmode && ! TARGET_CONST16 && constantpool_address_p (addr) && ! xtensa_tls_referenced_p (addr)) return true; @@ -3280,7 +3250,7 @@ xtensa_output_integer_literal_parts (FILE *file, rtx x, int size) fputs (", ", file); xtensa_output_integer_literal_parts (file, second, size / 2); } - else if (size == 4) + else if (size == 4 || size == 2) { output_addr_const (file, x); } @@ -4952,6 +4922,10 @@ xtensa_trampoline_init (rtx m_tramp, tree fndecl, rtx chain) static bool xtensa_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x) { + if (CONST_INT_P (x)) + return TARGET_AUTO_LITPOOLS || TARGET_CONST16 + || xtensa_simm12b (INTVAL (x)); + return !xtensa_tls_referenced_p (x); } @@ -5393,12 +5367,4 @@ xtensa_delegitimize_address (rtx op) return op; } -/* Implement TARGET_LRA_P. */ - -static bool -xtensa_lra_p (void) -{ - return TARGET_LRA; -} - #include "gt-xtensa.h" diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index c848e4e..1a2249b 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -87,6 +87,10 @@ ;; the same template. (define_mode_iterator HQI [HI QI]) +;; This mode iterator allows the SI and HI patterns to be defined from +;; the same template. +(define_mode_iterator SHI [SI HI]) + ;; Attributes. @@ -1244,7 +1248,7 @@ (define_split [(set (match_operand:DI 0 "register_operand") (match_operand:DI 1 "const_int_operand"))] - "!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS + "!TARGET_CONST16 && ! xtensa_split1_finished_p ()" [(set (match_dup 0) (match_dup 1)) @@ -1291,28 +1295,30 @@ (set_attr "length" "2,2,2,2,2,2,3,3,3,3,6,3,3,3,3,3")]) (define_split - [(set (match_operand:SI 0 "register_operand") - (match_operand:SI 1 "const_int_operand"))] + [(set (match_operand:SHI 0 "register_operand") + (match_operand:SHI 1 "const_int_operand"))] "!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS && ! xtensa_split1_finished_p () && ! xtensa_simm12b (INTVAL (operands[1]))" [(set (match_dup 0) (match_dup 1))] { - operands[1] = force_const_mem (SImode, operands[1]); + operands[1] = force_const_mem (<MODE>mode, operands[1]); }) (define_split - [(set (match_operand:SI 0 "register_operand") - (match_operand:SI 1 "constantpool_operand"))] + [(set (match_operand:SHI 0 "register_operand") + (match_operand:SHI 1 "constantpool_operand"))] "! optimize_debug && reload_completed" [(const_int 0)] { - rtx x = avoid_constant_pool_reference (operands[1]); + rtx x = avoid_constant_pool_reference (operands[1]), dst = operands[0]; if (! CONST_INT_P (x)) FAIL; - if (! xtensa_constantsynth (operands[0], INTVAL (x))) - emit_move_insn (operands[0], x); + if (<MODE>mode == HImode) + dst = gen_rtx_REG (SImode, REGNO (dst)); + if (! xtensa_constantsynth (dst, INTVAL (x))) + emit_move_insn (dst, x); DONE; }) @@ -1328,8 +1334,8 @@ }) (define_insn "movhi_internal" - [(set (match_operand:HI 0 "nonimmed_operand" "=D,D,a,a,a,a,U,*a,*A") - (match_operand:HI 1 "move_operand" "M,d,r,I,Y,U,r,*A,*r"))] + [(set (match_operand:HI 0 "nonimmed_operand" "=D,D,a,a,a,a,a,U,*a,*A") + (match_operand:HI 1 "move_operand" "M,d,r,I,Y,T,U,r,*A,*r"))] "xtensa_valid_move (HImode, operands)" "@ movi.n\t%0, %x1 @@ -1337,13 +1343,14 @@ mov\t%0, %1 movi\t%0, %x1 movi\t%0, %1 + %v1l32r\t%0, %1 %v1l16ui\t%0, %1 %v0s16i\t%1, %0 rsr\t%0, ACCLO wsr\t%1, ACCLO" - [(set_attr "type" "move,move,move,move,move,load,store,rsr,wsr") + [(set_attr "type" "move,move,move,move,move,load,load,store,rsr,wsr") (set_attr "mode" "HI") - (set_attr "length" "2,2,3,3,3,3,3,3,3")]) + (set_attr "length" "2,2,3,3,3,3,3,3,3,3")]) ;; 8-bit Integer moves @@ -1420,7 +1427,7 @@ if ((!register_operand (operands[0], SFmode) && !register_operand (operands[1], SFmode)) || (FP_REG_P (xt_true_regnum (operands[0])) - && !(reload_in_progress | reload_completed) + && can_create_pseudo_p () && (constantpool_mem_p (operands[1]) || CONSTANT_P (operands[1])))) operands[1] = force_reg (SFmode, operands[1]); @@ -2368,14 +2375,12 @@ (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) - (unspec [(const_int 0)] UNSPEC_LSETUP_END) - (clobber (match_dup 2))])] ; match_scratch + (unspec [(const_int 0)] UNSPEC_LSETUP_END)])] "TARGET_LOOPS && optimize" { /* The loop optimizer doesn't check the predicates... */ if (GET_MODE (operands[0]) != SImode) FAIL; - operands[2] = gen_rtx_SCRATCH (SImode); }) @@ -3264,7 +3269,7 @@ (define_insn_and_split "*eqne_zero_masked_bits" [(set (match_operand:SI 0 "register_operand" "=a") - (match_operator 3 "boolean_operator" + (match_operator:SI 3 "boolean_operator" [(and:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "const_int_operand" "i")) (const_int 0)]))] diff --git a/gcc/config/xtensa/xtensa.opt b/gcc/config/xtensa/xtensa.opt index a953f0b..b653e99 100644 --- a/gcc/config/xtensa/xtensa.opt +++ b/gcc/config/xtensa/xtensa.opt @@ -38,8 +38,8 @@ Target RejectNegative Joined UInteger Var(xtensa_extra_l32r_costs) Init(0) Set extra memory access cost for L32R instruction, in clock-cycle units. mlra -Target Mask(LRA) -Use LRA instead of reload (transitional). +Target Ignore +Does nothing. Preserved for backward compatibility. mtarget-align Target diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2d64d86..8a63a36 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,114 @@ +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR c++/113788 + * parser.cc (CP_PARSER_FLAGS_PARAMETER): New enumerator. + (cp_parser_decl_specifier_seq): Parse RID_THIS only if + CP_PARSER_FLAGS_PARAMETER is set in flags. + (cp_parser_parameter_declaration): Or in CP_PARSER_FLAGS_PARAMETER + when calling cp_parser_decl_specifier_seq. + +2024-02-06 Marek Polacek <polacek@redhat.com> + + * method.cc (early_check_defaulted_comparison): Add + auto_diagnostic_group. + +2024-02-06 Jason Merrill <jason@redhat.com> + + PR c++/107291 + * method.cc (early_check_defaulted_comparison): Fail if not friend. + +2024-02-05 Jason Merrill <jason@redhat.com> + + PR c++/111286 + * tree.cc (rvalue): Don't drop cv-quals from an array. + +2024-02-03 Patrick Palka <ppalka@redhat.com> + + PR c++/110006 + PR c++/112769 + * constraint.cc (subst_info::quiet): Accomodate non-diagnostic + tsubst flags. + (tsubst_valid_expression_requirement): Likewise. + (tsubst_simple_requirement): Return a substituted _REQ node when + processing_template_decl. + (tsubst_type_requirement_1): Accomodate non-diagnostic tsubst + flags. + (tsubst_type_requirement): Return a substituted _REQ node when + processing_template_decl. + (tsubst_compound_requirement): Likewise. Accomodate non-diagnostic + tsubst flags. + (tsubst_nested_requirement): Likewise. + (tsubst_requires_expr): Don't defer partial substitution when + processing_constraint_expression_p is true, in which case return + a substituted REQUIRES_EXPR. + * pt.cc (tsubst_expr) <case REQUIRES_EXPR>: Accomodate + non-diagnostic tsubst flags. + +2024-02-02 Jason Merrill <jason@redhat.com> + + PR c++/110084 + * pt.cc (tsubst_function_decl): Only check a function defaulted + outside the class if the class is complete. + +2024-02-02 Jason Merrill <jason@redhat.com> + + PR c++/112439 + * constexpr.cc (cxx_eval_store_expression): Check empty_base + before marking a CONSTRUCTOR readonly. + +2024-02-02 Jason Merrill <jason@redhat.com> + + PR c++/113638 + * cp-tree.h: Adjust comment. + * pt.cc (instantiate_template): Set VAR_HAD_UNKNOWN_BOUND for + variable template. + +2024-02-01 Marek Polacek <polacek@redhat.com> + + * call.cc (reference_like_class_p): Consider even non-templates for + std::span-like classes. + +2024-02-01 Patrick Palka <ppalka@redhat.com> + + PR c++/112737 + * pt.cc (iterative_hash_template_arg) <case TEMPLATE_DECL>: + Adjust hashing to match cp_tree_equal. + (ctp_hasher::hash): Also hash CLASS_PLACEHOLDER_TEMPLATE. + * tree.cc (cp_tree_equal) <case TEMPLATE_DECL>: Return true + for ttp TEMPLATE_DECLs if their TEMPLATE_TEMPLATE_PARMs are + equivalent. + * typeck.cc (structural_comptypes) <case TEMPLATE_TYPE_PARM>: + Use cp_tree_equal to compare CLASS_PLACEHOLDER_TEMPLATE. + +2024-02-01 Marek Polacek <polacek@redhat.com> + + PR c++/112437 + * typeck.cc (treat_lvalue_as_rvalue_p): Bail out on sk_namespace in + the move on throw of parms loop. + +2024-01-30 Marek Polacek <polacek@redhat.com> + + PR c++/110358 + PR c++/109640 + * call.cc (reference_like_class_p): Don't warn for std::span-like + classes. + +2024-01-30 Patrick Palka <ppalka@redhat.com> + + PR c++/113640 + * call.cc (keep_unused_object_arg): Punt for an xobj member + function. + +2024-01-30 Patrick Palka <ppalka@redhat.com> + + PR c++/113644 + * pt.cc (unify) <case INTEGER_CST>: Handle NULL_TREE type. + +2024-01-30 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/107594 + * module.cc (get_module): Bail on empty name. + 2024-01-29 Jason Merrill <jason@redhat.com> PR c++/113544 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 9de0d77..1dac147 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -5256,7 +5256,7 @@ keep_unused_object_arg (tree result, tree obj, tree fn) { if (result == NULL_TREE || result == error_mark_node - || TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE + || DECL_OBJECT_MEMBER_FUNCTION_P (fn) || !TREE_SIDE_EFFECTS (obj)) return result; @@ -14082,6 +14082,22 @@ reference_like_class_p (tree ctype) return true; } + /* Avoid warning if CTYPE looks like std::span: it has a T* member and + a trivial destructor. For example, + + template<typename T> + struct Span { + T* data_; + std::size len_; + }; + + is considered std::span-like. */ + if (NON_UNION_CLASS_TYPE_P (ctype) && TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) + for (tree field = next_aggregate_field (TYPE_FIELDS (ctype)); + field; field = next_aggregate_field (DECL_CHAIN (field))) + if (TYPE_PTR_P (TREE_TYPE (field))) + return true; + /* Some classes, such as std::tuple, have the reference member in its (non-direct) base class. */ if (dfs_walk_once (TYPE_BINFO (ctype), class_has_reference_member_p_r, diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 6350fe154..2ebb147 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -6694,6 +6694,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, object. Make a note of this fact by marking the CONSTRUCTOR TREE_READONLY. */ if (TREE_CODE (t) == INIT_EXPR + && !empty_base && TREE_CODE (*valp) == CONSTRUCTOR && TYPE_READONLY (type)) { diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index fef68cf..d956901 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -85,7 +85,7 @@ struct subst_info /* True if we should not diagnose errors. */ bool quiet() const { - return complain == tf_none; + return !(complain & tf_warning_or_error); } /* True if we should diagnose errors. */ @@ -1991,8 +1991,9 @@ hash_placeholder_constraint (tree c) static tree tsubst_valid_expression_requirement (tree t, tree args, sat_info info) { - tree r = tsubst_expr (t, args, tf_none, info.in_decl); - if (convert_to_void (r, ICV_STATEMENT, tf_none) != error_mark_node) + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst_expr (t, args, quiet, info.in_decl); + if (convert_to_void (r, ICV_STATEMENT, quiet) != error_mark_node) return r; if (info.diagnose_unsatisfaction_p ()) @@ -2028,6 +2029,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) tree expr = tsubst_valid_expression_requirement (t0, args, info); if (expr == error_mark_node) return error_mark_node; + if (processing_template_decl) + return finish_simple_requirement (EXPR_LOCATION (t), expr); return boolean_true_node; } @@ -2037,7 +2040,8 @@ tsubst_simple_requirement (tree t, tree args, sat_info info) static tree tsubst_type_requirement_1 (tree t, tree args, sat_info info, location_t loc) { - tree r = tsubst (t, args, tf_none, info.in_decl); + tsubst_flags_t quiet = info.complain & ~tf_warning_or_error; + tree r = tsubst (t, args, quiet, info.in_decl); if (r != error_mark_node) return r; @@ -2068,6 +2072,8 @@ tsubst_type_requirement (tree t, tree args, sat_info info) tree type = tsubst_type_requirement_1 (t0, args, info, EXPR_LOCATION (t)); if (type == error_mark_node) return error_mark_node; + if (processing_template_decl) + return finish_type_requirement (EXPR_LOCATION (t), type); return boolean_true_node; } @@ -2124,9 +2130,11 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) location_t loc = cp_expr_loc_or_input_loc (expr); + subst_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); + /* Check the noexcept condition. */ bool noexcept_p = COMPOUND_REQ_NOEXCEPT_P (t); - if (noexcept_p && !expr_noexcept_p (expr, tf_none)) + if (noexcept_p && !expr_noexcept_p (expr, quiet.complain)) { if (info.diagnose_unsatisfaction_p ()) inform (loc, "%qE is not %<noexcept%>", expr); @@ -2139,8 +2147,6 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) if (type == error_mark_node) return error_mark_node; - subst_info quiet (tf_none, info.in_decl); - /* Check expression against the result type. */ if (type) { @@ -2182,6 +2188,9 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) } } + if (processing_template_decl) + return finish_compound_requirement (EXPR_LOCATION (t), + expr, type, noexcept_p); return boolean_true_node; } @@ -2190,7 +2199,16 @@ tsubst_compound_requirement (tree t, tree args, sat_info info) static tree tsubst_nested_requirement (tree t, tree args, sat_info info) { - sat_info quiet (tf_none, info.in_decl); + if (processing_template_decl) + { + tree req = TREE_OPERAND (t, 0); + req = tsubst_constraint (req, args, info.complain, info.in_decl); + if (req == error_mark_node) + return error_mark_node; + return finish_nested_requirement (EXPR_LOCATION (t), req); + } + + sat_info quiet (info.complain & ~tf_warning_or_error, info.in_decl); tree result = constraint_satisfaction_value (t, args, quiet); if (result == boolean_true_node) return boolean_true_node; @@ -2330,18 +2348,25 @@ tsubst_requires_expr (tree t, tree args, sat_info info) args = add_extra_args (REQUIRES_EXPR_EXTRA_ARGS (t), args, info.complain, info.in_decl); - if (processing_template_decl) + if (processing_template_decl + && !processing_constraint_expression_p ()) { /* We're partially instantiating a generic lambda. Substituting into this requires-expression now may cause its requirements to get checked out of order, so instead just remember the template - arguments and wait until we can substitute them all at once. */ + arguments and wait until we can substitute them all at once. + + Except if this requires-expr is part of associated constraints + that we're substituting into directly (for e.g. declaration + matching or dguide constraint rewriting), in which case we need + to partially substitute. */ t = copy_node (t); REQUIRES_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, info.complain); return t; } - if (tree parms = REQUIRES_EXPR_PARMS (t)) + tree parms = REQUIRES_EXPR_PARMS (t); + if (parms) { parms = tsubst_constraint_variables (parms, args, info); if (parms == error_mark_node) @@ -2349,10 +2374,13 @@ tsubst_requires_expr (tree t, tree args, sat_info info) } tree result = boolean_true_node; + if (processing_template_decl) + result = NULL_TREE; for (tree reqs = REQUIRES_EXPR_REQS (t); reqs; reqs = TREE_CHAIN (reqs)) { tree req = TREE_VALUE (reqs); - if (tsubst_requirement (req, args, info) == error_mark_node) + req = tsubst_requirement (req, args, info); + if (req == error_mark_node) { result = boolean_false_node; if (info.diagnose_unsatisfaction_p ()) @@ -2360,7 +2388,11 @@ tsubst_requires_expr (tree t, tree args, sat_info info) else break; } + else if (processing_template_decl) + result = tree_cons (NULL_TREE, req, result); } + if (processing_template_decl && result != boolean_false_node) + result = finish_requires_expr (EXPR_LOCATION (t), parms, nreverse (result)); return result; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f46b448..969c723 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3251,7 +3251,7 @@ struct GTY(()) lang_decl { #define DECL_CONV_FN_TYPE(FN) \ TREE_TYPE ((gcc_checking_assert (DECL_CONV_FN_P (FN)), DECL_NAME (FN))) -/* Nonzero if NODE, a static data member, was declared in its class as an +/* Nonzero if NODE, a templated variable, was declared as an array of unknown bound. */ #define VAR_HAD_UNKNOWN_BOUND(NODE) \ (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \ diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index d49e5a5..957496d 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1228,7 +1228,12 @@ early_check_defaulted_comparison (tree fn) /* Defaulted outside the class body. */ ctx = TYPE_MAIN_VARIANT (parmtype); if (!is_friend (ctx, fn)) - error_at (loc, "defaulted %qD is not a friend of %qT", fn, ctx); + { + auto_diagnostic_group d; + error_at (loc, "defaulted %qD is not a friend of %qT", fn, ctx); + inform (location_of (ctx), "declared here"); + ok = false; + } } else if (!same_type_ignoring_top_level_qualifiers_p (parmtype, ctx)) saw_bad = true; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3748ccd..c4292c4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2088,7 +2088,9 @@ enum /* When parsing of the noexcept-specifier should be delayed. */ CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40, /* When parsing a consteval declarator. */ - CP_PARSER_FLAGS_CONSTEVAL = 0x80 + CP_PARSER_FLAGS_CONSTEVAL = 0x80, + /* When parsing a parameter declaration. */ + CP_PARSER_FLAGS_PARAMETER = 0x100 }; /* This type is used for parameters and variables which hold @@ -16342,7 +16344,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, /* Special case for "this" specifier, indicating a parm is an xobj parm. The "this" specifier must be the first specifier in the declaration, after any attributes. */ - if (token->keyword == RID_THIS) + if (token->keyword == RID_THIS && (flags & CP_PARSER_FLAGS_PARAMETER)) { cp_lexer_consume_token (parser->lexer); if (token != first_specifier) @@ -25607,7 +25609,7 @@ cp_parser_parameter_declaration (cp_parser *parser, /* Parse the declaration-specifiers. */ cp_token *decl_spec_token_start = cp_lexer_peek_token (parser->lexer); cp_parser_decl_specifier_seq (parser, - flags, + flags | CP_PARSER_FLAGS_PARAMETER, &decl_specifiers, &declares_class_or_enum); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index fb2448a..903a4a1 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -1816,6 +1816,11 @@ iterative_hash_template_arg (tree arg, hashval_t val) } return iterative_hash_template_arg (TREE_TYPE (arg), val); + case TEMPLATE_DECL: + if (DECL_TEMPLATE_TEMPLATE_PARM_P (arg)) + return iterative_hash_template_arg (TREE_TYPE (arg), val); + break; + case TARGET_EXPR: return iterative_hash_template_arg (TARGET_EXPR_INITIAL (arg), val); @@ -4499,6 +4504,8 @@ struct ctp_hasher : ggc_ptr_hash<tree_node> hashval_t val = iterative_hash_object (code, 0); val = iterative_hash_object (TEMPLATE_TYPE_LEVEL (t), val); val = iterative_hash_object (TEMPLATE_TYPE_IDX (t), val); + if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) + val = iterative_hash_template_arg (CLASS_PLACEHOLDER_TEMPLATE (t), val); if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM) val = iterative_hash_template_arg (TYPE_TI_ARGS (t), val); --comparing_specializations; @@ -14805,6 +14812,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, if (DECL_SECTION_NAME (t)) set_decl_section_name (r, t); if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) + && COMPLETE_TYPE_P (DECL_CONTEXT (r)) && !processing_template_decl) defaulted_late_check (r); @@ -21698,7 +21706,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case REQUIRES_EXPR: { - tree r = tsubst_requires_expr (t, args, tf_none, in_decl); + complain &= ~tf_warning_or_error; + tree r = tsubst_requires_expr (t, args, complain, in_decl); RETURN (r); } @@ -22098,9 +22107,16 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) DECL_TI_TEMPLATE (fndecl) = tmpl; DECL_TI_ARGS (fndecl) = targ_ptr; if (VAR_P (pattern)) - /* Now that we we've formed this variable template specialization, - remember the result of most_specialized_partial_spec for it. */ - TI_PARTIAL_INFO (DECL_TEMPLATE_INFO (fndecl)) = partial_ti; + { + /* Now that we we've formed this variable template specialization, + remember the result of most_specialized_partial_spec for it. */ + TI_PARTIAL_INFO (DECL_TEMPLATE_INFO (fndecl)) = partial_ti; + + /* And remember if the variable was declared with []. */ + if (TREE_CODE (TREE_TYPE (fndecl)) == ARRAY_TYPE + && TYPE_DOMAIN (TREE_TYPE (fndecl)) == NULL_TREE) + SET_VAR_HAD_UNKNOWN_BOUND (fndecl); + } fndecl = register_specialization (fndecl, gen_tmpl, targ_ptr, false, hash); if (fndecl == error_mark_node) @@ -24949,7 +24965,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, /* Type INTEGER_CST can come from ordinary constant template args. */ case INTEGER_CST: case REAL_CST: - if (!same_type_p (TREE_TYPE (parm), TREE_TYPE (arg))) + if (TREE_TYPE (arg) == NULL_TREE + || !same_type_p (TREE_TYPE (parm), TREE_TYPE (arg))) return unify_template_argument_mismatch (explain_p, parm, arg); while (CONVERT_EXPR_P (arg)) arg = TREE_OPERAND (arg, 0); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 77f57e0..50dc345 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -977,11 +977,12 @@ rvalue (tree expr) expr = mark_rvalue_use (expr); - /* [basic.lval] - - Non-class rvalues always have cv-unqualified types. */ + /* [expr.type]: "If a prvalue initially has the type "cv T", where T is a + cv-unqualified non-class, non-array type, the type of the expression is + adjusted to T prior to any further analysis. */ type = TREE_TYPE (expr); - if (!CLASS_TYPE_P (type) && cv_qualified_p (type)) + if (!CLASS_TYPE_P (type) && TREE_CODE (type) != ARRAY_TYPE + && cv_qualified_p (type)) type = cv_unqualified (type); /* We need to do this for rvalue refs as well to get the right answer @@ -4084,11 +4085,15 @@ cp_tree_equal (tree t1, tree t2) } return false; + case TEMPLATE_DECL: + if (DECL_TEMPLATE_TEMPLATE_PARM_P (t1) + && DECL_TEMPLATE_TEMPLATE_PARM_P (t2)) + return cp_tree_equal (TREE_TYPE (t1), TREE_TYPE (t2)); + /* Fall through. */ case VAR_DECL: case CONST_DECL: case FIELD_DECL: case FUNCTION_DECL: - case TEMPLATE_DECL: case IDENTIFIER_NODE: case SSA_NAME: case USING_DECL: diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index a15eda3..132c55c 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -1573,8 +1573,8 @@ structural_comptypes (tree t1, tree t2, int strict) return false; /* If T1 and T2 don't represent the same class template deduction, they aren't equal. */ - if (CLASS_PLACEHOLDER_TEMPLATE (t1) - != CLASS_PLACEHOLDER_TEMPLATE (t2)) + if (!cp_tree_equal (CLASS_PLACEHOLDER_TEMPLATE (t1), + CLASS_PLACEHOLDER_TEMPLATE (t2))) return false; /* Constrained 'auto's are distinct from parms that don't have the same constraints. */ @@ -10863,7 +10863,9 @@ treat_lvalue_as_rvalue_p (tree expr, bool return_p) for (tree decl = b->names; decl; decl = TREE_CHAIN (decl)) if (decl == retval) return set_implicit_rvalue_p (move (expr)); - if (b->kind == sk_function_parms || b->kind == sk_try) + if (b->kind == sk_function_parms + || b->kind == sk_try + || b->kind == sk_namespace) return NULL_TREE; } } diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 0741a35..45dd031 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,91 @@ +2024-02-04 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd a6f1083699. + * dmd/VERSION: Bump version to v2.107.0 + * Make-lang.in (D_FRONTEND_OBJS): Add d/pragmasem.o. + * d-builtins.cc (strip_type_modifiers): Update for new front-end + interface. + * d-codegen.cc (declaration_type): Likewise. + (parameter_type): Likewise. + * d-target.cc (TargetCPP::parameterType): Likewise. + * expr.cc (ExprVisitor::visit (IndexExp *)): Likewise. + (ExprVisitor::visit (VarExp *)): Likewise. + (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise. + * runtime.cc (get_libcall_type): Likewise. + * typeinfo.cc (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): + Likewise. + (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. + * types.cc (build_ctype): Likewise. + +2024-02-03 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd e770945277. + * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o, + d/funcsem.o, d/templatesem.o. + * d-builtins.cc (build_frontend_type): Update for new front-end + interface. + * d-codegen.cc (declaration_type): Likewise. + (parameter_type): Likewise. + * d-incpath.cc (add_globalpaths): Likewise. + (add_filepaths): Likewise. + (add_import_paths): Likewise. + * d-lang.cc (d_init_options): Likewise. + (d_handle_option): Likewise. + (d_parse_file): Likewise. + * decl.cc (DeclVisitor::finish_vtable): Likewise. + (DeclVisitor::visit (FuncDeclaration *)): Likewise. + (get_symbol_decl): Likewise. + * expr.cc (ExprVisitor::visit (StringExp *)): Likewise. + Implement support for 8-byte hexadecimal strings. + * typeinfo.cc (create_tinfo_types): Update internal TypeInfo + representation. + (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new + front-end interface. + (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. + (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for + TypeInfo_Class.nameSig to the end of the object. + (create_typeinfo): Update for new front-end interface. + +2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd bce5c1f7b5. + * d-attribs.cc (build_attributes): Update for new front-end interface. + * d-lang.cc (d_parse_file): Likewise. + * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise. + * expr.cc (build_lambda_tree): New function. + (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree. + (ExprVisitor::visit (SymOffExp *)): Likewise. + (ExprVisitor::visit (VarExp *)): Likewise. + * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal + TypeInfo representation. + (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data + for TypeInfo_Class.nameSig. + (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new + front-end interface. + +2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd d8e3976a58. + * dmd/VERSION: Bump version to v2.107.0-beta.1. + * d-lang.cc (d_parse_file): Update for new front-end interface. + * modules.cc (struct module_info): Add standalonectors. + (build_module_tree): Implement @standalone. + (register_module_decl): Likewise. + +2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd f1a045928e. + * dmd/VERSION: Bump version to v2.106.1-rc.1. + * gdc.texi (fignore-unknown-pragmas): Update documentation. + * d-builtins.cc (covariant_with_builtin_type_p): Update for new + front-end interface. + * d-lang.cc (d_parse_file): Likewise. + * typeinfo.cc (make_frontend_typeinfo): Likewise. + 2024-01-04 David Malcolm <dmalcolm@redhat.com> * lang.opt.urls: New file, autogenerated by diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index f0a03a1..d379ef1 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -87,6 +87,7 @@ D_FRONTEND_OBJS = \ d/ast_node.o \ d/astcodegen.o \ d/astenums.o \ + d/basicmangle.o \ d/blockexit.o \ d/builtin.o \ d/canthrow.o \ @@ -122,6 +123,7 @@ D_FRONTEND_OBJS = \ d/dtoh.o \ d/dversion.o \ d/entity.o \ + d/enumsem.o \ d/errors.o \ d/errorsink.o \ d/escape.o \ @@ -130,6 +132,7 @@ D_FRONTEND_OBJS = \ d/file_manager.o \ d/foreachvar.o \ d/func.o \ + d/funcsem.o \ d/globals.o \ d/gluelayer.o \ d/hdrgen.o \ @@ -160,6 +163,7 @@ D_FRONTEND_OBJS = \ d/parsetimevisitor.o \ d/permissivevisitor.o \ d/postordervisitor.o \ + d/pragmasem.o \ d/printast.o \ d/root-aav.o \ d/root-array.o \ @@ -192,6 +196,7 @@ D_FRONTEND_OBJS = \ d/stmtstate.o \ d/target.o \ d/templateparamsem.o \ + d/templatesem.o \ d/tokens.o \ d/traits.o \ d/transitivevisitor.o \ diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 8b66cf2..36a139b 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -327,7 +327,7 @@ build_attributes (Expressions *eattrs) for (size_t i = 0; i < eattrs->length; i++) { Expression *attr = (*eattrs)[i]; - Dsymbol *sym = attr->type->toDsymbol (0); + Dsymbol *sym = toDsymbol (attr->type, NULL); if (!sym) { diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 59a1b4c..4ed8751 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -240,7 +240,7 @@ build_frontend_type (tree type) sdecl->sizeok = Sizeok::done; sdecl->type = (TypeStruct::create (sdecl))->addMod (mod); sdecl->type->ctype = type; - sdecl->type->merge2 (); + merge2 (sdecl->type); /* Add both named and anonymous fields as members of the struct. Anonymous fields still need a name in D, so call them "__pad%u". */ @@ -690,7 +690,7 @@ strip_type_modifiers (Type *type) return tnext->pointerTo (); } - return type->castMod (0); + return castMod (type, 0); } /* Returns true if types T1 and T2 representing return types or types of @@ -724,7 +724,7 @@ static bool covariant_with_builtin_type_p (Type *t1, Type *t2) { /* Check whether the declared function matches the built-in. */ - if (same_type_p (t1, t2) || t1->covariant (t2) == Covariant::yes) + if (same_type_p (t1, t2) || covariant (t1, t2) == Covariant::yes) return true; /* May not be covariant because of D attributes applied on t1. diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 22005a4..95dc8b6 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -150,14 +150,14 @@ declaration_type (Declaration *decl) TypeFunction *tf = TypeFunction::create (NULL, decl->type, VARARGnone, LINK::d); TypeDelegate *t = TypeDelegate::create (tf); - return build_ctype (t->merge2 ()); + return build_ctype (merge2 (t)); } /* Static array va_list have array->pointer conversions applied. */ if (decl->isParameter () && valist_array_p (decl->type)) { Type *valist = decl->type->nextOf ()->pointerTo (); - valist = valist->castMod (decl->type->mod); + valist = castMod (valist, decl->type->mod); return build_ctype (valist); } @@ -200,14 +200,14 @@ parameter_type (Parameter *arg) TypeFunction *tf = TypeFunction::create (NULL, arg->type, VARARGnone, LINK::d); TypeDelegate *t = TypeDelegate::create (tf); - return build_ctype (t->merge2 ()); + return build_ctype (merge2 (t)); } /* Static array va_list have array->pointer conversions applied. */ if (valist_array_p (arg->type)) { Type *valist = arg->type->nextOf ()->pointerTo (); - valist = valist->castMod (arg->type->mod); + valist = castMod (valist, arg->type->mod); return build_ctype (valist); } diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc index e505f4e..32ab0b7 100644 --- a/gcc/d/d-incpath.cc +++ b/gcc/d/d-incpath.cc @@ -71,9 +71,6 @@ add_globalpaths (Strings *paths) { if (paths) { - if (!global.path) - global.path = d_gc_malloc<Strings> (); - for (size_t i = 0; i < paths->length; i++) { const char *path = (*paths)[i]; @@ -86,7 +83,7 @@ add_globalpaths (Strings *paths) continue; } - global.path->push (target); + global.path.push (target); } } } @@ -98,9 +95,6 @@ add_filepaths (Strings *paths) { if (paths) { - if (!global.filePath) - global.filePath = d_gc_malloc<Strings> (); - for (size_t i = 0; i < paths->length; i++) { const char *path = (*paths)[i]; @@ -112,7 +106,7 @@ add_filepaths (Strings *paths) continue; } - global.filePath->push (target); + global.filePath.push (target); } } } @@ -143,9 +137,9 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) /* Ignore duplicate entries. */ bool found = false; - for (size_t i = 0; i < global.params.imppath->length; i++) + for (size_t i = 0; i < global.params.imppath.length; i++) { - if (strcmp (path, (*global.params.imppath)[i]) == 0) + if (strcmp (path, global.params.imppath[i]) == 0) { found = true; break; @@ -162,33 +156,26 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) if (imultilib) { char *target_path = concat (path, "/", imultilib, NULL); - global.params.imppath->shift (target_path); + global.params.imppath.shift (target_path); } - global.params.imppath->shift (path); + global.params.imppath.shift (path); } } /* Add import search paths. */ - if (global.params.imppath) + for (size_t i = 0; i < global.params.imppath.length; i++) { - for (size_t i = 0; i < global.params.imppath->length; i++) - { - const char *path = (*global.params.imppath)[i]; - if (path) - add_globalpaths (FileName::splitPath (path)); - } + const char *path = global.params.imppath[i]; + if (path) + add_globalpaths (FileName::splitPath (path)); } /* Add string import search paths. */ - if (global.params.fileImppath) + for (size_t i = 0; i < global.params.fileImppath.length; i++) { - for (size_t i = 0; i < global.params.fileImppath->length; i++) - { - const char *path = (*global.params.fileImppath)[i]; - if (path) - add_filepaths (FileName::splitPath (path)); - } + const char *path = global.params.fileImppath[i]; + if (path) + add_filepaths (FileName::splitPath (path)); } } - diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 7840cf8..138a7f9 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "dmd/cond.h" #include "dmd/declaration.h" #include "dmd/doc.h" +#include "dmd/dsymbol.h" #include "dmd/errors.h" #include "dmd/expression.h" #include "dmd/hdrgen.h" @@ -305,9 +306,6 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) global.params.v.errorLimit = flag_max_errors; global.params.v.messageStyle = MessageStyle::gnu; - global.params.imppath = d_gc_malloc<Strings> (); - global.params.fileImppath = d_gc_malloc<Strings> (); - /* Extra GDC-specific options. */ d_option.fonly = NULL; d_option.multilib = NULL; @@ -723,11 +721,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_I: - global.params.imppath->push (arg); + global.params.imppath.push (arg); break; case OPT_J: - global.params.fileImppath->push (arg); + global.params.fileImppath.push (arg); break; case OPT_MM: @@ -1044,25 +1042,24 @@ d_parse_file (void) { if (global.params.v.verbose) { + /* Dump information about the D compiler and language version. */ message ("binary %s", global.params.argv0.ptr); message ("version %s", global.versionChars ()); - if (global.versionids) + /* Dump all predefined version identifiers. */ + obstack buffer; + gcc_obstack_init (&buffer); + obstack_grow (&buffer, "predefs ", 9); + for (size_t i = 0; i < global.versionids.length; i++) { - obstack buffer; - gcc_obstack_init (&buffer); - obstack_grow (&buffer, "predefs ", 9); - for (size_t i = 0; i < global.versionids->length; i++) - { - Identifier *id = (*global.versionids)[i]; - const char *str = id->toChars (); - obstack_1grow (&buffer, ' '); - obstack_grow (&buffer, str, strlen (str)); - } - - obstack_1grow (&buffer, '\0'); - message ("%s", (char *) obstack_finish (&buffer)); + Identifier *id = global.versionids[i]; + const char *str = id->toChars (); + obstack_1grow (&buffer, ' '); + obstack_grow (&buffer, str, strlen (str)); } + + obstack_1grow (&buffer, '\0'); + message ("%s", (char *) obstack_finish (&buffer)); } /* Start the main input file, if the debug writer wants it. */ @@ -1208,7 +1205,7 @@ d_parse_file (void) message ("import %s", m->toChars ()); OutBuffer buf; - genhdrfile (m, buf); + genhdrfile (m, global.params.dihdr.fullOutput, buf); d_write_file (m->hdrfile.toChars (), buf.peekChars ()); } @@ -1226,7 +1223,7 @@ d_parse_file (void) if (global.params.v.verbose) message ("importall %s", m->toChars ()); - m->importAll (NULL); + importAll (m, NULL); } if (global.errors) @@ -1343,7 +1340,10 @@ d_parse_file (void) } if (global.params.v.templates) - printTemplateStats (); + { + printTemplateStats (global.params.v.templatesListInstances, + global.errorSink); + } /* Generate JSON files. */ if (global.params.json.doOutput) @@ -1372,7 +1372,7 @@ d_parse_file (void) OutBuffer buf; buf.doindent = 1; - moduleToBuffer (buf, m); + moduleToBuffer (buf, true, m); message ("%s", buf.peekChars ()); } } diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 157253e..ff3489c 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -381,11 +381,11 @@ TargetCPP::parameterType (Type *type) Type *tvalist = target.va_listType (Loc (), NULL); if (type->ty == TY::Tsarray && tvalist->ty == TY::Tsarray) { - Type *tb = type->toBasetype ()->mutableOf (); + Type *tb = mutableOf (type->toBasetype ()); if (tb == tvalist) { tb = type->nextOf ()->pointerTo (); - type = tb->castMod (type->mod); + type = castMod (tb, type->mod); } } diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 2374931..d2e84d3 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -539,7 +539,7 @@ public: continue; /* Ensure function has a return value. */ - if (!fd->functionSemantic ()) + if (!functionSemantic (fd)) has_errors = true; /* No name hiding to check for. */ @@ -563,20 +563,23 @@ public: if (fd2->isFuture ()) continue; - if (fd->leastAsSpecialized (fd2, NULL) != MATCH::nomatch - || fd2->leastAsSpecialized (fd, NULL) != MATCH::nomatch) - { - error_at (make_location_t (fd->loc), "use of %qs", - fd->toPrettyChars ()); - inform (make_location_t (fd2->loc), "is hidden by %qs", - fd2->toPrettyChars ()); - inform (make_location_t (d->loc), - "use %<alias %s = %s.%s;%> to introduce base class " - "overload set", fd->toChars (), - fd->parent->toChars (), fd->toChars ()); - has_errors = true; - break; - } + if (FuncDeclaration::leastAsSpecialized (fd, fd2, NULL) + == MATCH::nomatch + && FuncDeclaration::leastAsSpecialized (fd2, fd, NULL) + == MATCH::nomatch) + continue; + + /* Hiding detected; same name, overlapping specializations. */ + error_at (make_location_t (fd->loc), "use of %qs", + fd->toPrettyChars ()); + inform (make_location_t (fd2->loc), "is hidden by %qs", + fd2->toPrettyChars ()); + inform (make_location_t (d->loc), + "use %<alias %s = %s.%s;%> to introduce base class " + "overload set", fd->toChars (), + fd->parent->toChars (), fd->toChars ()); + has_errors = true; + break; } } @@ -782,7 +785,7 @@ public: { /* Do not store variables we cannot take the address of, but keep the values for purposes of debugging. */ - if (d->type->isscalar () && !d->type->hasPointers ()) + if (d->type->isscalar () && !hasPointers (d->type)) { tree decl = get_symbol_decl (d); d_pushdecl (decl); @@ -943,7 +946,7 @@ public: gcc_assert (!doing_semantic_analysis_p); doing_semantic_analysis_p = true; - d->functionSemantic3 (); + functionSemantic3 (d); Module::runDeferredSemantic3 (); doing_semantic_analysis_p = false; } @@ -1231,7 +1234,7 @@ get_symbol_decl (Declaration *decl) if (fd) { /* Run full semantic on functions we need to know about. */ - if (!fd->functionSemantic ()) + if (!functionSemantic (fd)) { decl->csym = error_mark_node; return decl->csym; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 5edcee1..57ac2dc 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -2bbf64907cbbb483d003e0a8fcf8b502e4883799 +a6f10836997d0b5526c8c363d781b4029c77f09f The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index f8ac001..282e818 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -110,6 +110,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | File | Purpose | |-------------------------------------------------------------------------------------------|-------------------------------------------------------------------| | [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) | +| [enumsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d) | Enum semantics | +| [funcsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d) | Function semantics | | [semantic2.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) | | [semantic3.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) | | [inline.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) | @@ -117,6 +119,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | [expressionsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d) | Do semantic analysis for expressions | | [statementsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d) | Do semantic analysis for statements | | [initsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d) | Do semantic analysis for initializers | +| [pragmasem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/pragmasem.d) | Do semantic analysis for pragmas | +| [templatesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templatesem.d) | Do semantic analysis for templates | | [templateparamsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters | | [typesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d) | Do semantic analysis for types | @@ -230,6 +234,7 @@ Note that these groups have no strict meaning, the category assignments are a bi |-----------------------------------------------------------------------------------|------------------------------------------------------------------| | [cppmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmangle.d) | C++ name mangling | | [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmanglewin.d) | C++ name mangling for Windows | +| [basicmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/basicmangle.d) | D name mangling for basic types | | [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) | ### Linking diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 8c95cd0..8463aee 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.106.0 +v2.107.0 diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d index 1010c14..8d02203 100644 --- a/gcc/d/dmd/access.d +++ b/gcc/d/dmd/access.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d) diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 352ca88..2d32042 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -4,7 +4,7 @@ * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions), * $(LINK2 https://dlang.org/spec/class.html, Class). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d) @@ -65,7 +65,7 @@ enum ClassKind : ubyte * Returns: * 0-terminated string for `c` */ -const(char)* toChars(ClassKind c) @safe +const(char)* ClassKindToChars(ClassKind c) @safe { final switch (c) { diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 98fa6bd..f466ba6 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -234,7 +234,8 @@ struct ClassFlags hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, - hasDtor = 0x100 + hasDtor = 0x100, + hasNameSig = 0x200, }; }; diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index a8933f6..0e063ca 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d) @@ -14,16 +14,10 @@ module dmd.aliasthis; import core.stdc.stdio; -import dmd.aggregate; -import dmd.dscope; + import dmd.dsymbol; -import dmd.expression; -import dmd.expressionsem; -import dmd.globals; import dmd.identifier; import dmd.location; -import dmd.mtype; -import dmd.tokens; import dmd.visitor; /*********************************************************** @@ -71,161 +65,3 @@ extern (C++) final class AliasThis : Dsymbol return this.isDeprecated_; } } - -/************************************* - * Find the `alias this` symbol of e's type. - * Params: - * sc = context - * e = expression forming the `this` - * gag = do not print errors, return `null` instead - * findOnly = don't do further processing like resolving properties, - * i.e. just return plain dotExp() result. - * Returns: - * Expression that is `e.aliasthis` - */ -Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) -{ - import dmd.typesem : dotExp; - for (AggregateDeclaration ad = isAggregate(e.type); ad;) - { - if (ad.aliasthis) - { - Loc loc = e.loc; - Type tthis = (e.op == EXP.type ? e.type : null); - const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); - uint olderrors = gag ? global.startGagging() : 0; - e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); - if (!e || findOnly) - return gag && global.endGagging(olderrors) ? null : e; - - if (tthis && ad.aliasthis.sym.needThis()) - { - if (auto ve = e.isVarExp()) - { - if (auto fd = ve.var.isFuncDeclaration()) - { - // https://issues.dlang.org/show_bug.cgi?id=13009 - // Support better match for the overloaded alias this. - bool hasOverloads; - if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) - { - if (!hasOverloads) - fd = f; // use exact match - e = new VarExp(loc, fd, hasOverloads); - e.type = f.type; - e = new CallExp(loc, e); - goto L1; - } - } - } - /* non-@property function is not called inside typeof(), - * so resolve it ahead. - */ - { - int save = sc.intypeof; - sc.intypeof = 1; // bypass "need this" error check - e = resolveProperties(sc, e); - sc.intypeof = save; - } - L1: - e = new TypeExp(loc, new TypeTypeof(loc, e)); - e = e.expressionSemantic(sc); - } - e = resolveProperties(sc, e); - if (!gag) - ad.aliasthis.checkDeprecatedAliasThis(loc, sc); - else if (global.endGagging(olderrors)) - e = null; - } - - import dmd.dclass : ClassDeclaration; - auto cd = ad.isClassDeclaration(); - if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) - { - ad = cd.baseClass; - continue; - } - break; - } - return e; -} - -/** - * Check if an `alias this` is deprecated - * - * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to - * check if `expression` uses a deprecated `aliasthis`, but this calls - * `toPrettyChars` which lead to the following message: - * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" - * - * Params: - * at = The `AliasThis` object to check - * loc = `Loc` of the expression triggering the access to `at` - * sc = `Scope` of the expression - * (deprecations do not trigger in deprecated scopes) - * - * Returns: - * Whether the alias this was reported as deprecated. - */ -bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) -{ - import dmd.errors : deprecation, Classification; - import dmd.dsymbolsem : getMessage; - - if (global.params.useDeprecated != DiagnosticReporting.off - && at.isDeprecated() && !sc.isDeprecated()) - { - const(char)* message = null; - for (Dsymbol p = at; p; p = p.parent) - { - message = p.depdecl ? p.depdecl.getMessage() : null; - if (message) - break; - } - if (message) - deprecation(loc, "`alias %s this` is deprecated - %s", - at.sym.toChars(), message); - else - deprecation(loc, "`alias %s this` is deprecated", - at.sym.toChars()); - - if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) - ti.printInstantiationTrace(Classification.deprecation); - - return true; - } - return false; -} - -/************************************** - * Check and set 'att' if 't' is a recursive 'alias this' type - * - * The goal is to prevent endless loops when there is a cycle in the alias this chain. - * Since there is no multiple `alias this`, the chain either ends in a leaf, - * or it loops back on itself as some point. - * - * Example: S0 -> (S1 -> S2 -> S3 -> S1) - * - * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. - * `S1` is a recursive alias this type, but since `att` is initialized to `null`, - * this still returns `false`, but `att1` is set to `S1`. - * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, - * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. - * - * Params: - * att = type reference used to detect recursion. Should be initialized to `null`. - * t = type of 'alias this' rewrite to attempt - * - * Returns: - * `false` if the rewrite is safe, `true` if it would loop back around - */ -bool isRecursiveAliasThis(ref Type att, Type t) -{ - //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); - auto tb = t.toBasetype(); - if (att && tb.equivalent(att)) - return true; - else if (!att && tb.checkAliasThisRec()) - att = tb; - return false; -} diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h index 092490f..88ba353 100644 --- a/gcc/d/dmd/aliasthis.h +++ b/gcc/d/dmd/aliasthis.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2009-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index c3b8526..afe6054 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d) diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d index 6634a6a..feab9a4 100644 --- a/gcc/d/dmd/arraytypes.d +++ b/gcc/d/dmd/arraytypes.d @@ -1,7 +1,7 @@ /** * Provide aliases for arrays of certain declarations or statements. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d) diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h index 05126a5..7796428 100644 --- a/gcc/d/dmd/arraytypes.h +++ b/gcc/d/dmd/arraytypes.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2006-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2006-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/ast_node.d b/gcc/d/dmd/ast_node.d index 313c2bd..c8c95fa 100644 --- a/gcc/d/dmd/ast_node.d +++ b/gcc/d/dmd/ast_node.d @@ -1,7 +1,7 @@ /** * Defines the base class for all nodes which are part of the AST. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d) diff --git a/gcc/d/dmd/ast_node.h b/gcc/d/dmd/ast_node.h index 6154c6d..a24218a 100644 --- a/gcc/d/dmd/ast_node.h +++ b/gcc/d/dmd/ast_node.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d index d40f836..f179077 100644 --- a/gcc/d/dmd/astcodegen.d +++ b/gcc/d/dmd/astcodegen.d @@ -97,6 +97,6 @@ struct ASTCodegen alias isExpression = dmd.dtemplate.isExpression; alias isTuple = dmd.dtemplate.isTuple; - alias IgnoreErrors = dmd.dsymbol.IgnoreErrors; + alias SearchOpt = dmd.dsymbol.SearchOpt; alias PASS = dmd.dsymbol.PASS; } diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 6a9c010..77940b8 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -1,7 +1,7 @@ /** * Defines enums common to dmd and dmd as parse library. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d) * Documentation: https://dlang.org/phobos/dmd_astenums.html @@ -63,7 +63,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...) - // = 0x1_0000, + constscoperef = 0x1_0000, /// when `in` means const|scope|ref templateparameter = 0x2_0000, /// template parameter ref_ = 0x4_0000, /// `ref` scope_ = 0x8_0000, /// `scope` @@ -112,7 +112,7 @@ enum STC : ulong // transfer changes to declaration.h volatile_ = 0x40_0000_0000_0000, /// destined for volatile in the back end safeGroup = STC.safe | STC.trusted | STC.system, - IOR = STC.in_ | STC.ref_ | STC.out_, + IOR = STC.constscoperef | STC.in_ | STC.ref_ | STC.out_, TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live | safeGroup), @@ -459,3 +459,9 @@ extern (C++) struct structalign_t bool isPack() const { return pack; } void setPack(bool pack) { this.pack = pack; } } + +/// Use to return D arrays from C++ functions +extern (C++) struct DArray(T) +{ + T[] data; +} diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index faf0489..d7d3eca6 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -14,7 +14,7 @@ * - Protection (`private`, `public`) * - Deprecated declarations (`@deprecated`) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d) @@ -123,19 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return sc; } - override void importAll(Scope* sc) - { - Dsymbols* d = include(sc); - //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.importAll(sc2) ); - if (sc2 != sc) - sc2.pop(); - } - } - override void addComment(const(char)* comment) { //printf("AttribDeclaration::addComment %s\n", comment); @@ -150,17 +137,12 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return "attribute"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { Dsymbols* d = include(null); return Dsymbol.oneMembers(d, ps, ident); } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); - } - override final bool hasPointers() { return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; @@ -243,10 +225,10 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining); } - override final bool oneMember(Dsymbol* ps, Identifier ident) + override final bool oneMember(out Dsymbol ps, Identifier ident) { bool t = Dsymbol.oneMembers(decl, ps, ident); - if (t && *ps) + if (t && ps) { /* This is to deal with the following case: * struct Tick { @@ -256,7 +238,7 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration * before the semantic analysis of 'to', so that template overloading based on the * 'this' pointer can be successful. */ - FuncDeclaration fd = (*ps).isFuncDeclaration(); + FuncDeclaration fd = ps.isFuncDeclaration(); if (fd) { /* Use storage_class2 instead of storage_class otherwise when we do .di generation @@ -675,81 +657,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - size_t fieldstart = ad.fields.length; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - uint savestructsize = ad.structsize; - uint savealignsize = ad.alignsize; - ad.structsize = 0; - ad.alignsize = 0; - - FieldState fs; - decl.foreachDsymbol( (s) - { - s.setFieldOffset(ad, fs, this.isunion); - if (this.isunion) - fs.offset = 0; - }); - - /* https://issues.dlang.org/show_bug.cgi?id=13613 - * If the fields in this.members had been already - * added in ad.fields, just update *poffset for the subsequent - * field offset calculation. - */ - if (fieldstart == ad.fields.length) - { - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - fieldState.offset = ad.structsize; - return; - } - - anonstructsize = ad.structsize; - anonalignsize = ad.alignsize; - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - assert(_scope); - auto alignment = _scope.alignment(); - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - anonoffset = placeField( - fieldState.offset, - anonstructsize, anonalignsize, alignment, - ad.structsize, ad.alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - foreach (const i; fieldstart .. ad.fields.length) - { - VarDeclaration v = ad.fields[i]; - //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); - v.offset += anonoffset; - } - } - } - override const(char)* kind() const { return (isunion ? "anonymous union" : "anonymous struct"); @@ -836,7 +743,7 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); } - override final bool oneMember(Dsymbol* ps, Identifier ident) + override final bool oneMember(out Dsymbol ps, Identifier ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); if (condition.inc != Include.notComputed) @@ -846,8 +753,8 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration } else { - bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); - *ps = null; + bool res = (Dsymbol.oneMembers(decl, ps, ident) && ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && ps is null); + ps = null; return res; } } @@ -943,11 +850,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration } } - override void importAll(Scope* sc) - { - // do not evaluate condition before semantic pass - } - override const(char)* kind() const { return "static if"; @@ -999,7 +901,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration Dsymbol.arraySyntaxCopy(decl)); } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { // Required to support IFTI on a template that contains a // `static foreach` declaration. `super.oneMember` calls @@ -1010,7 +912,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration { return super.oneMember(ps, ident); } - *ps = null; // a `static foreach` declaration may in general expand to multiple symbols + ps = null; // a `static foreach` declaration may in general expand to multiple symbols return false; } @@ -1057,11 +959,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration // change this to give semantics to documentation comments on static foreach declarations } - override void importAll(Scope* sc) - { - // do not evaluate aggregate before semantic pass - } - override const(char)* kind() const { return "static foreach"; @@ -1399,3 +1296,27 @@ int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg) return 0; } + + +/** + * Returns: true if the given expression is an enum from `core.attribute` named `id` + */ +bool isEnumAttribute(Expression e, Identifier id) +{ + import dmd.attrib : isCoreUda; + import dmd.id : Id; + + // Logic based on dmd.objc.Supported.declaredAsOptionalCount + auto typeExp = e.isTypeExp; + if (!typeExp) + return false; + + auto typeEnum = typeExp.type.isTypeEnum(); + if (!typeEnum) + return false; + + if (isCoreUda(typeEnum.sym, id)) + return true; + + return false; +} diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 98c5e52..344a7e9 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -26,11 +26,9 @@ public: virtual Dsymbols *include(Scope *sc); virtual Scope *newScope(Scope *sc); - void importAll(Scope *sc) override; void addComment(const utf8_t *comment) override; const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override final; bool hasStaticCtorOrDtor() override final; void checkCtorConstInit() override final; @@ -46,7 +44,7 @@ public: StorageClassDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override final; + bool oneMember(Dsymbol *&ps, Identifier *ident) override final; StorageClassDeclaration *isStorageClassDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -132,7 +130,6 @@ public: unsigned anonalignsize; // size of anonymous struct for alignment purposes AnonDeclaration *syntaxCopy(Dsymbol *s) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; AnonDeclaration *isAnonDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -156,7 +153,7 @@ public: Dsymbols *elsedecl; // array of Dsymbol's for else block ConditionalDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override final; + bool oneMember(Dsymbol *&ps, Identifier *ident) override final; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override final; void accept(Visitor *v) override { v->visit(this); } @@ -171,7 +168,6 @@ public: StaticIfDeclaration *syntaxCopy(Dsymbol *s) override; Dsymbols *include(Scope *sc) override; - void importAll(Scope *sc) override; StaticIfDeclaration *isStaticIfDeclaration() override { return this; } const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } @@ -187,10 +183,9 @@ public: Dsymbols *cache; StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override; - void importAll(Scope *sc) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/basicmangle.d b/gcc/d/dmd/basicmangle.d new file mode 100644 index 0000000..52534fa --- /dev/null +++ b/gcc/d/dmd/basicmangle.d @@ -0,0 +1,109 @@ +/** + * Defines the building blocks for creating the mangled names for basic types. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/basicmangle.d, _basicmangle.d) + * Documentation: https://dlang.org/phobos/dmd_basicmangle.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/basicmangle.d + */ +module dmd.basicmangle; + +import dmd.astenums; +import dmd.common.outbuffer : OutBuffer; + +/// Type mangling mapping for basic, derived and user defined types +immutable char[TMAX] mangleChar = +[ + Tchar : 'a', + Tbool : 'b', + Tcomplex80 : 'c', + Tfloat64 : 'd', + Tfloat80 : 'e', + Tfloat32 : 'f', + Tint8 : 'g', + Tuns8 : 'h', + Tint32 : 'i', + Timaginary80 : 'j', + Tuns32 : 'k', + Tint64 : 'l', + Tuns64 : 'm', + Tnull : 'n', + Timaginary32 : 'o', + Timaginary64 : 'p', + Tcomplex32 : 'q', + Tcomplex64 : 'r', + Tint16 : 's', + Tuns16 : 't', + Twchar : 'u', + Tvoid : 'v', + Tdchar : 'w', + // x // const + // y // immutable + Tint128 : 'z', // zi + Tuns128 : 'z', // zk + + Tarray : 'A', + Ttuple : 'B', + Tclass : 'C', + Tdelegate : 'D', + Tenum : 'E', + Tfunction : 'F', // D function + Tsarray : 'G', + Taarray : 'H', + // I // in + // J // out + // K // ref + // L // lazy + // M // has this, or scope + // N // Nh:vector Ng:wild Nn:noreturn + // O // shared + Tpointer : 'P', + // Q // Type/symbol/identifier backward reference + Treference : 'R', + Tstruct : 'S', + // T // Ttypedef + // U // C function + // W // Windows function + // X // variadic T t...) + // Y // variadic T t,...) + // Z // not variadic, end of parameters + + // '@' shouldn't appear anywhere in the deco'd names + Tnone : '@', + Tident : '@', + Tinstance : '@', + Terror : '@', + Ttypeof : '@', + Tslice : '@', + Treturn : '@', + Tvector : '@', + Ttraits : '@', + Tmixin : '@', + Ttag : '@', + Tnoreturn : '@', // becomes 'Nn' +]; + +unittest +{ + foreach (i, mangle; mangleChar) + { + if (mangle == char.init) + { + import core.stdc.stdio; + fprintf(stderr, "ty = %u\n", cast(uint)i); + assert(0); + } + } +} + +/*********************** + * Mangle basic type ty to buf. + */ +void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe +{ + const c = mangleChar[ty]; + buf.writeByte(c); + if (c == 'z') + buf.writeByte(ty == Tint128 ? 'i' : 'k'); +} diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 5108ecf..d77af7e 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -1,7 +1,7 @@ /** * Find out in what ways control flow can exit a statement block. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d) diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d index 27ba1e0..d29092b 100644 --- a/gcc/d/dmd/builtin.d +++ b/gcc/d/dmd/builtin.d @@ -3,7 +3,7 @@ * * Currently includes functions from `std.math`, `core.math` and `core.bitop`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d) diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 5a608a9..31155f1 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d) diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index 8cfad59..5024f9b 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -1,7 +1,7 @@ /** * Check the arguments to `printf` and `scanf` against the `format` string. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d, _chkformat.d) diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index ca7f398..46470ee 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -2,7 +2,7 @@ * Builds struct member functions if needed and not defined by the user. * Includes `opEquals`, `opAssign`, post blit, copy constructor and destructor. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d) @@ -27,6 +27,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -905,7 +906,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) a.addMember(sc, ad); // temporarily add to symbol table } - sdv.dtor.functionSemantic(); + functionSemantic(sdv.dtor); stc = mergeFuncAttrs(stc, sdv.dtor); if (stc & STC.disable) @@ -1154,7 +1155,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) ad.members.push(func); func.addMember(sc2, ad); func.dsymbolSemantic(sc2); - func.functionSemantic(); // to infer attributes + functionSemantic(func); // to infer attributes sc2.pop(); return func; @@ -1336,7 +1337,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) // perform semantic on the member postblit in order to // be able to aggregate it later on with the rest of the // postblits - sdv.postblit.functionSemantic(); + functionSemantic(sdv.postblit); stc = mergeFuncAttrs(stc, sdv.postblit); stc = mergeFuncAttrs(stc, sdv.dtor); @@ -1401,7 +1402,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) */ if (sdv.dtor) { - sdv.dtor.functionSemantic(); + functionSemantic(sdv.dtor); // keep a list of fields that need to be destroyed in case // of a future postblit failure @@ -1571,7 +1572,7 @@ private Statement generateCopyCtorBody(StructDeclaration sd) * `true` if one needs to be generated * `false` otherwise */ -private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) +bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) { if (global.errors) return false; diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d index b9fcb09..01aa56d 100644 --- a/gcc/d/dmd/common/bitfields.d +++ b/gcc/d/dmd/common/bitfields.d @@ -1,7 +1,7 @@ /** * A library bitfields utility * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Dennis Korpel * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d) diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d index 704110f..8a28424 100644 --- a/gcc/d/dmd/common/file.d +++ b/gcc/d/dmd/common/file.d @@ -4,7 +4,7 @@ * Functions and objects dedicated to file I/O and management. TODO: Move here artifacts * from places such as root/ so both the frontend and the backend have access to them. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d, common/_file.d) diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index 4e7a82f..cb2439f 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -1,7 +1,7 @@ /** * An expandable buffer in which you can write text or binary data. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d, root/_outbuffer.d) @@ -756,6 +756,25 @@ struct OutBuffer } /** + * Write an array as a string of hexadecimal digits + * Params: + * data = bytes to write + * upperCase = whether to upper case hex digits A-F + */ + void writeHexString(scope const(ubyte)[] data, bool upperCase) pure nothrow @safe + { + auto slice = this.allocate(2 * data.length); + const a = upperCase ? 'A' : 'a'; + foreach (i, c; data) + { + char hi = (c >> 4) & 0xF; + slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + a); + char lo = c & 0xF; + slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + a); + } + } + + /** Destructively saves the contents of `this` to `filename`. As an optimization, if the file already has identical contents with the buffer, no copying is done. This is because on SSD drives reading is often much @@ -943,3 +962,11 @@ unittest else assert(buf[] == "\nabc\n\n"); } + +unittest +{ + OutBuffer buf; + buf.writeHexString([0xAA, 0xBB], false); + buf.writeHexString([0xCC], true); + assert(buf[] == "aabbCC"); +} diff --git a/gcc/d/dmd/common/outbuffer.h b/gcc/d/dmd/common/outbuffer.h index 4c1dcee..2250497 100644 --- a/gcc/d/dmd/common/outbuffer.h +++ b/gcc/d/dmd/common/outbuffer.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/common/smallbuffer.d b/gcc/d/dmd/common/smallbuffer.d index ec0eaae..c6aa7ab 100644 --- a/gcc/d/dmd/common/smallbuffer.d +++ b/gcc/d/dmd/common/smallbuffer.d @@ -1,7 +1,7 @@ /** * Common string functions including filename manipulation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/smallbuffer.d, common/_smallbuffer.d) @@ -48,7 +48,7 @@ struct SmallBuffer(Element) } else { - assert(len < sizeof.max / (2 * Element.sizeof)); + assert(len < size_t.max / (2 * Element.sizeof)); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; @@ -76,7 +76,7 @@ struct SmallBuffer(Element) else { __dtor(); - assert(len < sizeof.max / Element.sizeof); + assert(len < size_t.max / Element.sizeof); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d index 8b8a453..65330cf 100644 --- a/gcc/d/dmd/compiler.d +++ b/gcc/d/dmd/compiler.d @@ -1,7 +1,7 @@ /** * Describes a back-end compiler and implements compiler-specific actions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d) diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h index c7cbce3..74351ed 100644 --- a/gcc/d/dmd/compiler.h +++ b/gcc/d/dmd/compiler.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 568b639..e194664 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d) @@ -548,8 +548,6 @@ extern (C++) final class DebugCondition : DVCondition /// Ditto extern(D) static void addGlobalIdent(const(char)[] ident) { - if (!global.debugids) - global.debugids = new Identifiers(); global.debugids.push(Identifier.idPool(ident)); } @@ -579,7 +577,7 @@ extern (C++) final class DebugCondition : DVCondition bool definedInModule = false; if (ident) { - if (findCondition(mod.debugids, ident)) + if (mod.debugids && findCondition(*mod.debugids, ident)) { inc = Include.yes; definedInModule = true; @@ -830,8 +828,6 @@ extern (C++) final class VersionCondition : DVCondition /// Ditto extern(D) static void addPredefinedGlobalIdent(const(char)[] ident) { - if (!global.versionids) - global.versionids = new Identifiers(); global.versionids.push(Identifier.idPool(ident)); } @@ -861,7 +857,7 @@ extern (C++) final class VersionCondition : DVCondition bool definedInModule = false; if (ident) { - if (findCondition(mod.versionids, ident)) + if (mod.versionids && findCondition(*mod.versionids, ident)) { inc = Include.yes; definedInModule = true; @@ -983,15 +979,12 @@ extern (C++) final class StaticIfCondition : Condition * Returns: * true if found */ -bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure +bool findCondition(ref Identifiers ids, Identifier ident) @safe nothrow pure { - if (ids) + foreach (id; ids) { - foreach (id; *ids) - { - if (id == ident) - return true; - } + if (id == ident) + return true; } return false; } diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h index d02ae13..fe497c2d 100644 --- a/gcc/d/dmd/cond.h +++ b/gcc/d/dmd/cond.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index fc3fd3b..f5d2b60 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -5,7 +5,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d) @@ -711,7 +711,7 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e cmp = 1; // if dim1 winds up being 0 foreach (i; 0 .. dim1) { - uinteger_t c = es1.getCodeUnit(i); + uinteger_t c = es1.getIndex(i); auto ee2 = es2[i]; if (ee2.isConst() != 1) { @@ -1038,6 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) else if (tb.ty == Tstruct && e1.op == EXP.int64) { // Struct = 0; + import dmd.typesem : toDsymbol; StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration(); assert(sd); auto elements = new Expressions(); @@ -1118,7 +1119,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) } else { - emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type); + emplaceExp!(IntegerExp)(&ue, loc, es1.getIndex(cast(size_t) i), type); } } else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64) @@ -1281,7 +1282,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringE Type elemType = existingAE.type.nextOf(); foreach (j; 0 .. len) { - const val = newval.getCodeUnit(j); + const val = newval.getIndex(j); (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType); } } @@ -1330,9 +1331,9 @@ int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1 { foreach (j; 0 .. len) { - const val2 = cast(dchar)ae2[j + lo2].toInteger(); - const val1 = se1.getCodeUnit(j + lo1); - const int c = val1 - val2; + const val2 = ae2[j + lo2].toInteger(); + const val1 = se1.getIndex(j + lo1); + const int c = (val1 > val2) - (val1 < val2); if (c) return c; } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 89a5948..d462350 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -3,7 +3,7 @@ * * Specification: C11 * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d) @@ -247,6 +247,8 @@ final class CParser(AST) : Parser!AST break; case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -603,15 +605,23 @@ final class CParser(AST) : Parser!AST { Identifier ident; nextToken(); - if (token.value != TOK.identifier) + if (token.value == TOK.identifier) { - error("identifier expected following `goto`"); + ident = token.ident; + nextToken(); + } + else if (token.value == TOK.mul) + { + /* https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + */ + error("`goto *` computed goto extension is not supported"); ident = null; + cparseUnaryExp(); // parse and throw away } else { - ident = token.ident; - nextToken(); + error("identifier expected following `goto`"); + ident = null; } s = new AST.GotoStatement(loc, ident); check(TOK.semicolon, "`goto` statement"); @@ -725,6 +735,12 @@ final class CParser(AST) : Parser!AST nextToken(); break; + case TOK.wcharLiteral: + e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tuns16); + nextToken(); + break; + + case TOK.dcharLiteral: case TOK.uns32Literal: e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32); nextToken(); @@ -1048,6 +1064,14 @@ final class CParser(AST) : Parser!AST break; } + case TOK.andAnd: + /* https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + */ + error("unary `&&` computed goto extension is not supported"); + nextToken(); + e = cparseCastExp(); + break; + case TOK._Alignof: { nextToken(); @@ -1899,6 +1923,7 @@ final class CParser(AST) : Parser!AST } bool isalias = true; + Identifier idt; if (auto ts = dt.isTypeStruct()) { if (ts.sym.isAnonymous()) @@ -1908,6 +1933,7 @@ final class CParser(AST) : Parser!AST ts.sym.ident = id; isalias = false; } + idt = ts.sym.ident; } else if (auto te = dt.isTypeEnum()) { @@ -1917,24 +1943,25 @@ final class CParser(AST) : Parser!AST te.sym.ident = id; isalias = false; } + idt = te.sym.ident; } else if (auto tt = dt.isTypeTag()) { - if (tt.id || tt.tok == TOK.enum_) - { - if (!tt.id && id) - /* This applies for enums declared as - * typedef enum {A} E; - */ - tt.id = id; - Specifier spec; - declareTag(tt, spec); - } + if (!tt.id && id) + /* This applies for enums declared as + * typedef enum {A} E; + */ + tt.id = id; + Specifier spec; + declareTag(tt, spec); + idt = tt.id; } if (isalias) { + //printf("AliasDeclaration %s %s\n", id.toChars(), dt.toChars()); auto ad = new AST.AliasDeclaration(token.loc, id, dt); - ad.adFlags |= ad.hidden; // do not print when generating .di files + if (id == idt) + ad.adFlags |= ad.hidden; // do not print when generating .di files s = ad; } @@ -4272,6 +4299,7 @@ final class CParser(AST) : Parser!AST case TOK.rightParenthesis: case TOK.rightBracket: case TOK.endOfFile: + case TOK.endOfLine: if (!any) return false; break; @@ -4940,6 +4968,8 @@ final class CParser(AST) : Parser!AST { case TOK.identifier: case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -5261,7 +5291,7 @@ final class CParser(AST) : Parser!AST auto ifn = new AST.ExpInitializer(loc, efn); auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0 auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn); - efn.type = tfn.immutableOf(); + efn.type = tfn.makeImmutable(); efn.committed = true; auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_); auto e = new AST.DeclarationExp(loc, sfn); @@ -5794,6 +5824,9 @@ final class CParser(AST) : Parser!AST buf.writeByte(0); auto slice = buf.peekChars()[0 .. length]; resetDefineLines(slice); // reset lexer + auto save = eSink; + auto eLatch = new ErrorSinkLatch(); + eSink = eLatch; const(char)* endp = &slice[length - 7]; @@ -5801,40 +5834,40 @@ final class CParser(AST) : Parser!AST // indexed by Identifier, returns index into symbols[] // The memory for this is leaked - void addVar(AST.VarDeclaration v) + void addVar(AST.Dsymbol s) { - //printf("addVar() %s\n", v.toChars()); - v.isCmacro(true); // mark it as coming from a C #define + //printf("addVar() %s\n", s.toChars()); + if (auto v = s.isVarDeclaration()) + v.isCmacro(true); // mark it as coming from a C #define /* If it's already defined, replace the earlier * definition */ - if (size_t* pd = cast(void*)v.ident in defineTab) + if (size_t* pd = cast(void*)s.ident in defineTab) { //printf("replacing %s\n", v.toChars()); - (*symbols)[*pd] = v; + (*symbols)[*pd] = s; return; } - defineTab[cast(void*)v.ident] = symbols.length; - symbols.push(v); + defineTab[cast(void*)s.ident] = symbols.length; + symbols.push(s); } - Token n; - while (p < endp) { if (p[0 .. 7] == "#define") { p += 7; - scan(&n); - //printf("%s\n", n.toChars()); - if (n.value == TOK.identifier) + nextToken(); + //printf("define %s\n", token.toChars()); + if (token.value == TOK.identifier) { - auto id = n.ident; - scan(&n); + auto id = token.ident; + const params = *p == '('; + nextToken(); AST.Type t; - switch (n.value) + switch (token.value) { case TOK.endOfLine: // #define identifier nextDefineLine(); @@ -5842,14 +5875,16 @@ final class CParser(AST) : Parser!AST case TOK.int32Literal: case TOK.charLiteral: t = AST.Type.tint32; goto Linteger; + case TOK.wcharLiteral: t = AST.Type.tuns16; goto Linteger; + case TOK.dcharLiteral: case TOK.uns32Literal: t = AST.Type.tuns32; goto Linteger; case TOK.int64Literal: t = AST.Type.tint64; goto Linteger; case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger; Linteger: - const intvalue = n.intvalue; - scan(&n); - if (n.value == TOK.endOfLine) + const intvalue = token.intvalue; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = intvalue; @@ -5870,9 +5905,9 @@ final class CParser(AST) : Parser!AST case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat; Lfloat: - const floatvalue = n.floatvalue; - scan(&n); - if (n.value == TOK.endOfLine) + const floatvalue = token.floatvalue; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = floatvalue; @@ -5886,11 +5921,11 @@ final class CParser(AST) : Parser!AST break; case TOK.string_: - const str = n.ustring; - const len = n.len; - const postfix = n.postfix; - scan(&n); - if (n.value == TOK.endOfLine) + const str = token.ustring; + const len = token.len; + const postfix = token.postfix; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = "string"; @@ -5903,6 +5938,39 @@ final class CParser(AST) : Parser!AST } break; + case TOK.leftParenthesis: + /* Look for: + * #define ID ( expression ) + * and rewrite it to a template function: + * auto ID()() { return expression; } + */ + if (params) + break; // no parameters + nextToken(); + eLatch.sawErrors = false; + auto exp = cparseExpression(); + if (eLatch.sawErrors) // parsing errors + break; // abandon this #define + if (token.value != TOK.rightParenthesis) + break; + nextToken(); + if (token.value != TOK.endOfLine) + break; + auto ret = new AST.ReturnStatement(exp.loc, exp); + auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0); + StorageClass stc = STC.auto_; + auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc); + auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0); + fd.fbody = ret; + AST.Dsymbols* decldefs = new AST.Dsymbols(); + decldefs.push(fd); + AST.TemplateParameters* tpl = new AST.TemplateParameters(); + AST.Expression constraint = null; + auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false); + addVar(tempdecl); + nextDefineLine(); + continue; + default: break; } @@ -5911,8 +5979,8 @@ final class CParser(AST) : Parser!AST } else { - scan(&n); - if (n.value != TOK.endOfLine) + scan(&token); + if (token.value != TOK.endOfLine) { skipToNextLine(); } @@ -5920,6 +5988,7 @@ final class CParser(AST) : Parser!AST nextDefineLine(); } + eSink = save; defines = buf; } diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 55844dd..90b6295 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -4,7 +4,7 @@ * This is the POSIX side of the implementation. * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d) diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h index bb92778..72d895c 100644 --- a/gcc/d/dmd/ctfe.h +++ b/gcc/d/dmd/ctfe.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 43efc05..d2fcf5f 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -1,7 +1,7 @@ /** * CTFE for expressions involving pointers, slices, array concatenation etc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d) @@ -34,6 +34,7 @@ import dmd.root.ctfloat; import dmd.root.port; import dmd.root.rmem; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /****************************************************************/ @@ -568,6 +569,9 @@ StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, T case 4: (cast(dchar*)s)[elemi] = value; break; + case 8: + (cast(ulong*)s)[elemi] = value; + break; default: assert(0); } @@ -636,8 +640,10 @@ bool isSafePointerCast(Type srcPointee, Type destPointee) // It's OK if function pointers differ only in safe/pure/nothrow if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) + { return srcPointee.covariant(destPointee) == Covariant.yes || destPointee.covariant(srcPointee) == Covariant.yes; + } // it's OK to cast to void* if (destPointee.ty == Tvoid) return true; @@ -1491,7 +1497,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len); return CTFEExp.cantexp; } - emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type); + emplaceExp!IntegerExp(pue, loc, es1.getIndex(cast(size_t) indx), type); return pue.exp(); } @@ -1701,7 +1707,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray void* s = mem.xcalloc(newlen + 1, oldse.sz); const data = oldse.peekData(); memcpy(s, data.ptr, copylen * oldse.sz); - const defaultValue = cast(uint)defaultElem.toInteger(); + const defaultValue = cast(ulong)defaultElem.toInteger(); foreach (size_t elemi; copylen .. newlen) { switch (oldse.sz) @@ -1715,6 +1721,9 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray case 4: (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue; break; + case 8: + (cast(ulong*)s)[cast(size_t)(indxlo + elemi)] = cast(ulong)defaultValue; + break; default: assert(0); } diff --git a/gcc/d/dmd/ctorflow.d b/gcc/d/dmd/ctorflow.d index 128c698..ba5240e 100644 --- a/gcc/d/dmd/ctorflow.d +++ b/gcc/d/dmd/ctorflow.d @@ -1,7 +1,7 @@ /** * Manage flow analysis for constructors. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d) diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index bb86b08..9ee8e8c 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1,7 +1,7 @@ /** * Semantic analysis for cast-expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d) @@ -24,11 +24,13 @@ import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.location; @@ -719,11 +721,6 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t) return m; case Tint8: case Tuns8: - if (e.hexString) - { - m = MATCH.convert; - return m; - } break; case Tenum: if (tn.isTypeEnum().sym.isSpecial()) @@ -738,6 +735,14 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t) break; } } + if (e.hexString) + { + if (tn.isintegral && tn.size == e.sz) + { + m = MATCH.convert; + return m; + } + } break; default: @@ -2184,7 +2189,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (auto f = isFuncAddress(e)) { - if (f.checkForwardRef(e.loc)) + if (checkForwardRef(f, e.loc)) { return ErrorExp.get(); } @@ -2440,7 +2445,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (auto f = isFuncAddress(e)) { - if (f.checkForwardRef(e.loc)) + if (checkForwardRef(f, e.loc)) { return ErrorExp.get(); } @@ -2495,7 +2500,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (auto f = isFuncAddress(e)) { - if (f.checkForwardRef(e.loc)) + if (checkForwardRef(f, e.loc)) { return ErrorExp.get(); } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 72b85cf..8bac1f4 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d) @@ -33,6 +33,7 @@ import dmd.mtype; import dmd.objc; import dmd.root.rmem; import dmd.target; +import dmd.typesem; import dmd.visitor; /*********************************************************** @@ -123,6 +124,7 @@ extern (C++) struct BaseClass } } +// These must match the values in druntime/src/object.d enum ClassFlags : uint { none = 0x0, @@ -135,6 +137,7 @@ enum ClassFlags : uint isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100, + hasNameSig = 0x200, } /*********************************************************** @@ -594,7 +597,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration fieldState.offset = structsize; foreach (s; *members) { - s.setFieldOffset(this, fieldState, false); + s.setFieldOffset(this, &fieldState, false); } sizeok = Sizeok.done; @@ -614,7 +617,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration final bool isFuncHidden(FuncDeclaration fd) { //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars()); - Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); + Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors); if (!s) { //printf("not found\n"); @@ -670,6 +673,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration void searchVtbl(ref Dsymbols vtbl) { + import dmd.typesem : covariant; bool seenInterfaceVirtual; foreach (s; vtbl) { diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 0e125fd..93ef63f 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -2,7 +2,7 @@ * Miscellaneous declarations, including typedef, alias, variable declarations including the * implicit this declaration, type tuples, ClassInfo, ModuleInfo and various TypeInfos. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d) @@ -246,8 +246,6 @@ extern (C++) abstract class Declaration : Dsymbol enum nounderscore = 4; // don't prepend _ to mangled name enum hidden = 8; // don't print this in .di files - Symbol* isym; // import version of csym - // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; @@ -1214,88 +1212,6 @@ extern (C++) class VarDeclaration : Declaration return v; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - - if (aliasTuple) - { - // If this variable was really a tuple, set the offsets for the tuple fields - aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); - return; - } - - if (!isField()) - return; - assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter))); - - //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - - /* Fields that are tuples appear both as part of TupleDeclarations and - * as members. That means ignore them if they are already a field. - */ - if (offset) - { - // already a field - fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 - return; - } - for (size_t i = 0; i < ad.fields.length; i++) - { - if (ad.fields[i] == this) - { - // already a field - fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 - return; - } - } - - // Check for forward referenced types which will fail the size() call - Type t = type.toBasetype(); - if (storage_class & STC.ref_) - { - // References are the size of a pointer - t = Type.tvoidptr; - } - Type tv = t.baseElemOf(); - if (tv.ty == Tstruct) - { - auto ts = cast(TypeStruct)tv; - assert(ts.sym != ad); // already checked in ad.determineFields() - if (!ts.sym.determineSize(loc)) - { - type = Type.terror; - errors = true; - return; - } - } - - // List in ad.fields. Even if the type is error, it's necessary to avoid - // pointless error diagnostic "more initializers than fields" on struct literal. - ad.fields.push(this); - - if (t.ty == Terror) - return; - - /* If coming after a bit field in progress, - * advance past the field - */ - fieldState.inFlight = false; - - const sz = t.size(loc); - assert(sz != SIZE_INVALID && sz < uint.max); - uint memsize = cast(uint)sz; // size of member - uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - offset = placeField( - fieldState.offset, - memsize, memalignsize, alignment, - ad.structsize, ad.alignsize, - isunion); - - //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); - } - override const(char)* kind() const { return "variable"; @@ -1803,211 +1719,6 @@ extern (C++) class BitFieldDeclaration : VarDeclaration : (1L << (width - 1)) - 1); return v; } - - override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - enum log = false; - static if (log) - { - printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); - void print(const ref FieldState fieldState) - { - fieldState.print(); - printf(" fieldWidth = %d bits\n", fieldWidth); - } - print(fieldState); - } - - Type t = type.toBasetype(); - const bool anon = isAnonymous(); - - // List in ad.fields. Even if the type is error, it's necessary to avoid - // pointless error diagnostic "more initializers than fields" on struct literal. - if (!anon) - ad.fields.push(this); - - if (t.ty == Terror) - return; - - const sz = t.size(loc); - assert(sz != SIZE_INVALID && sz < uint.max); - uint memsize = cast(uint)sz; // size of member - uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); - - if (fieldWidth == 0 && !anon) - error(loc, "named bit fields cannot have 0 width"); - if (fieldWidth > memsize * 8) - error(loc, "bit field width %d is larger than type", fieldWidth); - - const style = target.c.bitFieldStyle; - - void startNewField() - { - if (log) printf("startNewField()\n"); - uint alignsize; - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (fieldWidth > 32) - alignsize = memalignsize; - else if (fieldWidth > 16) - alignsize = 4; - else if (fieldWidth > 8) - alignsize = 2; - else - alignsize = 1; - } - else - alignsize = memsize; // not memalignsize - - uint dummy; - offset = placeField( - fieldState.offset, - memsize, alignsize, alignment, - ad.structsize, - (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, - isunion); - - fieldState.inFlight = true; - fieldState.fieldOffset = offset; - fieldState.bitOffset = 0; - fieldState.fieldSize = memsize; - } - - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (fieldWidth == 0) - { - if (!isunion) - { - // Use type of zero width field to align to next field - fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - - if (ad.alignsize == 0) - ad.alignsize = 1; - if (!anon && - ad.alignsize < memalignsize) - ad.alignsize = memalignsize; - } - else if (style == TargetC.BitFieldStyle.MS) - { - if (ad.alignsize == 0) - ad.alignsize = 1; - if (fieldWidth == 0) - { - if (fieldState.inFlight && !isunion) - { - // documentation says align to next int - //const alsz = cast(uint)Type.tint32.size(); - const alsz = memsize; // but it really does this - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - } - else if (style == TargetC.BitFieldStyle.DM) - { - if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) - return; // this probably should be a bug in DMC - if (ad.alignsize == 0) - ad.alignsize = 1; - if (fieldWidth == 0) - { - if (fieldState.inFlight && !isunion) - { - const alsz = memsize; - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - } - - if (!fieldState.inFlight) - { - //printf("not in flight\n"); - startNewField(); - } - else if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - // If the bit-field spans more units of alignment than its type, - // start a new field at the next alignment boundary. - if (fieldState.bitOffset == fieldState.fieldSize * 8 && - fieldState.bitOffset + fieldWidth > memalignsize * 8) - { - if (log) printf("more units of alignment than its type\n"); - startNewField(); // the bit field is full - } - else - { - // if alignment boundary is crossed - uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; - uint end = start + fieldWidth; - //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); - if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) - { - if (log) printf("alignment is crossed\n"); - startNewField(); - } - } - } - else if (style == TargetC.BitFieldStyle.DM || - style == TargetC.BitFieldStyle.MS) - { - if (memsize != fieldState.fieldSize || - fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8) - { - //printf("new field\n"); - startNewField(); - } - } - else - assert(0); - - offset = fieldState.fieldOffset; - bitOffset = fieldState.bitOffset; - - const pastField = bitOffset + fieldWidth; - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - auto size = (pastField + 7) / 8; - fieldState.fieldSize = size; - //printf(" offset: %d, size: %d\n", offset, size); - if (isunion) - { - const newstructsize = offset + size; - if (newstructsize > ad.structsize) - ad.structsize = newstructsize; - } - else - ad.structsize = offset + size; - } - else - fieldState.fieldSize = memsize; - //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); - //print(fieldState); - - if (!isunion) - { - fieldState.offset = offset + fieldState.fieldSize; - fieldState.bitOffset = pastField; - } - - //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); - //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); - } } /*********************************************************** @@ -2038,6 +1749,35 @@ extern (C++) final class SymbolDeclaration : Declaration /*********************************************************** */ +private Identifier getTypeInfoIdent(Type t) +{ + import dmd.dmangle; + import core.stdc.stdlib; + import dmd.root.rmem; + // _init_10TypeInfo_%s + OutBuffer buf; + buf.reserve(32); + mangleToBuffer(t, buf); + + const slice = buf[]; + + // Allocate buffer on stack, fail over to using malloc() + char[128] namebuf; + const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; + auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); + + const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", + cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); + //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); + assert(0 < length && length < namelen); // don't overflow the buffer + + auto id = Identifier.idPool(name[0 .. length]); + + if (name != namebuf.ptr) + free(name); + return id; +} + extern (C++) class TypeInfoDeclaration : VarDeclaration { Type tinfo; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index a65fb44..afbb997 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -30,6 +30,9 @@ class StructDeclaration; struct IntRange; struct AttributeViolation; +bool functionSemantic(FuncDeclaration* fd); +bool functionSemantic3(FuncDeclaration* fd); + //enum STC : ulong from astenums.d: #define STCundefined 0ULL @@ -54,7 +57,7 @@ struct AttributeViolation; #define STCforeach 0x4000ULL /// variable for foreach loop #define STCvariadic 0x8000ULL /// the `variadic` parameter in: T foo(T a, U b, V variadic...) - // 0x10000ULL + #define STCconstscoperef 0x10000ULL /// when `in` means const|scope|ref #define STCtemplateparameter 0x20000ULL /// template parameter #define STCref 0x40000ULL /// `ref` #define STCscope 0x80000ULL /// `scope` @@ -118,7 +121,6 @@ public: LINK _linkage; // may be `LINK::system`; use `resolvedLinkage()` to resolve it short inuse; // used to detect cycles uint8_t adFlags; - Symbol* isym; // import version of csym DString mangleOverride; // overridden symbol with pragma(mangle, "...") const char *kind() const override; @@ -281,7 +283,6 @@ public: bool systemInferred(bool v); static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined); VarDeclaration *syntaxCopy(Dsymbol *) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final; const char *kind() const override; AggregateDeclaration *isThis() override final; bool needThis() override final; @@ -700,14 +701,11 @@ public: FuncDeclaration *fdensure(FuncDeclaration *fde); Expressions *fdrequireParams(Expressions *fdrp); Expressions *fdensureParams(Expressions *fdep); - bool functionSemantic(); - bool functionSemantic3(); bool equals(const RootObject * const o) const override final; - int findVtblIndex(Dsymbols *vtbl, int dim); bool overloadInsert(Dsymbol *s) override; bool inUnittest(); - MATCH leastAsSpecialized(FuncDeclaration *g, Identifiers *names); + static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc); const char *toPrettyChars(bool QualifyTypes = false) override; const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' @@ -844,6 +842,7 @@ public: class SharedStaticCtorDeclaration final : public StaticCtorDeclaration { public: + bool standalone; SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *) override; SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() override { return this; } diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d index 490ef56..62800d3 100644 --- a/gcc/d/dmd/delegatize.d +++ b/gcc/d/dmd/delegatize.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d) diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 5713be1..3679976 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d) @@ -18,19 +18,16 @@ import core.stdc.stdio; import dmd.astenums; import dmd.attrib; -import dmd.errors; import dmd.gluelayer; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.expression; import dmd.id; import dmd.identifier; import dmd.init; import dmd.location; import dmd.mtype; -import dmd.typesem; import dmd.visitor; /*********************************************************** @@ -66,6 +63,8 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol import dmd.common.bitfields : generateBitFields; mixin(generateBitFields!(BitFields, ubyte)); + Symbol* sinit; + extern (D) this(const ref Loc loc, Identifier ident, Type memtype) { super(loc, ident); @@ -83,7 +82,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return ed; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { if (isAnonymous()) return Dsymbol.oneMembers(members, ps, ident); @@ -122,98 +121,11 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return isSpecialEnumIdent(ident) && memtype; } - Expression getDefaultValue(const ref Loc loc) - { - Expression handleErrors(){ - defaultval = ErrorExp.get(); - return defaultval; - } - //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); - // https://issues.dlang.org/show_bug.cgi?id=23904 - // Return defaultval only if it is not ErrorExp. - // A speculative context may set defaultval to ErrorExp; - // subsequent non-speculative contexts need to be able - // to print the error. - if (defaultval && !defaultval.isErrorExp()) - return defaultval; - - if (isCsymbol()) - return memtype.defaultInit(loc, true); - - if (_scope) - dsymbolSemantic(this, _scope); - if (errors) - return handleErrors(); - if (!members) - { - if (isSpecial()) - { - /* Allow these special enums to not need a member list - */ - return defaultval = memtype.defaultInit(loc); - } - - error(loc, "%s `%s` is opaque and has no default initializer", kind, toPrettyChars); - return handleErrors(); - } - - foreach (const i; 0 .. members.length) - { - EnumMember em = (*members)[i].isEnumMember(); - if (em) - { - if (em.semanticRun < PASS.semanticdone) - { - error(loc, "%s `%s` forward reference of `%s.init`", kind, toPrettyChars, toChars()); - return handleErrors(); - } - - defaultval = em.value; - return defaultval; - } - } - return handleErrors(); - } - - Type getMemtype(const ref Loc loc) - { - if (_scope) - { - /* Enum is forward referenced. We don't need to resolve the whole thing, - * just the base type - */ - if (memtype) - { - Loc locx = loc.isValid() ? loc : this.loc; - memtype = memtype.typeSemantic(locx, _scope); - } - else - { - // Run semantic to get the type from a possible first member value - dsymbolSemantic(this, _scope); - } - } - if (!memtype) - { - if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone)) - memtype = Type.tint32; - else - { - Loc locx = loc.isValid() ? loc : this.loc; - error(locx, "is forward referenced looking for base type"); - return Type.terror; - } - } - return memtype; - } - override inout(EnumDeclaration) isEnumDeclaration() inout { return this; } - Symbol* sinit; - override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 5c01a9f..b083c03 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -1,7 +1,7 @@ /** * A `Dsymbol` representing a renamed import. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d) @@ -222,48 +222,6 @@ extern (C++) final class Import : Dsymbol return global.errors != errors; } - override void importAll(Scope* sc) - { - if (mod) return; // Already done - - /* - * https://issues.dlang.org/show_bug.cgi?id=15525 - * - * Loading the import has failed, - * most likely because of parsing errors. - * Therefore we cannot trust the resulting AST. - */ - if (load(sc)) - { - // https://issues.dlang.org/show_bug.cgi?id=23873 - // For imports that are not at module or function level, - // e.g. aggregate level, the import symbol is added to the - // symbol table and later semantic is performed on it. - // This leads to semantic analysis on an malformed AST - // which causes all kinds of segfaults. - // The fix is to note that the module has errors and avoid - // semantic analysis on it. - if(mod) - mod.errors = true; - return; - } - - if (!mod) return; // Failed - - if (sc.stc & STC.static_) - isstatic = true; - mod.importAll(null); - mod.checkImportDeprecation(loc, sc); - if (sc.explicitVisibility) - visibility = sc.visibility; - if (!isstatic && !aliasId && !names.length) - sc.scopesym.importScope(mod, visibility); - // Enable access to pkgs/mod as soon as posible, because compiler - // can traverse them before the import gets semantic (Issue: 21501) - if (!aliasId && !names.length) - addPackageAccess(sc.scopesym); - } - /******************************* * Mark the imported packages as accessible from the current * scope. This access check is necessary when using FQN b/c diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 90352e3..b078542 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE)) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d) @@ -33,6 +33,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -49,6 +50,8 @@ import dmd.rootobject; import dmd.root.utf; import dmd.statement; import dmd.tokens; +import dmd.typesem : mutableOf; +import dmd.utils : arrayCastBigEndian; import dmd.visitor; /************************************* @@ -440,7 +443,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta fdError("circular dependency. Functions cannot be interpreted while being compiled"); return CTFEExp.cantexp; } - if (!fd.functionSemantic3()) + if (!functionSemantic3(fd)) return CTFEExp.cantexp; if (fd.semanticRun < PASS.semantic3done) { @@ -1416,6 +1419,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) foreach (ca; *s.catches) { Type catype = ca.type; + import dmd.typesem : isBaseOf; if (!catype.equals(extype) && !catype.isBaseOf(extype, null)) continue; @@ -6096,11 +6100,35 @@ public: result.type = e.to; return; } + // Disallow array type painting, except for conversions between built-in // types of identical size. if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf())) { + auto se = e1.isStringExp(); + // Allow casting a hex string literal to short[], int[] or long[] + if (se && se.hexString && se.postfix == StringExp.NoPostfix) + { + const sz = cast(size_t) e.to.nextOf().size; + if ((se.len % sz) != 0) + { + error(e.loc, "hex string length %d must be a multiple of %d to cast to `%s`", + cast(int) se.len, cast(int) sz, e.to.toChars()); + result = CTFEExp.cantexp; + return; + } + + auto str = arrayCastBigEndian((cast(const ubyte[]) se.peekString()), sz); + emplaceExp!(StringExp)(pue, e1.loc, str, se.len / sz, cast(ubyte) sz); + result = pue.exp(); + result.type = e.to; + return; + } error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars()); + if (se && se.hexString && se.postfix != StringExp.NoPostfix) + errorSupplemental(e.loc, "perhaps remove postfix `%s` from hex string", + (cast(char) se.postfix ~ "\0").ptr); + result = CTFEExp.cantexp; return; } @@ -6237,6 +6265,11 @@ public: { if (soe.offset == 0 && soe.var.isFuncDeclaration()) return; + if (soe.offset == 0 && soe.var.isVarDeclaration() && soe.var.isImmutable()) + { + result = getVarExp(e.loc, istate, soe.var, CTFEGoal.RValue); + return; + } error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars()); result = CTFEExp.cantexp; return; @@ -6359,6 +6392,7 @@ public: { if (auto t = isType(ex.isTypeidExp().obj)) { + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null); if (auto ident = (sym ? sym.ident : null)) { @@ -6643,6 +6677,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) private bool stopPointersEscaping(const ref Loc loc, Expression e) { + import dmd.typesem : hasPointers; if (!e.type.hasPointers()) return true; if (isPointer(e.type)) @@ -6706,7 +6741,7 @@ Statement findGotoTarget(InterState* istate, Identifier ident) Statement target = null; if (ident) { - LabelDsymbol label = istate.fd.searchLabel(ident); + LabelDsymbol label = istate.fd.searchLabel(ident, Loc.initial); assert(label && label.statement); LabelStatement ls = label.statement; target = ls.gotoTarget ? ls.gotoTarget : ls.statement; @@ -7263,6 +7298,33 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi return eresult; } +/// Returns: equivalent `StringExp` from `ArrayLiteralExp ale` containing only `IntegerExp` elements +StringExp arrayLiteralToString(ArrayLiteralExp ale) +{ + const len = ale.elements ? ale.elements.length : 0; + const size = ale.type.nextOf().size(); + + StringExp impl(T)() + { + T[] result = new T[len]; + foreach (i; 0 .. len) + result[i] = cast(T) (*ale.elements)[i].isIntegerExp().getInteger(); + return new StringExp(ale.loc, result[], len, cast(ubyte) size); + } + + switch (size) + { + case 1: + return impl!char(); + case 2: + return impl!wchar(); + case 4: + return impl!dchar(); + default: + assert(0); + } +} + /* Decoding UTF strings for foreach loops. Duplicates the functionality of * the twelve _aApplyXXn functions in aApply.d in the runtime. */ @@ -7299,8 +7361,10 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str = resolveSlice(str, &strTmp); auto se = str.isStringExp(); - auto ale = str.isArrayLiteralExp(); - if (!se && !ale) + if (auto ale = str.isArrayLiteralExp()) + se = arrayLiteralToString(ale); + + if (!se) { error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars()); return CTFEExp.cantexp; @@ -7309,7 +7373,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression Expression eresult = null; // ded-store to prevent spurious warning - // Buffers for encoding; also used for decoding array literals + // Buffers for encoding char[4] utf8buf = void; wchar[2] utf16buf = void; @@ -7323,90 +7387,11 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression dchar rawvalue; // Holds the decoded dchar size_t currentIndex = indx; // The index of the decoded character - if (ale) - { - // If it is an array literal, copy the code points into the buffer - size_t buflen = 1; // #code points in the buffer - size_t n = 1; // #code points in this char - size_t sz = cast(size_t)ale.type.nextOf().size(); + // String literals + size_t saveindx; // used for reverse iteration - switch (sz) - { - case 1: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - while (indx > 0 && buflen < 4) - { - Expression r = (*ale.elements)[indx]; - char x = cast(char)r.isIntegerExp().getInteger(); - if ((x & 0xC0) != 0x80) - break; - --indx; - ++buflen; - } - } - else - buflen = (indx + 4 > len) ? len - indx : 4; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf8buf[i] = cast(char)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue); - break; - - case 2: - if (rvs) - { - // find the start of the string - --indx; - buflen = 1; - Expression r = (*ale.elements)[indx]; - ushort x = cast(ushort)r.isIntegerExp().getInteger(); - if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) - { - --indx; - ++buflen; - } - } - else - buflen = (indx + 2 > len) ? len - indx : 2; - for (size_t i = 0; i < buflen; ++i) - { - Expression r = (*ale.elements)[indx + i]; - utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger(); - } - n = 0; - errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue); - break; - - case 4: - { - if (rvs) - --indx; - Expression r = (*ale.elements)[indx]; - rawvalue = cast(dchar)r.isIntegerExp().getInteger(); - n = 1; - } - break; - - default: - assert(0); - } - if (!rvs) - indx += n; - } - else + switch (se.sz) { - // String literals - size_t saveindx; // used for reverse iteration - - switch (se.sz) - { case 1: { if (rvs) @@ -7450,8 +7435,8 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression default: assert(0); - } } + if (errmsg) { error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr); diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d index 6e6c4b1..c04fbec 100644 --- a/gcc/d/dmd/dmacro.d +++ b/gcc/d/dmd/dmacro.d @@ -1,7 +1,7 @@ /** * Text macro processor for Ddoc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d) diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 2bedccb..1d01647 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d) @@ -137,6 +137,7 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; +import dmd.basicmangle; import dmd.dclass; import dmd.declaration; import dmd.dinterpret; @@ -161,89 +162,6 @@ import dmd.target; import dmd.tokens; import dmd.visitor; -private immutable char[TMAX] mangleChar = -[ - Tchar : 'a', - Tbool : 'b', - Tcomplex80 : 'c', - Tfloat64 : 'd', - Tfloat80 : 'e', - Tfloat32 : 'f', - Tint8 : 'g', - Tuns8 : 'h', - Tint32 : 'i', - Timaginary80 : 'j', - Tuns32 : 'k', - Tint64 : 'l', - Tuns64 : 'm', - Tnull : 'n', - Timaginary32 : 'o', - Timaginary64 : 'p', - Tcomplex32 : 'q', - Tcomplex64 : 'r', - Tint16 : 's', - Tuns16 : 't', - Twchar : 'u', - Tvoid : 'v', - Tdchar : 'w', - // x // const - // y // immutable - Tint128 : 'z', // zi - Tuns128 : 'z', // zk - - Tarray : 'A', - Ttuple : 'B', - Tclass : 'C', - Tdelegate : 'D', - Tenum : 'E', - Tfunction : 'F', // D function - Tsarray : 'G', - Taarray : 'H', - // I // in - // J // out - // K // ref - // L // lazy - // M // has this, or scope - // N // Nh:vector Ng:wild Nn:noreturn - // O // shared - Tpointer : 'P', - // Q // Type/symbol/identifier backward reference - Treference : 'R', - Tstruct : 'S', - // T // Ttypedef - // U // C function - // W // Windows function - // X // variadic T t...) - // Y // variadic T t,...) - // Z // not variadic, end of parameters - - // '@' shouldn't appear anywhere in the deco'd names - Tnone : '@', - Tident : '@', - Tinstance : '@', - Terror : '@', - Ttypeof : '@', - Tslice : '@', - Treturn : '@', - Tvector : '@', - Ttraits : '@', - Tmixin : '@', - Ttag : '@', - Tnoreturn : '@', // becomes 'Nn' -]; - -unittest -{ - foreach (i, mangle; mangleChar) - { - if (mangle == char.init) - { - fprintf(stderr, "ty = %u\n", cast(uint)i); - assert(0); - } - } -} - /************************************************ * Append the mangling of type `t` to `buf`. * Params: @@ -528,7 +446,7 @@ void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref) if (stc & STC.return_) buf.writestring("Nk"); // return - switch (stc & (STC.IOR | STC.lazy_)) + switch (stc & ((STC.IOR | STC.lazy_) & ~STC.constscoperef)) { case 0: break; @@ -584,6 +502,20 @@ public: toBuffer(*buf, id.toString(), s); } + void mangleInteger(dinteger_t v) + { + if (cast(sinteger_t) v < 0) + { + buf.writeByte('N'); + buf.print(-v); + } + else + { + buf.writeByte('i'); + buf.print(v); + } + } + //////////////////////////////////////////////////////////////////////////// void mangleDecl(Declaration sthis) { @@ -991,17 +923,7 @@ public: override void visit(IntegerExp e) { - const v = e.toInteger(); - if (cast(sinteger_t)v < 0) - { - buf.writeByte('N'); - buf.print(-v); - } - else - { - buf.writeByte('i'); - buf.print(v); - } + mangleInteger(e.toInteger()); } override void visit(RealExp e) @@ -1028,6 +950,15 @@ public: char m; OutBuffer tmp; const(char)[] q; + + void mangleAsArray() + { + buf.writeByte('A'); + buf.print(e.len); + foreach (i; 0 .. e.len) + mangleInteger(e.getIndex(i)); + } + /* Write string in UTF-8 format */ switch (e.sz) @@ -1044,7 +975,7 @@ public: { dchar c; if (const s = utf_decodeWchar(slice, u, c)) - error(e.loc, "%.*s", cast(int)s.length, s.ptr); + return mangleAsArray(); else tmp.writeUTF8(c); } @@ -1058,14 +989,16 @@ public: foreach (c; slice) { if (!utf_isValidDchar(c)) - error(e.loc, "invalid UCS-32 char \\U%08x", c); + return mangleAsArray(); else tmp.writeUTF8(c); } q = tmp[]; break; } - + case 8: + // String of size 8 has to be hexstring cast to long[], mangle as array literal + return mangleAsArray(); default: assert(0); } @@ -1073,14 +1006,7 @@ public: buf.writeByte(m); buf.print(q.length); buf.writeByte('_'); // nbytes <= 11 - auto slice = buf.allocate(2 * q.length); - foreach (i, c; q) - { - char hi = (c >> 4) & 0xF; - slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a'); - char lo = c & 0xF; - slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a'); - } + buf.writeHexString(cast(const(ubyte)[]) q, false); } override void visit(ArrayLiteralExp e) @@ -1168,6 +1094,7 @@ private struct Backref { if (t.isFunction_Delegate_PtrToFunction()) { + import dmd.typesem : merge2; t = t.merge2(); } } @@ -1213,19 +1140,6 @@ private struct Backref AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf } - -/*********************** - * Mangle basic type ty to buf. - */ - -private void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe -{ - const c = mangleChar[ty]; - buf.writeByte(c); - if (c == 'z') - buf.writeByte(ty == Tint128 ? 'i' : 'k'); -} - /********************************* * Mangling for mod. */ diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index d096e43..6167e2a 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/module.html, Modules) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d) @@ -401,7 +401,7 @@ extern (C++) final class Module : Package Identifier searchCacheIdent; Dsymbol searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags + SearchOptFlags searchCacheFlags; // cached flags bool insearch; /** @@ -490,7 +490,7 @@ extern (C++) final class Module : Package extern (D) static const(char)[] find(const(char)[] filename) { - return global.fileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null); + return global.fileManager.lookForSourceFile(filename, global.path[]); } extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident) @@ -644,9 +644,9 @@ extern (C++) final class Module : Package { /* Print path */ - if (global.path) + if (global.path.length) { - foreach (i, p; *global.path) + foreach (i, p; global.path[]) fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p); } else @@ -679,23 +679,23 @@ extern (C++) final class Module : Package /* Preprocess the file if it's a .c file */ FileName filename = srcfile; - bool ifile = false; // did we generate a .i file - scope (exit) - { - if (ifile) - File.remove(filename.toChars()); // remove generated file - } + const(ubyte)[] srctext; if (global.preprocess && FileName.equalsExt(srcfile.toString(), c_ext) && FileName.exists(srcfile.toString())) { - filename = global.preprocess(srcfile, loc, ifile, &defines); // run C preprocessor + /* Apply C preprocessor to the .c file, returning the contents + * after preprocessing + */ + srctext = global.preprocess(srcfile, loc, defines).data; } + else + srctext = global.fileManager.getFileContents(filename); + this.src = srctext; - if (auto result = global.fileManager.lookup(filename)) + if (srctext) { - this.src = result; if (global.params.makeDeps.doOutput) global.params.makeDeps.files.push(srcfile.toChars()); return true; @@ -921,70 +921,6 @@ extern (C++) final class Module : Package return this; } - override void importAll(Scope* prevsc) - { - //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - if (_scope) - return; // already done - if (filetype == FileType.ddoc) - { - error(loc, "%s `%s` is a Ddoc file, cannot import it", kind, toPrettyChars); - return; - } - - /* Note that modules get their own scope, from scratch. - * This is so regardless of where in the syntax a module - * gets imported, it is unaffected by context. - * Ignore prevsc. - */ - Scope* sc = Scope.createGlobal(this, global.errorSink); // create root scope - - if (md && md.msg) - md.msg = semanticString(sc, md.msg, "deprecation message"); - - // Add import of "object", even for the "object" module. - // If it isn't there, some compiler rewrites, like - // classinst == classinst -> .object.opEquals(classinst, classinst) - // would fail inside object.d. - if (filetype != FileType.c && - (members.length == 0 || - (*members)[0].ident != Id.object || - (*members)[0].isImport() is null)) - { - auto im = new Import(Loc.initial, null, Id.object, null, 0); - members.shift(im); - } - if (!symtab) - { - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.addMember(sc, sc.scopesym); - } - } - // anything else should be run after addMember, so version/debug symbols are defined - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - this.setScope(sc); // remember module scope for semantic - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.setScope(sc); - } - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.importAll(sc); - } - sc = sc.pop(); - sc.pop(); // 2 pops because Scope.createGlobal() created 2 - } - /********************************** * Determine if we need to generate an instance of ModuleInfo * for this Module. @@ -1021,14 +957,14 @@ extern (C++) final class Module : Package } } - override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) + override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) { if (insearch) // don't follow import cycles return false; insearch = true; scope (exit) insearch = false; - if (flags & IgnorePrivateImports) + if (flags & SearchOpt.ignorePrivateImports) visibility = Visibility(Visibility.Kind.public_); // only consider public imports return super.isPackageAccessible(p, visibility); } @@ -1384,7 +1320,53 @@ extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses) return 0; } - ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg); + _foreach(null, mod.members, &pushAddClassDg); +} + + +alias ForeachDg = int delegate(size_t idx, Dsymbol s); + +/*************************************** + * Expands attribute declarations in members in depth first + * order. Calls dg(size_t symidx, Dsymbol *sym) for each + * member. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + * Returns: + * last value returned by dg() + */ +int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) +{ + assert(dg); + if (!members) + return 0; + size_t n = pn ? *pn : 0; // take over index + int result = 0; + foreach (size_t i; 0 .. members.length) + { + import dmd.attrib : AttribDeclaration; + import dmd.dtemplate : TemplateMixin; + + Dsymbol s = (*members)[i]; + if (AttribDeclaration a = s.isAttribDeclaration()) + result = _foreach(sc, a.include(sc), dg, &n); + else if (TemplateMixin tm = s.isTemplateMixin()) + result = _foreach(sc, tm.members, dg, &n); + else if (s.isTemplateInstance()) + { + } + else if (s.isUnitTestDeclaration()) + { + } + else + result = dg(n++, s); + if (result) + break; + } + if (pn) + *pn = n; // update index + return result; } /** diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 5488d5a..bcf358c 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/ddoc.html, Documentation Generator) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/doc.d, _doc.d) @@ -748,7 +748,8 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false) auto a = imp.aliases[i]; auto id = a ? a : imp.names[i]; auto loc = Loc.init; - if (auto symFromId = sc.search(loc, id, null)) + Dsymbol pscopesym; + if (auto symFromId = sc.search(loc, id, pscopesym)) { emitAnchor(buf, symFromId, sc, forHeader); } @@ -1295,7 +1296,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) Type origType = d.originalType ? d.originalType : d.type; if (origType.ty == Tfunction) { - functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, &hgs, td); + functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, hgs, td); } else toCBuffer(origType, *buf, d.ident, hgs); @@ -1354,6 +1355,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) { if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum) { + import dmd.typesem : toDsymbol; if (Dsymbol s = type.toDsymbol(null)) // elaborate type prettyPrintDsymbol(s, ad.parent); else @@ -3636,11 +3638,12 @@ struct MarkdownLinkReferences if (id) { auto loc = Loc(); - auto symbol = _scope.search(loc, id, null, IgnoreErrors); + Dsymbol pscopesym; + auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors); for (size_t i = 1; symbol && i < ids.length; ++i) { id = Identifier.lookup(ids[i].ptr, ids[i].length); - symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null; + symbol = id !is null ? symbol.search(loc, id, SearchOpt.ignoreErrors) : null; } if (symbol) link = MarkdownLink(createHref(symbol), null, name, symbol); @@ -4997,7 +5000,8 @@ void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset) auto a = imp.aliases[i]; auto id = a ? a : imp.names[i]; auto loc = Loc.init; - if (auto symFromId = sc.search(loc, id, null)) + Dsymbol pscopesym; + if (auto symFromId = sc.search(loc, id, pscopesym)) { highlightCode(sc, symFromId, buf, offset); } @@ -5200,6 +5204,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) highlight = "$(D_COMMENT "; break; case TOK.string_: + case TOK.interpolated: highlight = "$(D_STRING "; break; default: @@ -5212,7 +5217,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) res.writestring(highlight); size_t o = res.length; highlightCode3(sc, res, tok.ptr, lex.p); - if (tok.value == TOK.comment || tok.value == TOK.string_) + if (tok.value == TOK.comment || tok.value == TOK.string_ || tok.value == TOK.interpolated) /* https://issues.dlang.org/show_bug.cgi?id=7656 * https://issues.dlang.org/show_bug.cgi?id=7715 * https://issues.dlang.org/show_bug.cgi?id=10519 diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h index ebd3094..71a66b9 100644 --- a/gcc/d/dmd/doc.h +++ b/gcc/d/dmd/doc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index d68bcda..e02ba9a 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -3,7 +3,7 @@ * * Not to be confused with the `scope` storage class. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d) @@ -97,6 +97,7 @@ extern (C++) struct Scope Dsymbol inunion; /// != null if processing members of a union bool nofree; /// true if shouldn't free it bool inLoop; /// true if inside a loop (where constructor calls aren't allowed) + bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; /// in typeof(exp) VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init ErrorSink eSink; /// sink for error messages @@ -344,13 +345,13 @@ extern (C++) struct Scope * Params: * loc = location to use for error messages * ident = name to look up - * pscopesym = if supplied and name is found, set to scope that ident was found in + * pscopesym = if supplied and name is found, set to scope that ident was found in, otherwise set to null * flags = modify search based on flags * * Returns: * symbol if found, null if not */ - extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) + extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all) { version (LOGSEARCH) { @@ -371,7 +372,7 @@ extern (C++) struct Scope } // This function is called only for unqualified lookup - assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); + assert(!(flags & (SearchOpt.localsOnly | SearchOpt.importsOnly))); /* If ident is "start at module scope", only look at module scope */ @@ -386,15 +387,14 @@ extern (C++) struct Scope if (Dsymbol s = sc.scopesym.isModule()) { //printMsg("\tfound", s); - if (pscopesym) - *pscopesym = sc.scopesym; + pscopesym = sc.scopesym; return s; } } return null; } - Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp) + Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, SearchOptFlags flags, Expression* exp) { import dmd.mtype; if (!ad || !ad.aliasthis) @@ -458,7 +458,7 @@ extern (C++) struct Scope return s; } - Dsymbol searchScopes(int flags) + Dsymbol searchScopes(SearchOptFlags flags) { for (Scope* sc = &this; sc; sc = sc.enclosing) { @@ -468,13 +468,13 @@ extern (C++) struct Scope //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); if (sc.scopesym.isModule()) - flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration()) continue; // C doesn't have struct scope if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) { - if (flags & TagNameSpace) + if (flags & SearchOpt.tagNameSpace) { // ImportC: if symbol is not a tag, look for it in tag table if (!s.isScopeDsymbol()) @@ -486,8 +486,7 @@ extern (C++) struct Scope } } //printMsg("\tfound local", s); - if (pscopesym) - *pscopesym = sc.scopesym; + pscopesym = sc.scopesym; return s; } @@ -499,8 +498,7 @@ extern (C++) struct Scope if (aliasSym) { //printf("found aliassym: %s\n", aliasSym.toChars()); - if (pscopesym) - *pscopesym = new ExpressionDsymbol(exp); + pscopesym = new ExpressionDsymbol(exp); return aliasSym; } } @@ -513,15 +511,15 @@ extern (C++) struct Scope } if (this.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; // First look in local scopes - Dsymbol s = searchScopes(flags | SearchLocalsOnly); + Dsymbol s = searchScopes(flags | SearchOpt.localsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s); if (!s) { // Second look in imported modules - s = searchScopes(flags | SearchImportsOnly); + s = searchScopes(flags | SearchOpt.importsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s); } return s; @@ -554,8 +552,8 @@ extern (C++) struct Scope return null; Scope* sc = &this; Module.clearCache(); - Dsymbol scopesym = null; - Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors); + Dsymbol scopesym; + Dsymbol s = sc.search(Loc.initial, id, scopesym, SearchOpt.ignoreErrors); if (!s) return null; @@ -579,9 +577,9 @@ extern (C++) struct Scope return s; } - Dsymbol scopesym = null; + Dsymbol scopesym; // search for exact name first - if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors)) + if (auto s = search(Loc.initial, ident, scopesym, SearchOpt.ignoreErrors)) return s; return speller!scope_search_fp(ident.toString()); } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 36e847c..7546fb6 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d) @@ -289,7 +289,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration for (size_t i = 0; i < members.length; i++) { Dsymbol s = (*members)[i]; - s.setFieldOffset(this, fieldState, isunion); + s.setFieldOffset(this, &fieldState, isunion); } if (type.ty == Terror) { @@ -434,7 +434,11 @@ extern (C++) class StructDeclaration : AggregateDeclaration ispod = ThreeState.yes; - if (enclosing || postblit || dtor || hasCopyCtor) + import dmd.clone; + bool hasCpCtorLocal; + needCopyCtor(this, hasCpCtorLocal); + + if (enclosing || search(this, loc, Id.postblit) || search(this, loc, Id.dtor) || hasCpCtorLocal) { ispod = ThreeState.no; return false; @@ -612,7 +616,7 @@ bool _isZeroInit(Expression exp) foreach (i; 0 .. se.len) { - if (se.getCodeUnit(i)) + if (se.getIndex(i) != 0) return false; } return true; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 8f5a292..5e7922e 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1,7 +1,7 @@ /** * The base class for a D symbol, which can be a module, variable, function, enum, etc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d) @@ -203,20 +203,21 @@ enum PASS : ubyte } // Search options -enum : int +alias SearchOptFlags = uint; +enum SearchOpt : SearchOptFlags { - IgnoreNone = 0x00, // default - IgnorePrivateImports = 0x01, // don't search private imports - IgnoreErrors = 0x02, // don't give error messages - IgnoreAmbiguous = 0x04, // return NULL if ambiguous - SearchLocalsOnly = 0x08, // only look at locals (don't search imports) - SearchImportsOnly = 0x10, // only look in imports - SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, + all = 0x00, // search for all symbols + ignorePrivateImports = 0x01, // don't search private imports + ignoreErrors = 0x02, // don't give error messages + ignoreAmbiguous = 0x04, // return NULL if ambiguous + localsOnly = 0x08, // only look at locals (don't search imports) + importsOnly = 0x10, // only look in imports + unqualifiedModule = 0x20, // the module scope search is unqualified, // meaning don't search imports in that scope, // because qualified module searches search // their imports - IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols - TagNameSpace = 0x100, // search ImportC tag symbol table + tagNameSpace = 0x40, // search ImportC tag symbol table + ignoreVisibility = 0x80, // also find private and package protected symbols } /*********************************************************** @@ -712,10 +713,6 @@ extern (C++) class Dsymbol : ASTNode return toAlias(); } - void importAll(Scope* sc) - { - } - bool overloadInsert(Dsymbol s) { //printf("Dsymbol::overloadInsert('%s')\n", s.toChars()); @@ -848,27 +845,27 @@ extern (C++) class Dsymbol : ASTNode /************************************** * Determine if this symbol is only one. * Returns: - * false, *ps = NULL: There are 2 or more symbols - * true, *ps = NULL: There are zero symbols - * true, *ps = symbol: The one and only one symbol + * false, ps = null: There are 2 or more symbols + * true, ps = null: There are zero symbols + * true, ps = symbol: The one and only one symbol */ - bool oneMember(Dsymbol* ps, Identifier ident) + bool oneMember(out Dsymbol ps, Identifier ident) { //printf("Dsymbol::oneMember()\n"); - *ps = this; + ps = this; return true; } /***************************************** * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ - extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident) + extern (D) static bool oneMembers(Dsymbols* members, out Dsymbol ps, Identifier ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members.length : 0); Dsymbol s = null; if (!members) { - *ps = null; + ps = null; return true; } @@ -880,21 +877,21 @@ extern (C++) class Dsymbol : ASTNode if (!x) { //printf("\tfalse 1\n"); - assert(*ps is null); + assert(ps is null); return false; } - if (*ps) + if (ps) { assert(ident); - if (!(*ps).ident || !(*ps).ident.equals(ident)) + if (!ps.ident || !ps.ident.equals(ident)) continue; if (!s) - s = *ps; - else if (s.isOverloadable() && (*ps).isOverloadable()) + s = ps; + else if (s.isOverloadable() && ps.isOverloadable()) { // keep head of overload set FuncDeclaration f1 = s.isFuncDeclaration(); - FuncDeclaration f2 = (*ps).isFuncDeclaration(); + FuncDeclaration f2 = ps.isFuncDeclaration(); if (f1 && f2) { assert(!f1.isFuncAliasDeclaration()); @@ -911,21 +908,17 @@ extern (C++) class Dsymbol : ASTNode } else // more than one symbol { - *ps = null; + ps = null; //printf("\tfalse 2\n"); return false; } } } - *ps = s; // s is the one symbol, null if none + ps = s; // s is the one symbol, null if none //printf("\ttrue\n"); return true; } - void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - } - /***************************************** * Is Dsymbol a variable that contains pointers? */ @@ -1263,7 +1256,7 @@ public: (*pary)[p.tag] = true; } - bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow + bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) nothrow { if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] || visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag]) @@ -1272,7 +1265,7 @@ public: { // only search visible scopes && imported modules should ignore private imports if (visibility.kind <= visibilities[i] && - ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports)) + ss.isScopeDsymbol.isPackageAccessible(p, visibility, SearchOpt.ignorePrivateImports)) return true; } return false; @@ -1371,48 +1364,6 @@ public: return false; } - extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s); - - /*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - * Returns: - * last value returned by dg() - */ - extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) - { - assert(dg); - if (!members) - return 0; - size_t n = pn ? *pn : 0; // take over index - int result = 0; - foreach (size_t i; 0 .. members.length) - { - Dsymbol s = (*members)[i]; - if (AttribDeclaration a = s.isAttribDeclaration()) - result = _foreach(sc, a.include(sc), dg, &n); - else if (TemplateMixin tm = s.isTemplateMixin()) - result = _foreach(sc, tm.members, dg, &n); - else if (s.isTemplateInstance()) - { - } - else if (s.isUnitTestDeclaration()) - { - } - else - result = dg(n++, s); - if (result) - break; - } - if (pn) - *pn = n; // update index - return result; - } - override final inout(ScopeDsymbol) isScopeDsymbol() inout { return this; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 15c9970..e463d3d 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -147,20 +147,21 @@ enum /* Flags for symbol search */ -enum +typedef unsigned SearchOptFlags; +enum class SearchOpt : SearchOptFlags { - IgnoreNone = 0x00, // default - IgnorePrivateImports = 0x01, // don't search private imports - IgnoreErrors = 0x02, // don't give error messages - IgnoreAmbiguous = 0x04, // return NULL if ambiguous - SearchLocalsOnly = 0x08, // only look at locals (don't search imports) - SearchImportsOnly = 0x10, // only look in imports - SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, - // meaning don't search imports in that scope, - // because qualified module searches search - // their imports - IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols - TagNameSpace = 0x100, // search ImportC tag symbol table + all = 0x00, // default + ignorePrivateImports = 0x01, // don't search private imports + ignoreErrors = 0x02, // don't give error messages + ignoreAmbiguous = 0x04, // return NULL if ambiguous + localsOnly = 0x08, // only look at locals (don't search imports) + importsOnly = 0x10, // only look in imports + unqualifiedModule = 0x20, // the module scope search is unqualified, + // meaning don't search imports in that scope, + // because qualified module searches search + // their imports + tagNameSpace = 0x40, // search ImportC tag symbol table + ignoreVisibility = 0x80, // also find private and package protected symbols }; struct FieldState @@ -227,7 +228,6 @@ public: virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); - virtual void importAll(Scope *sc); virtual bool overloadInsert(Dsymbol *s); virtual uinteger_t size(const Loc &loc); virtual bool isforwardRef(); @@ -246,8 +246,7 @@ public: virtual bool needThis(); // need a 'this' pointer? virtual Visibility visible(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual bool oneMember(Dsymbol **ps, Identifier *ident); - virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); + virtual bool oneMember(Dsymbol *&ps, Identifier *ident); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { } @@ -336,7 +335,7 @@ private: public: ScopeDsymbol *syntaxCopy(Dsymbol *s) override; virtual void importScope(Dsymbol *s, Visibility visibility); - virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0); + virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); bool isforwardRef() override final; static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2); const char *kind() const override; @@ -427,6 +426,8 @@ public: }; void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds); -Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); +Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly); bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc); void setScope(Dsymbol *d, Scope *sc); +void importAll(Dsymbol *d, Scope *sc); +void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 060abfe..33a397a 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2,7 +2,7 @@ * Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers * or function bodies. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d) @@ -21,28 +21,27 @@ import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; import dmd.attrib; -import dmd.blockexit; import dmd.clone; import dmd.cond; -import dmd.compiler; import dmd.dcast; import dmd.dclass; import dmd.declaration; import dmd.denum; import dmd.dimport; import dmd.dinterpret; -import dmd.dmangle; import dmd.dmodule; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.dversion; +import dmd.enumsem; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -54,7 +53,6 @@ import dmd.hdrgen; import dmd.location; import dmd.mtype; import dmd.mustuse; -import dmd.nogc; import dmd.nspace; import dmd.objc; import dmd.opover; @@ -65,17 +63,16 @@ import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; import dmd.rootobject; -import dmd.root.utf; import dmd.semantic2; import dmd.semantic3; import dmd.sideeffect; -import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utils; import dmd.statement; import dmd.target; import dmd.templateparamsem; +import dmd.templatesem; import dmd.typesem; import dmd.visitor; @@ -85,48 +82,6 @@ else version = MARS; enum LOG = false; -package uint setMangleOverride(Dsymbol s, const(char)[] sym) -{ - if (s.isFuncDeclaration() || s.isVarDeclaration()) - { - s.isDeclaration().mangleOverride = sym; - return 1; - } - - if (auto ad = s.isAttribDeclaration()) - { - uint nestedCount = 0; - - ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); - - return nestedCount; - } - return 0; -} - -/** - * Apply pragma printf/scanf to FuncDeclarations under `s`, - * poking through attribute declarations such as `extern(C)` - * but not through aggregates or function bodies. - * - * Params: - * s = symbol to apply - * printf = `true` for printf, `false` for scanf - */ -private void setPragmaPrintf(Dsymbol s, bool printf) -{ - if (auto fd = s.isFuncDeclaration()) - { - fd.printf = printf; - fd.scanf = !printf; - } - - if (auto ad = s.isAttribDeclaration()) - { - ad.include(null).foreachDsymbol( (s) { setPragmaPrintf(s, printf); } ); - } -} - /************************************* * Does semantic analysis on the public face of declarations. */ @@ -246,6 +201,20 @@ bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc) return true; } +/********************************* + * Check type to see if it is based on a deprecated symbol. + */ +private void checkDeprecated(Type type, const ref Loc loc, Scope* sc) +{ + if (Dsymbol s = type.toDsymbol(sc)) + { + s.checkDeprecated(loc, sc); + } + + if (auto tn = type.nextOf()) + tn.checkDeprecated(loc, sc); +} + // Returns true if a contract can appear without a function body. package bool allowsContractWithoutBody(FuncDeclaration funcdecl) { @@ -304,6 +273,137 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem return false; } +/************************************* + * Find the `alias this` symbol of e's type. + * Params: + * sc = context + * e = expression forming the `this` + * gag = do not print errors, return `null` instead + * findOnly = don't do further processing like resolving properties, + * i.e. just return plain dotExp() result. + * Returns: + * Expression that is `e.aliasthis` + */ +Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) +{ + import dmd.typesem : dotExp; + for (AggregateDeclaration ad = isAggregate(e.type); ad;) + { + if (ad.aliasthis) + { + Loc loc = e.loc; + Type tthis = (e.op == EXP.type ? e.type : null); + const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); + uint olderrors = gag ? global.startGagging() : 0; + e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); + if (!e || findOnly) + return gag && global.endGagging(olderrors) ? null : e; + + if (tthis && ad.aliasthis.sym.needThis()) + { + if (auto ve = e.isVarExp()) + { + if (auto fd = ve.var.isFuncDeclaration()) + { + // https://issues.dlang.org/show_bug.cgi?id=13009 + // Support better match for the overloaded alias this. + bool hasOverloads; + if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) + { + if (!hasOverloads) + fd = f; // use exact match + e = new VarExp(loc, fd, hasOverloads); + e.type = f.type; + e = new CallExp(loc, e); + goto L1; + } + } + } + /* non-@property function is not called inside typeof(), + * so resolve it ahead. + */ + { + int save = sc.intypeof; + sc.intypeof = 1; // bypass "need this" error check + e = resolveProperties(sc, e); + sc.intypeof = save; + } + L1: + e = new TypeExp(loc, new TypeTypeof(loc, e)); + e = e.expressionSemantic(sc); + } + e = resolveProperties(sc, e); + if (!gag) + ad.aliasthis.checkDeprecatedAliasThis(loc, sc); + else if (global.endGagging(olderrors)) + e = null; + } + + import dmd.dclass : ClassDeclaration; + auto cd = ad.isClassDeclaration(); + if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) + { + ad = cd.baseClass; + continue; + } + break; + } + return e; +} + +/** + * Check if an `alias this` is deprecated + * + * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to + * check if `expression` uses a deprecated `aliasthis`, but this calls + * `toPrettyChars` which lead to the following message: + * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" + * + * Params: + * at = The `AliasThis` object to check + * loc = `Loc` of the expression triggering the access to `at` + * sc = `Scope` of the expression + * (deprecations do not trigger in deprecated scopes) + * + * Returns: + * Whether the alias this was reported as deprecated. + */ +private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) +{ + if (global.params.useDeprecated != DiagnosticReporting.off + && at.isDeprecated() && !sc.isDeprecated()) + { + const(char)* message = null; + for (Dsymbol p = at; p; p = p.parent) + { + message = p.depdecl ? p.depdecl.getMessage() : null; + if (message) + break; + } + if (message) + deprecation(loc, "`alias %s this` is deprecated - %s", + at.sym.toChars(), message); + else + deprecation(loc, "`alias %s this` is deprecated", + at.sym.toChars()); + + if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) + ti.printInstantiationTrace(Classification.deprecation); + + return true; + } + return false; +} + +// Save the scope and defer semantic analysis on the Dsymbol. +void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope *scx) +{ + s._scope = scx ? scx : sc.copy(); + s._scope.setNoFree(); + Module.addDeferredSemantic(s); +} + + private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; @@ -314,14 +414,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor this.sc = sc; } - // Save the scope and defer semantic analysis on the Dsymbol. - private void deferDsymbolSemantic(Dsymbol s, Scope *scx) - { - s._scope = scx ? scx : sc.copy(); - s._scope.setNoFree(); - Module.addDeferredSemantic(s); - } - override void visit(Dsymbol dsym) { .error(dsym.loc, "%s `%s` %p has no semantic routine", dsym.kind, dsym.toPrettyChars, dsym); @@ -359,7 +451,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Dsymbol s = ad.search(dsym.loc, dsym.ident); if (!s) { - s = sc.search(dsym.loc, dsym.ident, null); + Dsymbol pscopesym; + s = sc.search(dsym.loc, dsym.ident, pscopesym); if (s) error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); else @@ -449,7 +542,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null"); printf(" stc = x%llx\n", dsym.storage_class); printf(" storage_class = x%llx\n", dsym.storage_class); - printf("linkage = %d\n", dsym.linkage); + printf("linkage = %d\n", dsym._linkage); //if (strcmp(toChars(), "mul") == 0) assert(0); } //if (semanticRun > PASS.initial) @@ -810,7 +903,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // At this point we can add `scope` to the STC instead of `in`, // because we are never going to use this variable's STC for user messages - if (dsym.storage_class & STC.in_ && global.params.previewIn) + if (dsym.storage_class & STC.constscoperef) dsym.storage_class |= STC.scope_; if (dsym.storage_class & STC.scope_) @@ -1206,9 +1299,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); import dmd.semantic2 : lowerStaticAAs; lowerStaticAAs(dsym, sc); - const init_err = dsym._init.isExpInitializer(); + auto init_err = dsym._init.isExpInitializer(); if (init_err && init_err.exp.op == EXP.showCtfeContext) { + init_err.exp = ErrorExp.get(); errorSupplemental(dsym.loc, "compile time context created here"); } } @@ -1494,7 +1588,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { AliasDeclaration ad = imp.aliasdecls[i]; //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope); - Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports); + Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports); if (sym) { import dmd.access : symbolIsVisible; @@ -1660,311 +1754,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(PragmaDeclaration pd) { - StringExp verifyMangleString(ref Expression e) - { - auto se = semanticString(sc, e, "mangled name"); - if (!se) - return null; - e = se; - if (!se.len) - { - .error(pd.loc, "%s `%s` - zero-length string not allowed for mangled name", pd.kind, pd.toPrettyChars); - return null; - } - if (se.sz != 1) - { - .error(pd.loc, "%s `%s` - mangled name characters can only be of type `char`", pd.kind, pd.toPrettyChars); - return null; - } - version (all) - { - /* Note: D language specification should not have any assumption about backend - * implementation. Ideally pragma(mangle) can accept a string of any content. - * - * Therefore, this validation is compiler implementation specific. - */ - auto slice = se.peekString(); - for (size_t i = 0; i < se.len;) - { - dchar c = slice[i]; - if (c < 0x80) - { - if (c.isValidMangling) - { - ++i; - continue; - } - else - { - .error(pd.loc, "%s `%s` char 0x%02x not allowed in mangled name", pd.kind, pd.toPrettyChars, c); - break; - } - } - if (const msg = utf_decodeChar(slice, i, c)) - { - .error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr); - break; - } - if (!isUniAlpha(c)) - { - .error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c); - break; - } - } - } - return se; - } - void declarations() - { - if (!pd.decl) - return; - - Scope* sc2 = pd.newScope(sc); - scope(exit) - if (sc2 != sc) - sc2.pop(); - - foreach (s; (*pd.decl)[]) - { - if (pd.ident == Id.printf || pd.ident == Id.scanf) - { - s.setPragmaPrintf(pd.ident == Id.printf); - s.dsymbolSemantic(sc2); - continue; - } - - s.dsymbolSemantic(sc2); - if (pd.ident != Id.mangle) - continue; - assert(pd.args); - if (auto ad = s.isAggregateDeclaration()) - { - Expression e = (*pd.args)[0]; - sc2 = sc2.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc2, e); - sc2 = sc2.endCTFE(); - AggregateDeclaration agg; - if (auto tc = e.type.isTypeClass()) - agg = tc.sym; - else if (auto ts = e.type.isTypeStruct()) - agg = ts.sym; - ad.pMangleOverride = new MangleOverride; - void setString(ref Expression e) - { - if (auto se = verifyMangleString(e)) - { - const name = (cast(const(char)[])se.peekData()).xarraydup; - ad.pMangleOverride.id = Identifier.idPool(name); - e = se; - } - else - error(e.loc, "must be a string"); - } - if (agg) - { - ad.pMangleOverride.agg = agg; - if (pd.args.length == 2) - { - setString((*pd.args)[1]); - } - else - ad.pMangleOverride.id = agg.ident; - } - else - setString((*pd.args)[0]); - } - else if (auto td = s.isTemplateDeclaration()) - { - .error(pd.loc, "%s `%s` cannot apply to a template declaration", pd.kind, pd.toPrettyChars); - errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`"); - } - else if (auto se = verifyMangleString((*pd.args)[0])) - { - const name = (cast(const(char)[])se.peekData()).xarraydup; - uint cnt = setMangleOverride(s, name); - if (cnt > 1) - .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); - } - } - } - - void noDeclarations() - { - if (pd.decl) - { - .error(pd.loc, "%s `%s` is missing a terminating `;`", pd.kind, pd.toPrettyChars); - declarations(); - // do them anyway, to avoid segfaults. - } - } - - // Should be merged with PragmaStatement - //printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars()); - if (target.supportsLinkerDirective()) - { - if (pd.ident == Id.linkerDirective) - { - if (!pd.args || pd.args.length != 1) - .error(pd.loc, "%s `%s` one string argument expected for pragma(linkerDirective)", pd.kind, pd.toPrettyChars); - else - { - auto se = semanticString(sc, (*pd.args)[0], "linker directive"); - if (!se) - return noDeclarations(); - (*pd.args)[0] = se; - if (global.params.v.verbose) - message("linkopt %.*s", cast(int)se.len, se.peekString().ptr); - } - return noDeclarations(); - } - } - if (pd.ident == Id.msg) - { - if (!pd.args) - return noDeclarations(); - - if (!pragmaMsgSemantic(pd.loc, sc, pd.args)) - return; - - return noDeclarations(); - } - else if (pd.ident == Id.lib) - { - if (!pd.args || pd.args.length != 1) - .error(pd.loc, "%s `%s` string expected for library name", pd.kind, pd.toPrettyChars); - else - { - auto se = semanticString(sc, (*pd.args)[0], "library name"); - if (!se) - return noDeclarations(); - (*pd.args)[0] = se; - - auto name = se.peekString().xarraydup; - if (global.params.v.verbose) - message("library %s", name.ptr); - if (global.params.moduleDeps.buffer && !global.params.moduleDeps.name) - { - OutBuffer* ob = global.params.moduleDeps.buffer; - Module imod = sc._module; - ob.writestring("depsLib "); - ob.writestring(imod.toPrettyChars()); - ob.writestring(" ("); - escapePath(ob, imod.srcfile.toChars()); - ob.writestring(") : "); - ob.writestring(name); - ob.writenl(); - } - mem.xfree(name.ptr); - } - return noDeclarations(); - } - else if (pd.ident == Id.startaddress) - { - pragmaStartAddressSemantic(pd.loc, sc, pd.args); - return noDeclarations(); - } - else if (pd.ident == Id.Pinline) - { - // this pragma now gets evaluated on demand in function semantic - - return declarations(); - } - else if (pd.ident == Id.mangle) - { - if (!pd.args) - pd.args = new Expressions(); - if (pd.args.length == 0 || pd.args.length > 2) - { - .error(pd.loc, pd.args.length == 0 ? "%s `%s` - string expected for mangled name" - : "%s `%s` expected 1 or 2 arguments", pd.kind, pd.toPrettyChars); - pd.args.setDim(1); - (*pd.args)[0] = ErrorExp.get(); // error recovery - } - return declarations(); - } - else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) - { - if (pd.args && pd.args.length != 0) - .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); - else - { - immutable isCtor = pd.ident == Id.crt_constructor; - - static uint recurse(Dsymbol s, bool isCtor) - { - if (auto ad = s.isAttribDeclaration()) - { - uint nestedCount; - auto decls = ad.include(null); - if (decls) - { - for (size_t i = 0; i < decls.length; ++i) - nestedCount += recurse((*decls)[i], isCtor); - } - return nestedCount; - } - else if (auto f = s.isFuncDeclaration()) - { - if (isCtor) - f.isCrtCtor = true; - else - f.isCrtDtor = true; - - return 1; - } - else - return 0; - assert(0); - } - - if (recurse(pd, isCtor) > 1) - .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); - } - return declarations(); - } - else if (pd.ident == Id.printf || pd.ident == Id.scanf) - { - if (pd.args && pd.args.length != 0) - .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); - return declarations(); - } - else if (!global.params.ignoreUnsupportedPragmas) - { - error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); - return declarations(); - } - - if (!global.params.v.verbose) - return declarations(); - - /* Print unrecognized pragmas - */ - OutBuffer buf; - buf.writestring(pd.ident.toString()); - if (pd.args) - { - const errors_save = global.startGagging(); - for (size_t i = 0; i < pd.args.length; i++) - { - Expression e = (*pd.args)[i]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - if (i == 0) - buf.writestring(" ("); - else - buf.writeByte(','); - buf.writestring(e.toChars()); - } - if (pd.args.length) - buf.writeByte(')'); - global.endGagging(errors_save); - } - message("pragma %s", buf.peekChars()); - return declarations(); + import dmd.pragmasem : pragmaDeclSemantic; + pragmaDeclSemantic(pd, sc); } override void visit(StaticIfDeclaration sid) @@ -2164,684 +1955,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(EnumDeclaration ed) { - //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); - //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); - if (ed.semanticRun >= PASS.semanticdone) - return; // semantic() already completed - if (ed.semanticRun == PASS.semantic) - { - assert(ed.memtype); - error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); - ed.errors = true; - ed.semanticRun = PASS.semanticdone; - return; - } - Scope* scx = null; - if (ed._scope) - { - sc = ed._scope; - scx = ed._scope; // save so we don't make redundant copies - ed._scope = null; - } - - if (!sc) - return; - - ed.parent = sc.parent; - ed.type = ed.type.typeSemantic(ed.loc, sc); - - ed.visibility = sc.visibility; - if (sc.stc & STC.deprecated_) - ed.isdeprecated = true; - ed.userAttribDecl = sc.userAttribDecl; - ed.cppnamespace = sc.namespace; - - ed.semanticRun = PASS.semantic; - UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); - checkMustUseReserved(ed); - - if (!ed.members && !ed.memtype) // enum ident; - { - ed.semanticRun = PASS.semanticdone; - return; - } - - if (!ed.symtab) - ed.symtab = new DsymbolTable(); - - /* The separate, and distinct, cases are: - * 1. enum { ... } - * 2. enum : memtype { ... } - * 3. enum ident { ... } - * 4. enum ident : memtype { ... } - * 5. enum ident : memtype; - * 6. enum ident; - */ - - if (ed.memtype) - { - ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); - - /* Check to see if memtype is forward referenced - */ - if (auto te = ed.memtype.isTypeEnum()) - { - auto sym = te.toDsymbol(sc).isEnumDeclaration(); - // Special enums like __c_[u]long[long] are fine to forward reference - // see https://issues.dlang.org/show_bug.cgi?id=20599 - if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) - { - // memtype is forward referenced, so try again later - deferDsymbolSemantic(ed, scx); - //printf("\tdeferring %s\n", toChars()); - ed.semanticRun = PASS.initial; - return; - } - else - // Ensure that semantic is run to detect. e.g. invalid forward references - sym.dsymbolSemantic(sc); - } - if (ed.memtype.ty == Tvoid) - { - .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars); - ed.memtype = Type.terror; - } - if (ed.memtype.ty == Terror) - { - ed.errors = true; - // poison all the members - ed.members.foreachDsymbol( (s) { s.errors = true; } ); - ed.semanticRun = PASS.semanticdone; - return; - } - } - - if (!ed.members) // enum ident : memtype; - { - ed.semanticRun = PASS.semanticdone; - return; - } - - if (ed.members.length == 0) - { - .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars()); - ed.errors = true; - ed.semanticRun = PASS.semanticdone; - return; - } - - if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done - ed.semanticRun = PASS.semanticdone; - - version (none) - { - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sc.stc & STC.scope_) - deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); - } - - Scope* sce; - if (ed.isAnonymous()) - sce = sc; - else - { - sce = sc.push(ed); - sce.parent = ed; - } - sce = sce.startCTFE(); - sce.setNoFree(); // needed for getMaxMinValue() - - /* Each enum member gets the sce scope - */ - ed.members.foreachDsymbol( (s) - { - EnumMember em = s.isEnumMember(); - if (em) - em._scope = sce; - }); - - /* addMember() is not called when the EnumDeclaration appears as a function statement, - * so we have to do what addMember() does and install the enum members in the right symbol - * table - */ - addEnumMembersToSymtab(ed, sc, sc.getScopesym()); - - if (sc.flags & SCOPE.Cfile) - { - /* C11 6.7.2.2 - */ - Type commonType = ed.memtype; - if (!commonType) - commonType = Type.tint32; - ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 - - // C11 6.7.2.2-2 value must be representable as an int. - // The sizemask represents all values that int will fit into, - // from 0..uint.max. We want to cover int.min..uint.max. - IntRange ir = IntRange.fromType(commonType); - - void emSemantic(EnumMember em, ref ulong nextValue) - { - static void errorReturn(EnumMember em) - { - em.value = ErrorExp.get(); - em.errors = true; - em.semanticRun = PASS.semanticdone; - } - - em.semanticRun = PASS.semantic; - em.type = commonType; - em._linkage = LINK.c; - em.storage_class |= STC.manifest; - if (em.value) - { - Expression e = em.value; - assert(e.dyncast() == DYNCAST.expression); - - /* To merge the type of e with commonType, add 0 of type commonType - */ - if (!ed.memtype) - e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); - - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.integralPromotions(sc); - e = e.ctfeInterpret(); - if (e.op == EXP.error) - return errorReturn(em); - auto ie = e.isIntegerExp(); - if (!ie) - { - // C11 6.7.2.2-2 - .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars()); - return errorReturn(em); - } - if (ed.memtype && !ir.contains(getIntRange(ie))) - { - // C11 6.7.2.2-2 - .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars()); - return errorReturn(em); - } - nextValue = ie.toInteger(); - if (!ed.memtype) - commonType = e.type; - em.value = new IntegerExp(em.loc, nextValue, commonType); - } - else - { - // C11 6.7.2.2-3 add 1 to value of previous enumeration constant - bool first = (em == (*em.ed.members)[0]); - if (!first) - { - Expression max = getProperty(commonType, null, em.loc, Id.max, 0); - if (nextValue == max.toInteger()) - { - .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars()); - return errorReturn(em); - } - nextValue += 1; - } - em.value = new IntegerExp(em.loc, nextValue, commonType); - } - em.type = commonType; - em.semanticRun = PASS.semanticdone; - } - - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - emSemantic(em, nextValue); - }); - - if (!ed.memtype) - { - // cast all members to commonType - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - { - em.type = commonType; - em.value = em.value.castTo(sc, commonType); - } - }); - } - - ed.memtype = commonType; - ed.semanticRun = PASS.semanticdone; - return; - } - - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - em.dsymbolSemantic(em._scope); - }); - //printf("defaultval = %lld\n", defaultval); - - //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); - //printf("members = %s\n", members.toChars()); + enumSemantic(sc, ed); } override void visit(EnumMember em) { - //printf("EnumMember::semantic() %s\n", em.toChars()); - - void errorReturn() - { - em.errors = true; - em.semanticRun = PASS.semanticdone; - } - - if (em.errors || em.semanticRun >= PASS.semanticdone) - return; - if (em.semanticRun == PASS.semantic) - { - .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars); - return errorReturn(); - } - assert(em.ed); - - em.ed.dsymbolSemantic(sc); - if (em.ed.errors) - return errorReturn(); - if (em.errors || em.semanticRun >= PASS.semanticdone) - return; - - if (em._scope) - sc = em._scope; - if (!sc) - return; - - em.semanticRun = PASS.semantic; - - em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); - em._linkage = LINK.d; - em.storage_class |= STC.manifest; - - // https://issues.dlang.org/show_bug.cgi?id=9701 - if (em.ed.isAnonymous()) - { - if (em.userAttribDecl) - em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; - else - em.userAttribDecl = em.ed.userAttribDecl; - } - - // Eval UDA in this same scope. Issues 19344, 20835, 21122 - if (em.userAttribDecl) - { - // Set scope but avoid extra sc.uda attachment inside setScope() - auto inneruda = em.userAttribDecl.userAttribDecl; - em.userAttribDecl.setScope(sc); - em.userAttribDecl.userAttribDecl = inneruda; - em.userAttribDecl.dsymbolSemantic(sc); - } - - // The first enum member is special - bool first = (em == (*em.ed.members)[0]); - - if (em.origType) - { - em.origType = em.origType.typeSemantic(em.loc, sc); - em.type = em.origType; - assert(em.value); // "type id;" is not a valid enum member declaration - } - - if (em.value) - { - Expression e = em.value; - assert(e.dyncast() == DYNCAST.expression); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.ctfeInterpret(); - if (e.op == EXP.error) - return errorReturn(); - if (first && !em.ed.memtype && !em.ed.isAnonymous()) - { - em.ed.memtype = e.type; - if (em.ed.memtype.ty == Terror) - { - em.ed.errors = true; - return errorReturn(); - } - if (em.ed.memtype.ty != Terror) - { - /* https://issues.dlang.org/show_bug.cgi?id=11746 - * All of named enum members should have same type - * with the first member. If the following members were referenced - * during the first member semantic, their types should be unified. - */ - em.ed.members.foreachDsymbol( (s) - { - EnumMember enm = s.isEnumMember(); - if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) - return; - - //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); - Expression ev = enm.value; - ev = ev.implicitCastTo(sc, em.ed.memtype); - ev = ev.ctfeInterpret(); - ev = ev.castTo(sc, em.ed.type); - if (ev.op == EXP.error) - em.ed.errors = true; - enm.value = ev; - }); - - if (em.ed.errors) - { - em.ed.memtype = Type.terror; - return errorReturn(); - } - } - } - - if (em.ed.memtype && !em.origType) - { - e = e.implicitCastTo(sc, em.ed.memtype); - e = e.ctfeInterpret(); - - // save origValue for better json output - em.origValue = e; - - if (!em.ed.isAnonymous()) - { - e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 - e = e.ctfeInterpret(); - } - } - else if (em.origType) - { - e = e.implicitCastTo(sc, em.origType); - e = e.ctfeInterpret(); - assert(em.ed.isAnonymous()); - - // save origValue for better json output - em.origValue = e; - } - em.value = e; - } - else if (first) - { - Type t; - if (em.ed.memtype) - t = em.ed.memtype; - else - { - t = Type.tint32; - if (!em.ed.isAnonymous()) - em.ed.memtype = t; - } - const errors = global.startGagging(); - Expression e = new IntegerExp(em.loc, 0, t); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - error(em.loc, "cannot generate 0 value of type `%s` for `%s`", - t.toChars(), em.toChars()); - } - // save origValue for better json output - em.origValue = e; - - if (!em.ed.isAnonymous()) - { - e = e.castTo(sc, em.ed.type); - e = e.ctfeInterpret(); - } - em.value = e; - } - else - { - /* Find the previous enum member, - * and set this to be the previous value + 1 - */ - EnumMember emprev = null; - em.ed.members.foreachDsymbol( (s) - { - if (auto enm = s.isEnumMember()) - { - if (enm == em) - return 1; // found - emprev = enm; - } - return 0; // continue - }); - - assert(emprev); - if (emprev.semanticRun < PASS.semanticdone) // if forward reference - emprev.dsymbolSemantic(emprev._scope); // resolve it - if (emprev.errors) - return errorReturn(); - - auto errors = global.startGagging(); - Expression eprev = emprev.value; - assert(eprev); - // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 - Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) - ? em.ed.memtype - : eprev.type; - /* - https://issues.dlang.org/show_bug.cgi?id=20777 - Previously this used getProperty, which doesn't consider anything user defined, - this construct does do that and thus fixes the bug. - */ - Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); - emax = emax.expressionSemantic(sc); - emax = emax.ctfeInterpret(); - - // check that (eprev != emax) - Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); - e = e.expressionSemantic(sc); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - // display an introductory error before showing what actually failed - error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); - // rerun to show errors - Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); - e2 = e2.expressionSemantic(sc); - e2 = e2.ctfeInterpret(); - e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); - e2 = e2.expressionSemantic(sc); - e2 = e2.ctfeInterpret(); - } - // now any errors are for generating a value - if (e.toInteger()) - { - auto mt = em.ed.memtype; - if (!mt) - mt = eprev.type; - .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, - emprev.ed.toChars(), emprev.toChars(), mt.toChars()); - return errorReturn(); - } - errors = global.startGagging(); - // Now set e to (eprev + 1) - e = new AddExp(em.loc, eprev, IntegerExp.literal!1); - e = e.expressionSemantic(sc); - e = e.castTo(sc, eprev.type); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); - // rerun to show errors - Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); - e2 = e2.expressionSemantic(sc); - e2 = e2.castTo(sc, eprev.type); - e2 = e2.ctfeInterpret(); - } - // save origValue (without cast) for better json output - if (e.op != EXP.error) // avoid duplicate diagnostics - { - assert(emprev.origValue); - em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); - em.origValue = em.origValue.expressionSemantic(sc); - em.origValue = em.origValue.ctfeInterpret(); - } - - if (e.op == EXP.error) - return errorReturn(); - if (e.type.isfloating()) - { - // Check that e != eprev (not always true for floats) - Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); - etest = etest.expressionSemantic(sc); - etest = etest.ctfeInterpret(); - if (etest.toInteger()) - { - .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars); - return errorReturn(); - } - } - em.value = e; - } - if (!em.origType) - em.type = em.value.type; - - assert(em.origValue); - em.semanticRun = PASS.semanticdone; + enumMemberSemantic(sc, em); } override void visit(TemplateDeclaration tempdecl) { - static if (LOG) - { - printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); - printf("sc.stc = %llx\n", sc.stc); - printf("sc.module = %s\n", sc._module.toChars()); - } - if (tempdecl.semanticRun != PASS.initial) - return; // semantic() already run - - if (tempdecl._scope) - { - sc = tempdecl._scope; - tempdecl._scope = null; - } - if (!sc) - return; - - // Remember templates defined in module object that we need to know about - if (sc._module && sc._module.ident == Id.object) - { - if (tempdecl.ident == Id.RTInfo) - Type.rtinfo = tempdecl; - } - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - if (!tempdecl._scope) - { - tempdecl._scope = sc.copy(); - tempdecl._scope.setNoFree(); - } - - tempdecl.semanticRun = PASS.semantic; - - tempdecl.parent = sc.parent; - tempdecl.visibility = sc.visibility; - tempdecl.userAttribDecl = sc.userAttribDecl; - tempdecl.cppnamespace = sc.namespace; - tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_); - tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_); - - UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage); - - if (!tempdecl.isstatic) - { - if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration()) - ad.makeNested(); - } - - // Set up scope for parameters - auto paramsym = new ScopeDsymbol(); - paramsym.parent = tempdecl.parent; - Scope* paramscope = sc.push(paramsym); - paramscope.stc = 0; - - if (global.params.ddoc.doOutput) - { - tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.length); - for (size_t i = 0; i < tempdecl.parameters.length; i++) - { - TemplateParameter tp = (*tempdecl.parameters)[i]; - (*tempdecl.origParameters)[i] = tp.syntaxCopy(); - } - } - - for (size_t i = 0; i < tempdecl.parameters.length; i++) - { - TemplateParameter tp = (*tempdecl.parameters)[i]; - if (!tp.declareParameter(paramscope)) - { - error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars()); - tempdecl.errors = true; - } - if (!tp.tpsemantic(paramscope, tempdecl.parameters)) - { - tempdecl.errors = true; - } - if (i + 1 != tempdecl.parameters.length && tp.isTemplateTupleParameter()) - { - .error(tempdecl.loc, "%s `%s` template sequence parameter must be the last one", tempdecl.kind, tempdecl.toPrettyChars); - tempdecl.errors = true; - } - } - - /* Calculate TemplateParameter.dependent - */ - TemplateParameters tparams = TemplateParameters(1); - for (size_t i = 0; i < tempdecl.parameters.length; i++) - { - TemplateParameter tp = (*tempdecl.parameters)[i]; - tparams[0] = tp; - - for (size_t j = 0; j < tempdecl.parameters.length; j++) - { - // Skip cases like: X(T : T) - if (i == j) - continue; - - if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter()) - { - if (reliesOnTident(ttp.specType, &tparams)) - tp.dependent = true; - } - else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter()) - { - if (reliesOnTident(tap.specType, &tparams) || - reliesOnTident(isType(tap.specAlias), &tparams)) - { - tp.dependent = true; - } - } - } - } - - paramscope.pop(); - - // Compute again - tempdecl.onemember = null; - if (tempdecl.members) - { - Dsymbol s; - if (Dsymbol.oneMembers(tempdecl.members, &s, tempdecl.ident) && s) - { - tempdecl.onemember = s; - s.parent = tempdecl; - } - } - - /* BUG: should check: - * 1. template functions must not introduce virtual functions, as they - * cannot be accomodated in the vtbl[] - * 2. templates cannot introduce non-static data members (i.e. fields) - * as they would change the instance size of the aggregate. - */ - - tempdecl.semanticRun = PASS.semanticdone; + templateDeclarationSemantic(sc, tempdecl); } override void visit(TemplateInstance ti) @@ -2889,7 +2013,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tm.semanticRun == PASS.initial) // forward reference had occurred { //printf("forward reference - deferring\n"); - return deferDsymbolSemantic(tm, scx); + return deferDsymbolSemantic(sc, tm, scx); } tm.inst = tm; @@ -3185,974 +2309,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ns.semanticRun = PASS.semanticdone; } - void funcDeclarationSemantic(FuncDeclaration funcdecl) - { - version (none) - { - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); - if (funcdecl.isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : ""); - printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); - } - - if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration()) - { - /* Member functions that have return types that are - * forward references can have semantic() run more than - * once on them. - * See test\interface2.d, test20 - */ - return; - } - - if (funcdecl.semanticRun >= PASS.semanticdone) - return; - assert(funcdecl.semanticRun <= PASS.semantic); - funcdecl.semanticRun = PASS.semantic; - - if (funcdecl._scope) - { - sc = funcdecl._scope; - funcdecl._scope = null; - } - - if (!sc || funcdecl.errors) - return; - - funcdecl.cppnamespace = sc.namespace; - funcdecl.parent = sc.parent; - Dsymbol parent = funcdecl.toParent(); - - funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function - - funcdecl.storage_class |= sc.stc & ~STC.ref_; - AggregateDeclaration ad = funcdecl.isThis(); - // Don't nest structs b/c of generated methods which should not access the outer scopes. - // https://issues.dlang.org/show_bug.cgi?id=16627 - if (ad && !funcdecl.isGenerated()) - { - funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); - ad.makeNested(); - } - if (sc.func) - funcdecl.storage_class |= sc.func.storage_class & STC.disable; - // Remove prefix storage classes silently. - if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested())) - funcdecl.storage_class &= ~STC.TYPECTOR; - - //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); - - if (sc.flags & SCOPE.compile) - funcdecl.skipCodegen = true; - - funcdecl._linkage = sc.linkage; - if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration()) - funcdecl._linkage = LINK.d; // so they are uniquely mangled - - if (auto fld = funcdecl.isFuncLiteralDeclaration()) - { - if (fld.treq) - { - Type treq = fld.treq; - assert(treq.nextOf().ty == Tfunction); - if (treq.ty == Tdelegate) - fld.tok = TOK.delegate_; - else if (treq.isPtrToFunction()) - fld.tok = TOK.function_; - else - assert(0); - funcdecl._linkage = treq.nextOf().toTypeFunction().linkage; - } - } - - // evaluate pragma(inline) - if (auto pragmadecl = sc.inlining) - funcdecl.inlining = evalPragmaInline(pragmadecl.loc, sc, pragmadecl.args); - - funcdecl.visibility = sc.visibility; - funcdecl.userAttribDecl = sc.userAttribDecl; - UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage); - checkMustUseReserved(funcdecl); - - if (!funcdecl.originalType) - funcdecl.originalType = funcdecl.type.syntaxCopy(); - - static TypeFunction getFunctionType(FuncDeclaration fd) - { - if (auto tf = fd.type.isTypeFunction()) - return tf; - - if (!fd.type.isTypeError()) - { - .error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars()); - fd.type = Type.terror; - } - fd.errors = true; - return null; - } - - if (sc.flags & SCOPE.Cfile) - { - /* C11 allows a function to be declared with a typedef, D does not. - */ - if (auto ti = funcdecl.type.isTypeIdentifier()) - { - auto tj = ti.typeSemantic(funcdecl.loc, sc); - if (auto tjf = tj.isTypeFunction()) - { - /* Copy the type instead of just pointing to it, - * as we don't merge function types - */ - auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); - funcdecl.type = tjf2; - funcdecl.originalType = tjf2; - } - } - } - - if (!getFunctionType(funcdecl)) - return; - - if (!funcdecl.type.deco) - { - sc = sc.push(); - sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type - - TypeFunction tf = funcdecl.type.toTypeFunction(); - if (sc.func) - { - /* If the nesting parent is pure without inference, - * then this function defaults to pure too. - * - * auto foo() pure { - * auto bar() {} // become a weak purity function - * class C { // nested class - * auto baz() {} // become a weak purity function - * } - * - * static auto boo() {} // typed as impure - * // Even though, boo cannot call any impure functions. - * // See also Expression::checkPurity(). - * } - */ - if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis())) - { - FuncDeclaration fd = null; - for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2()) - { - if (AggregateDeclaration adx = p.isAggregateDeclaration()) - { - if (adx.isNested()) - continue; - break; - } - if ((fd = p.isFuncDeclaration()) !is null) - break; - } - - /* If the parent's purity is inferred, then this function's purity needs - * to be inferred first. - */ - if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated()) - { - tf.purity = PURE.fwdref; // default to pure - } - } - } - - if (tf.isref) - sc.stc |= STC.ref_; - if (tf.isScopeQual) - sc.stc |= STC.scope_; - if (tf.isnothrow) - sc.stc |= STC.nothrow_; - if (tf.isnogc) - sc.stc |= STC.nogc; - if (tf.isproperty) - sc.stc |= STC.property; - if (tf.purity == PURE.fwdref) - sc.stc |= STC.pure_; - - if (tf.trust != TRUST.default_) - { - sc.stc &= ~STC.safeGroup; - if (tf.trust == TRUST.safe) - sc.stc |= STC.safe; - else if (tf.trust == TRUST.system) - sc.stc |= STC.system; - else if (tf.trust == TRUST.trusted) - sc.stc |= STC.trusted; - } - - if (funcdecl.isCtorDeclaration()) - { - tf.isctor = true; - Type tret = ad.handleType(); - assert(tret); - tret = tret.addStorageClass(funcdecl.storage_class | sc.stc); - tret = tret.addMod(funcdecl.type.mod); - tf.next = tret; - if (ad.isStructDeclaration()) - sc.stc |= STC.ref_; - } - - // 'return' on a non-static class member function implies 'scope' as well - if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_)) - sc.stc |= STC.scope_; - - // If 'this' has no pointers, remove 'scope' as it has no meaning - // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`, - // but existing code relies on `hasPointers()` being called here to resolve forward references: - // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 - if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) - { - sc.stc &= ~STC.scope_; - tf.isScopeQual = false; - if (tf.isreturnscope) - { - sc.stc &= ~(STC.return_ | STC.returnScope); - tf.isreturn = false; - tf.isreturnscope = false; - } - } - - sc.linkage = funcdecl._linkage; - - if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) - { - import core.bitop : popcnt; - auto mods = MODtoChars(tf.mod); - .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods); - if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1) - .errorSupplemental(funcdecl.loc, - "did you mean to use `%s(%s)` as the return type?", mods, tf.next.toChars()); - - tf.mod = 0; // remove qualifiers - } - - /* Apply const, immutable, wild and shared storage class - * to the function type. Do this before type semantic. - */ - auto stc = funcdecl.storage_class; - if (funcdecl.type.isImmutable()) - stc |= STC.immutable_; - if (funcdecl.type.isConst()) - stc |= STC.const_; - if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_) - stc |= STC.shared_; - if (funcdecl.type.isWild()) - stc |= STC.wild; - funcdecl.type = funcdecl.type.addSTC(stc); - - funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); - sc = sc.pop(); - } - - auto f = getFunctionType(funcdecl); - if (!f) - return; // funcdecl's type is not a function - - { - // Merge back function attributes into 'originalType'. - // It's used for mangling, ddoc, and json output. - TypeFunction tfo = funcdecl.originalType.toTypeFunction(); - tfo.mod = f.mod; - tfo.isScopeQual = f.isScopeQual; - tfo.isreturninferred = f.isreturninferred; - tfo.isscopeinferred = f.isscopeinferred; - tfo.isref = f.isref; - tfo.isnothrow = f.isnothrow; - tfo.isnogc = f.isnogc; - tfo.isproperty = f.isproperty; - tfo.purity = f.purity; - tfo.trust = f.trust; - - funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); - } - - // check pragma(crt_constructor) signature - if (funcdecl.isCrtCtor || funcdecl.isCrtDtor) - { - const idStr = funcdecl.isCrtCtor ? "crt_constructor" : "crt_destructor"; - if (f.nextOf().ty != Tvoid) - .error(funcdecl.loc, "%s `%s` must return `void` for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); - if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) - .error(funcdecl.loc, "%s `%s` must be `extern(C)` for `pragma(%s)` when taking parameters", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); - if (funcdecl.isThis()) - .error(funcdecl.loc, "%s `%s` cannot be a non-static member function for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); - } - - if (funcdecl.overnext && funcdecl.isCsymbol()) - { - /* C does not allow function overloading, but it does allow - * redeclarations of the same function. If .overnext points - * to a redeclaration, ok. Error if it is an overload. - */ - auto fnext = funcdecl.overnext.isFuncDeclaration(); - funcDeclarationSemantic(fnext); - auto fn = fnext.type.isTypeFunction(); - if (!fn || !cFuncEquivalence(f, fn)) - { - .error(funcdecl.loc, "%s `%s` redeclaration with different type", funcdecl.kind, funcdecl.toPrettyChars); - //printf("t1: %s\n", f.toChars()); - //printf("t2: %s\n", fn.toChars()); - } - funcdecl.overnext = null; // don't overload the redeclarations - } - - if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) - .error(funcdecl.loc, "%s `%s` storage class `auto` has no effect if return type is not inferred", funcdecl.kind, funcdecl.toPrettyChars); - - if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested()) - { - /* Non-static nested functions have a hidden 'this' pointer to which - * the 'return' applies - */ - if (sc.scopesym && sc.scopesym.isAggregateDeclaration()) - .error(funcdecl.loc, "%s `%s` `static` member has no `this` to which `return` can apply", funcdecl.kind, funcdecl.toPrettyChars); - else - error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); - } - - if (funcdecl.isAbstract() && !funcdecl.isVirtual()) - { - const(char)* sfunc; - if (funcdecl.isStatic()) - sfunc = "static"; - else if (funcdecl.visibility.kind == Visibility.Kind.private_ || funcdecl.visibility.kind == Visibility.Kind.package_) - sfunc = visibilityToChars(funcdecl.visibility.kind); - else - sfunc = "final"; - .error(funcdecl.loc, "%s `%s` `%s` functions cannot be `abstract`", funcdecl.kind, funcdecl.toPrettyChars, sfunc); - } - - if (funcdecl.isOverride() && !funcdecl.isVirtual() && !funcdecl.isFuncLiteralDeclaration()) - { - Visibility.Kind kind = funcdecl.visible().kind; - if ((kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_) && funcdecl.isMember()) - .error(funcdecl.loc, "%s `%s` `%s` method is not virtual and cannot override", funcdecl.kind, funcdecl.toPrettyChars, visibilityToChars(kind)); - else - .error(funcdecl.loc, "%s `%s` cannot override a non-virtual function", funcdecl.kind, funcdecl.toPrettyChars); - } - - if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) - .error(funcdecl.loc, "%s `%s` cannot be both `final` and `abstract`", funcdecl.kind, funcdecl.toPrettyChars); - - if (funcdecl.printf || funcdecl.scanf) - { - checkPrintfScanfSignature(funcdecl, f, sc); - } - - if (auto id = parent.isInterfaceDeclaration()) - { - funcdecl.storage_class |= STC.abstract_; - if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) - .error(funcdecl.loc, "%s `%s` constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); - if (funcdecl.fbody && funcdecl.isVirtual()) - .error(funcdecl.loc, "%s `%s` function body only allowed in `final` functions in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); - } - - if (UnionDeclaration ud = parent.isUnionDeclaration()) - { - if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) - .error(funcdecl.loc, "%s `%s` destructors, postblits and invariants are not allowed in union `%s`", funcdecl.kind, funcdecl.toPrettyChars, ud.toChars()); - } - - if (StructDeclaration sd = parent.isStructDeclaration()) - { - if (funcdecl.isCtorDeclaration()) - { - goto Ldone; - } - } - - if (ClassDeclaration cd = parent.isClassDeclaration()) - { - parent = cd = objc.getParent(funcdecl, cd); - - if (funcdecl.isCtorDeclaration()) - { - goto Ldone; - } - - if (funcdecl.storage_class & STC.abstract_) - cd.isabstract = ThreeState.yes; - - // if static function, do not put in vtbl[] - if (!funcdecl.isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - // Suppress further errors if the return type is an error - if (funcdecl.type.nextOf() == Type.terror) - goto Ldone; - - bool may_override = false; - for (size_t i = 0; i < cd.baseclasses.length; i++) - { - BaseClass* b = (*cd.baseclasses)[i]; - ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); - if (!cbd) - continue; - for (size_t j = 0; j < cbd.vtbl.length; j++) - { - FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); - if (!f2 || f2.ident != funcdecl.ident) - continue; - if (cbd.parent && cbd.parent.isTemplateInstance()) - { - if (!f2.functionSemantic()) - goto Ldone; - } - may_override = true; - } - } - if (may_override && funcdecl.type.nextOf() is null) - { - /* If same name function exists in base class but 'this' is auto return, - * cannot find index of base class's vtbl[] to override. - */ - .error(funcdecl.loc, "%s `%s` return type inference is not supported if may override base class function", funcdecl.kind, funcdecl.toPrettyChars); - } - - /* Find index of existing function in base class's vtbl[] to override - * (the index will be the same as in cd's current vtbl[]) - */ - int vi = cd.baseClass ? funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.length) : -1; - - bool doesoverride = false; - switch (vi) - { - case -1: - Lintro: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd.baseClass) - { - Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); - if (s) - { - if (auto f2 = s.isFuncDeclaration()) - { - f2 = f2.overloadExactMatch(funcdecl.type); - if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) - .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, f2.toPrettyChars()); - } - } - } - - /* These quirky conditions mimic what happens when virtual - inheritance is implemented by producing a virtual base table - with offsets to each of the virtual bases. - */ - if (target.cpp.splitVBasetable && cd.classKind == ClassKind.cpp && - cd.baseClass && cd.baseClass.vtbl.length) - { - /* if overriding an interface function, then this is not - * introducing and don't put it in the class vtbl[] - */ - funcdecl.interfaceVirtual = funcdecl.overrideInterface(); - if (funcdecl.interfaceVirtual) - { - //printf("\tinterface function %s\n", toChars()); - cd.vtblFinal.push(funcdecl); - goto Linterfaces; - } - } - - if (funcdecl.isFinalFunc()) - { - // Don't check here, as it may override an interface function - //if (isOverride()) - // error("is marked as override, but does not override any function"); - cd.vtblFinal.push(funcdecl); - } - else - { - //printf("\tintroducing function %s\n", funcdecl.toChars()); - funcdecl.isIntroducing = true; - if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) - { - /* Overloaded functions with same name are grouped and in reverse order. - * Search for first function of overload group, and insert - * funcdecl into vtbl[] immediately before it. - */ - funcdecl.vtblIndex = cast(int)cd.vtbl.length; - bool found; - foreach (const i, s; cd.vtbl) - { - if (found) - // the rest get shifted forward - ++s.isFuncDeclaration().vtblIndex; - else if (s.ident == funcdecl.ident && s.parent == parent) - { - // found first function of overload group - funcdecl.vtblIndex = cast(int)i; - found = true; - ++s.isFuncDeclaration().vtblIndex; - } - } - cd.vtbl.insert(funcdecl.vtblIndex, funcdecl); - - debug foreach (const i, s; cd.vtbl) - { - // a C++ dtor gets its vtblIndex later (and might even be added twice to the vtbl), - // e.g. when compiling druntime with a debug compiler, namely with core.stdcpp.exception. - if (auto fd = s.isFuncDeclaration()) - assert(fd.vtblIndex == i || - (cd.classKind == ClassKind.cpp && fd.isDtorDeclaration) || - funcdecl.parent.isInterfaceDeclaration); // interface functions can be in multiple vtbls - } - } - else - { - // Append to end of vtbl[] - vi = cast(int)cd.vtbl.length; - cd.vtbl.push(funcdecl); - funcdecl.vtblIndex = vi; - } - } - break; - - case -2: - // can't determine because of forward references - funcdecl.errors = true; - return; - - default: - { - if (vi >= cd.vtbl.length) - { - /* the derived class cd doesn't have its vtbl[] allocated yet. - * https://issues.dlang.org/show_bug.cgi?id=21008 - */ - .error(funcdecl.loc, "%s `%s` circular reference to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); - funcdecl.errors = true; - return; - } - FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); - FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); - // This function is covariant with fdv - - if (fdc == funcdecl) - { - doesoverride = true; - break; - } - - auto vtf = getFunctionType(fdv); - if (vtf.trust > TRUST.system && f.trust == TRUST.system) - .error(funcdecl.loc, "%s `%s` cannot override `@safe` method `%s` with a `@system` attribute", funcdecl.kind, funcdecl.toPrettyChars, - fdv.toPrettyChars); - - if (fdc.toParent() == parent) - { - //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", - // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(), - // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(), - // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars()); - - // fdc overrides fdv exactly, then this introduces new function. - if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod) - goto Lintro; - } - - if (fdv.isDeprecated && !funcdecl.isDeprecated) - deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`", - funcdecl.toPrettyChars, fdv.toPrettyChars); - - // This function overrides fdv - if (fdv.isFinalFunc()) - .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, fdv.toPrettyChars()); - - if (!funcdecl.isOverride()) - { - if (fdv.isFuture()) - { - deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars()); - // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] - goto Lintro; - } - else - { - // https://issues.dlang.org/show_bug.cgi?id=17349 - error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", - fdv.toPrettyChars(), funcdecl.toPrettyChars()); - } - } - doesoverride = true; - if (fdc.toParent() == parent) - { - // If both are mixins, or both are not, then error. - // If either is not, the one that is not overrides the other. - bool thismixin = funcdecl.parent.isClassDeclaration() !is null; - bool fdcmixin = fdc.parent.isClassDeclaration() !is null; - if (thismixin == fdcmixin) - { - .error(funcdecl.loc, "%s `%s` multiple overrides of same function", funcdecl.kind, funcdecl.toPrettyChars); - } - /* - * https://issues.dlang.org/show_bug.cgi?id=711 - * - * If an overriding method is introduced through a mixin, - * we need to update the vtbl so that both methods are - * present. - */ - else if (thismixin) - { - /* if the mixin introduced the overriding method, then reintroduce it - * in the vtbl. The initial entry for the mixined method - * will be updated at the end of the enclosing `if` block - * to point to the current (non-mixined) function. - */ - auto vitmp = cast(int)cd.vtbl.length; - cd.vtbl.push(fdc); - fdc.vtblIndex = vitmp; - } - else if (fdcmixin) - { - /* if the current overriding function is coming from a - * mixined block, then push the current function in the - * vtbl, but keep the previous (non-mixined) function as - * the overriding one. - */ - auto vitmp = cast(int)cd.vtbl.length; - cd.vtbl.push(funcdecl); - funcdecl.vtblIndex = vitmp; - break; - } - else // fdc overrides fdv - { - // this doesn't override any function - break; - } - } - cd.vtbl[vi] = funcdecl; - funcdecl.vtblIndex = vi; - - /* Remember which functions this overrides - */ - funcdecl.foverrides.push(fdv); - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv.tintro) - funcdecl.tintro = fdv.tintro; - else if (!funcdecl.type.equals(fdv.type)) - { - auto tnext = funcdecl.type.nextOf(); - if (auto handle = tnext.isClassHandle()) - { - if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) - handle.dsymbolSemantic(null); - } - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv.type.nextOf().isBaseOf(tnext, &offset)) - { - funcdecl.tintro = fdv.type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - Linterfaces: - bool foundVtblMatch = false; - - for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass) - { - foreach (b; bcd.interfaces) - { - vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length); - switch (vi) - { - case -1: - break; - - case -2: - // can't determine because of forward references - funcdecl.errors = true; - return; - - default: - { - auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; - Type ti = null; - - foundVtblMatch = true; - - /* Remember which functions this overrides - */ - funcdecl.foverrides.push(fdv); - - if (fdv.tintro) - ti = fdv.tintro; - else if (!funcdecl.type.equals(fdv.type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) - { - ti = fdv.type; - } - } - if (ti) - { - if (funcdecl.tintro) - { - if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null)) - { - .error(funcdecl.loc, "%s `%s` incompatible covariant types `%s` and `%s`", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.tintro.toChars(), ti.toChars()); - } - } - else - { - funcdecl.tintro = ti; - } - } - } - } - } - } - if (foundVtblMatch) - { - goto L2; - } - - if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override)) - { - BaseClass* bc = null; - Dsymbol s = null; - for (size_t i = 0; i < cd.baseclasses.length; i++) - { - bc = (*cd.baseclasses)[i]; - s = bc.sym.search_correct(funcdecl.ident); - if (s) - break; - } - - if (s) - { - HdrGenState hgs; - OutBuffer buf; - - auto fd = s.isFuncDeclaration(); - functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, - new Identifier(funcdecl.toPrettyChars()), &hgs, null); - const(char)* funcdeclToChars = buf.peekChars(); - - if (fd) - { - OutBuffer buf1; - - if (fd.ident == funcdecl.ident) - hgs.fullQual = true; - - // https://issues.dlang.org/show_bug.cgi?id=23745 - // If the potentially overridden function contains errors, - // inform the user to fix that one first - if (fd.errors) - { - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", - funcdecl.toChars(), fd.toPrettyChars()); - errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overridden", - fd.toPrettyChars()); - } - else - { - functionToBufferFull(cast(TypeFunction)(fd.type), buf1, - new Identifier(fd.toPrettyChars()), &hgs, null); - - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", - funcdeclToChars, buf1.peekChars()); - } - } - else - { - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", - funcdeclToChars, s.kind, s.toPrettyChars()); - errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overridden"); - } - } - else - .error(funcdecl.loc, "%s `%s` does not override any function", funcdecl.kind, funcdecl.toPrettyChars); - } - - L2: - objc.setSelector(funcdecl, sc); - objc.checkLinkage(funcdecl); - objc.addToClassMethodList(funcdecl, cd); - objc.setAsOptional(funcdecl, sc); - - /* Go through all the interface bases. - * Disallow overriding any final functions in the interface(s). - */ - foreach (b; cd.interfaces) - { - if (b.sym) - { - if (auto s = search_function(b.sym, funcdecl.ident)) - { - if (auto f2 = s.isFuncDeclaration()) - { - f2 = f2.overloadExactMatch(funcdecl.type); - if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) - .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s.%s`", funcdecl.kind, funcdecl.toPrettyChars, b.sym.toChars(), f2.toPrettyChars()); - } - } - } - } - - if (funcdecl.isOverride) - { - if (funcdecl.storage_class & STC.disable) - deprecation(funcdecl.loc, - "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class", - funcdecl.toPrettyChars); - - if (funcdecl.isDeprecated && !(funcdecl.foverrides.length && funcdecl.foverrides[0].isDeprecated)) - deprecation(funcdecl.loc, - "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class", - funcdecl.toPrettyChars); - } - - } - else if (funcdecl.isOverride() && !parent.isTemplateInstance()) - .error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars); - - if (auto ti = parent.isTemplateInstance) - { - objc.setSelector(funcdecl, sc); - objc.setAsOptional(funcdecl, sc); - } - - objc.validateSelector(funcdecl); - objc.validateOptional(funcdecl); - // Reflect this.type to f because it could be changed by findVtblIndex - f = funcdecl.type.toTypeFunction(); - - Ldone: - if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody()) - .error(funcdecl.loc, "%s `%s` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract", funcdecl.kind, funcdecl.toPrettyChars); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (funcdecl.isVirtual()) - { - if (auto ti = parent.isTemplateInstance()) - { - // Take care of nested templates - while (1) - { - TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration cd = ti.tempdecl.isClassMember(); - if (cd) - { - .error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); - } - } - } - - funcdecl.checkMain(); // Check main() parameters and return type - - /* Purity and safety can be inferred for some functions by examining - * the function body. - */ - if (funcdecl.canInferAttributes(sc)) - funcdecl.initInferAttributes(); - - funcdecl.semanticRun = PASS.semanticdone; - - /* Save scope for possible later use (if we need the - * function internals) - */ - funcdecl._scope = sc.copy(); - funcdecl._scope.setNoFree(); - - __gshared bool printedMain = false; // semantic might run more than once - if (global.params.v.verbose && !printedMain) - { - const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null; - Module mod = sc._module; - - if (type && mod) - { - printedMain = true; - auto name = mod.srcfile.toChars(); - auto path = FileName.searchPath(global.path, name, true); - message("entry %-10s\t%s", type, path ? path : name); - } - } - - if (funcdecl.fbody && sc._module.isRoot() && - (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain())) - global.hasMainFunction = true; - - if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot()) - { - // check if `_d_cmain` is defined - bool cmainTemplateExists() - { - auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null); - if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) - if (moduleSymbol.search(funcdecl.loc, Id.CMain)) - return true; - - return false; - } - - // Only mixin `_d_cmain` if it is defined - if (cmainTemplateExists()) - { - // add `mixin _d_cmain!();` to the declaring module - auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain); - auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null); - sc._module.members.push(tm); - } - } - - assert(funcdecl.type.ty != Terror || funcdecl.errors); - - // semantic for parameters' UDAs - foreach (i, param; f.parameterList) - { - if (param && param.userAttribDecl) - param.userAttribDecl.dsymbolSemantic(sc); - } - } - /// Do the semantic analysis on the external interface to the function. override void visit(FuncDeclaration funcdecl) { - funcDeclarationSemantic(funcdecl); + funcDeclarationSemantic(sc, funcdecl); } override void visit(CtorDeclaration ctd) @@ -4189,7 +2349,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc &= ~STC.static_; // not a static constructor - funcDeclarationSemantic(ctd); + funcDeclarationSemantic(sc, ctd); sc.pop(); @@ -4288,7 +2448,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc &= ~STC.static_; // not static sc.linkage = LINK.d; - funcDeclarationSemantic(pbd); + funcDeclarationSemantic(sc, pbd); sc.pop(); } @@ -4354,7 +2514,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sc.linkage != LINK.cpp) sc.linkage = LINK.d; - funcDeclarationSemantic(dd); + funcDeclarationSemantic(sc, dd); sc.pop(); } @@ -4442,7 +2602,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Just correct it sc.linkage = LINK.d; } - funcDeclarationSemantic(scd); + funcDeclarationSemantic(sc, scd); sc.linkage = save; // We're going to need ModuleInfo @@ -4454,6 +2614,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor m.needmoduleinfo = 1; //printf("module1 %s needs moduleinfo\n", m.toChars()); } + + foreachUda(scd, sc, (Expression e) { + import dmd.attrib : isEnumAttribute; + if (!isEnumAttribute(e, Id.udaStandalone)) + return 0; + + if (auto sharedCtor = scd.isSharedStaticCtorDeclaration()) + { + auto trust = sharedCtor.type.isTypeFunction().trust; + if (trust != TRUST.system && trust != TRUST.trusted) + error(e.loc, "a module constructor using `@%s` must be `@system` or `@trusted`", Id.udaStandalone.toChars()); + sharedCtor.standalone = true; + } + else + .error(e.loc, "`@%s` can only be used on shared static constructors", Id.udaStandalone.toChars()); + + return 1; + }); } override void visit(StaticDtorDeclaration sdd) @@ -4540,7 +2718,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Just correct it sc.linkage = LINK.d; } - funcDeclarationSemantic(sdd); + funcDeclarationSemantic(sc, sdd); sc.linkage = save; // We're going to need ModuleInfo @@ -4591,7 +2769,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_; sc.linkage = LINK.d; - funcDeclarationSemantic(invd); + funcDeclarationSemantic(sc, invd); sc.pop(); } @@ -4624,7 +2802,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor utd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, utd.storage_class); Scope* sc2 = sc.push(); sc2.linkage = LINK.d; - funcDeclarationSemantic(utd); + funcDeclarationSemantic(sc, utd); sc2.pop(); } @@ -4653,7 +2831,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!nd.type) nd.type = new TypeFunction(ParameterList(), Type.tvoid.pointerTo(), LINK.d, nd.storage_class); - funcDeclarationSemantic(nd); + funcDeclarationSemantic(sc, nd); } override void visit(StructDeclaration sd) @@ -4693,9 +2871,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { if (ts.sym != sd) { - auto ti = ts.sym.isInstantiated(); + TemplateInstance ti = ts.sym.isInstantiated(); if (ti && isError(ti)) ts.sym = sd; + /* For C modules, if module A contains `struct S;` and + * module B contains `struct S { members...}` then replace + * the former with the latter + */ + else if (!ts.sym.members && sd.members) + ts.sym = sd; } } @@ -4783,7 +2967,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); if (log) printf("\tdeferring %s\n", sd.toChars()); - return deferDsymbolSemantic(sd, scx); + return deferDsymbolSemantic(sc, sd, scx); } /* Look for special member functions. @@ -5174,7 +3358,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // Forward referencee of one or more bases, try again later //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } cldec.baseok = Baseok.done; @@ -5219,7 +3403,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.classKind = ClassKind.cpp; if (cldec.classKind != cldec.baseClass.classKind) .error(cldec.loc, "%s `%s` with %s linkage cannot inherit from class `%s` with %s linkage", cldec.kind, cldec.toPrettyChars, - cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars()); + ClassKindToChars(cldec.classKind), cldec.baseClass.toChars(), ClassKindToChars(cldec.baseClass.classKind)); if (cldec.baseClass.stack) cldec.stack = true; @@ -5284,7 +3468,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tc.sym._scope) Module.addDeferredSemantic(tc.sym); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } } @@ -5401,7 +3585,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); //printf("\tdeferring %s\n", toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } /* Look for special member functions. @@ -5743,7 +3927,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (idec.baseok == Baseok.none) { // Forward referencee of one or more bases, try again later - return deferDsymbolSemantic(idec, scx); + return deferDsymbolSemantic(sc, idec, scx); } idec.baseok = Baseok.done; @@ -5780,7 +3964,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Forward referencee of one or more bases, try again later if (tc.sym._scope) Module.addDeferredSemantic(tc.sym); - return deferDsymbolSemantic(idec, scx); + return deferDsymbolSemantic(sc, idec, scx); } } @@ -6119,7 +4303,7 @@ private extern(C++) class AddMemberVisitor : Visitor } else { - if (findCondition(m.debugidsNot, ds.ident)) + if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident)) { .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars); ds.errors = true; @@ -6157,7 +4341,7 @@ private extern(C++) class AddMemberVisitor : Visitor } else { - if (findCondition(m.versionidsNot, vs.ident)) + if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident)) { .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars); vs.errors = true; @@ -6391,7 +4575,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TemplateStats.incInstance(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incInstance(tempdecl, tempinst, global.params.v.templatesListInstances); tempdecl.checkDeprecated(tempinst.loc, sc); @@ -6584,7 +4769,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent; //printf("parent = '%s'\n", parent.kind()); - TemplateStats.incUnique(tempdecl, tempinst); + if (global.params.v.templates) + TemplateStats.incUnique(tempdecl, tempinst); TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst); @@ -6669,7 +4855,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList if (tempinst.members.length) { Dsymbol s; - if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempinst.members, s, tempdecl.ident) && s) { //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); @@ -6714,7 +4900,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList if (tempinst.members.length) { Dsymbol s; - if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempinst.members, s, tempdecl.ident) && s) { if (!tempinst.aliasdecl || tempinst.aliasdecl != s) { @@ -7206,7 +5392,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc) { Dsymbol scopesym; - Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym); + Dsymbol as = sc.search(ds.loc, ds.ident, scopesym); if (!as) { .error(ds.loc, "%s `%s` undefined identifier `%s`", ds.kind, ds.toPrettyChars, ds.ident.toChars()); @@ -7642,50 +5828,6 @@ private CallExp doAtomicOp (string op, Identifier var, Expression arg) return CallExp.create(loc, dti, args); } -/*************************************** - * Interpret a `pragma(inline, x)` - * - * Params: - * loc = location for error messages - * sc = scope for evaluation of argument - * args = pragma arguments - * Returns: corresponding `PINLINE` state - */ -PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) -{ - if (!args || args.length == 0) - return PINLINE.default_; - - if (args && args.length > 1) - { - .error(loc, "one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.length); - args.setDim(1); - (*args)[0] = ErrorExp.get(); - } - - Expression e = (*args)[0]; - if (!e.type) - { - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - e = e.toBoolean(sc); - if (e.isErrorExp()) - .error(loc, "pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars()); - (*args)[0] = e; - } - - const opt = e.toBool(); - if (opt.isEmpty()) - return PINLINE.default_; - else if (opt.get()) - return PINLINE.always; - else - return PINLINE.never; -} - /*************************************************** * Set up loc for a parse of a mixin. Append the input text to the mixin. * Params: @@ -7833,11 +5975,11 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* * d = dsymbol where ident is searched for * loc = location to print for error messages * ident = identifier to search for - * flags = IgnoreXXXX + * flags = search options * Returns: * null if not found */ -extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone) +extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all) { scope v = new SearchVisitor(loc, ident, flags); d.accept(v); @@ -7862,13 +6004,13 @@ Dsymbol search_correct(Dsymbol d, Identifier ident) cost = 0; // all the same cost Dsymbol s = d; Module.clearCache(); - return s.search(Loc.initial, id, IgnoreErrors); + return s.search(Loc.initial, id, SearchOpt.ignoreErrors); } if (global.gag) return null; // don't do it for speculative compiles; too time consuming // search for exact name first - if (auto s = d.search(Loc.initial, ident, IgnoreErrors)) + if (auto s = d.search(Loc.initial, ident, SearchOpt.ignoreErrors)) return s; import dmd.root.speller : speller; @@ -7881,10 +6023,10 @@ private extern(C++) class SearchVisitor : Visitor const Loc loc; Identifier ident; - int flags; + SearchOptFlags flags; Dsymbol result; - this(const ref Loc loc, Identifier ident, int flags) + this(const ref Loc loc, Identifier ident, SearchOptFlags flags) { this.loc = loc; this.ident = ident; @@ -7908,7 +6050,7 @@ private extern(C++) class SearchVisitor : Visitor //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module - if (sds.symtab && !(flags & SearchImportsOnly)) + if (sds.symtab && !(flags & SearchOpt.importsOnly)) { //printf(" look in locals\n"); auto s1 = sds.symtab.lookup(ident); @@ -7931,30 +6073,30 @@ private extern(C++) class SearchVisitor : Visitor for (size_t i = 0; i < sds.importedScopes.length; i++) { // If private import, don't search it - if ((flags & IgnorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_) + if ((flags & SearchOpt.ignorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_) continue; - int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches + SearchOptFlags sflags = flags & (SearchOpt.ignoreErrors | SearchOpt.ignoreAmbiguous); // remember these in recursive searches Dsymbol ss = (*sds.importedScopes)[i]; //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport()); if (ss.isModule()) { - if (flags & SearchLocalsOnly) + if (flags & SearchOpt.localsOnly) continue; } else // mixin template { - if (flags & SearchImportsOnly) + if (flags & SearchOpt.importsOnly) continue; - sflags |= SearchLocalsOnly; + sflags |= SearchOpt.localsOnly; } /* Don't find private members if ss is a module */ - Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); + Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? SearchOpt.ignorePrivateImports : SearchOpt.all)); import dmd.access : symbolIsVisible; - if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2)) + if (!s2 || !(flags & SearchOpt.ignoreVisibility) && !symbolIsVisible(sds, s2)) continue; if (!s) { @@ -8025,7 +6167,7 @@ private extern(C++) class SearchVisitor : Visitor } } - if (flags & IgnoreAmbiguous) // if return NULL on ambiguity + if (flags & SearchOpt.ignoreAmbiguous) // if return NULL on ambiguity return setResult(null); /* If two imports from C import files, pick first one, as C has global name space @@ -8033,7 +6175,7 @@ private extern(C++) class SearchVisitor : Visitor if (s.isCsymbol() && s2.isCsymbol()) continue; - if (!(flags & IgnoreErrors)) + if (!(flags & SearchOpt.ignoreErrors)) ScopeDsymbol.multiplyDefined(loc, s, s2); break; } @@ -8060,7 +6202,7 @@ private extern(C++) class SearchVisitor : Visitor override void visit(WithScopeSymbol ws) { //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); - if (flags & SearchImportsOnly) + if (flags & SearchOpt.importsOnly) return setResult(null); // Acts as proxy to the with class declaration Dsymbol s = null; @@ -8301,7 +6443,7 @@ private extern(C++) class SearchVisitor : Visitor if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called { - if (!(flags & IgnoreErrors)) + if (!(flags & SearchOpt.ignoreErrors)) .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars()); return setResult(null); } @@ -8324,7 +6466,7 @@ private extern(C++) class SearchVisitor : Visitor override void visit(Package pkg) { //printf("%s Package.search('%s', flags = x%x)\n", pkg.toChars(), ident.toChars(), flags); - flags &= ~SearchLocalsOnly; // searching an import is always transitive + flags &= ~cast(int)SearchOpt.localsOnly; // searching an import is always transitive if (!pkg.isModule() && pkg.mod) { // Prefer full package name. @@ -8351,8 +6493,8 @@ private extern(C++) class SearchVisitor : Visitor /* Qualified module searches always search their imports, * even if SearchLocalsOnly */ - if (!(flags & SearchUnqualifiedModule)) - flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); + if (!(flags & SearchOpt.unqualifiedModule)) + flags &= ~(SearchOpt.unqualifiedModule | SearchOpt.localsOnly); if (m.searchCacheIdent == ident && m.searchCacheFlags == flags) { @@ -8401,7 +6543,7 @@ private extern(C++) class SearchVisitor : Visitor if (!sd.members || !sd.symtab) // opaque or semantic() is not yet called { // .stringof is always defined (but may be hidden by some other symbol) - if(ident != Id.stringof && !(flags & IgnoreErrors) && sd.semanticRun < PASS.semanticdone) + if(ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && sd.semanticRun < PASS.semanticdone) .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars()); return setResult(null); } @@ -8427,7 +6569,7 @@ private extern(C++) class SearchVisitor : Visitor if (!cd.members || !cd.symtab) // opaque or addMember is not yet done { // .stringof is always defined (but may be hidden by some other symbol) - if (ident != Id.stringof && !(flags & IgnoreErrors) && cd.semanticRun < PASS.semanticdone) + if (ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && cd.semanticRun < PASS.semanticdone) cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); //*(char*)0=0; return setResult(null); @@ -8437,7 +6579,7 @@ private extern(C++) class SearchVisitor : Visitor auto s = result; // don't search imports of base classes - if (flags & SearchImportsOnly) + if (flags & SearchOpt.importsOnly) return setResult(s); if (s) @@ -8462,7 +6604,7 @@ private extern(C++) class SearchVisitor : Visitor continue; else if (s == cd) // happens if s is nested in this and derives from this s = null; - else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s)) + else if (!(flags & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s)) s = null; else break; @@ -8621,3 +6763,554 @@ private extern(C++) class SetScopeVisitor : Visitor visit(cast(AttribDeclaration)uad); } } + +extern(C++) void importAll(Dsymbol d, Scope* sc) +{ + scope iav = new ImportAllVisitor(sc); + d.accept(iav); +} + +extern(C++) class ImportAllVisitor : Visitor +{ + alias visit = typeof(super).visit; + Scope* sc; + + this(Scope* sc) + { + this.sc = sc; + } + + override void visit(Dsymbol d) {} + + override void visit(Import imp) + { + if (imp.mod) return; // Already done + + /* + * https://issues.dlang.org/show_bug.cgi?id=15525 + * + * Loading the import has failed, + * most likely because of parsing errors. + * Therefore we cannot trust the resulting AST. + */ + if (imp.load(sc)) + { + // https://issues.dlang.org/show_bug.cgi?id=23873 + // For imports that are not at module or function level, + // e.g. aggregate level, the import symbol is added to the + // symbol table and later semantic is performed on it. + // This leads to semantic analysis on an malformed AST + // which causes all kinds of segfaults. + // The fix is to note that the module has errors and avoid + // semantic analysis on it. + if(imp.mod) + imp.mod.errors = true; + return; + } + + if (!imp.mod) return; // Failed + + if (sc.stc & STC.static_) + imp.isstatic = true; + imp.mod.importAll(null); + imp.mod.checkImportDeprecation(imp.loc, sc); + if (sc.explicitVisibility) + imp.visibility = sc.visibility; + if (!imp.isstatic && !imp.aliasId && !imp.names.length) + sc.scopesym.importScope(imp.mod, imp.visibility); + // Enable access to pkgs/mod as soon as posible, because compiler + // can traverse them before the import gets semantic (Issue: 21501) + if (!imp.aliasId && !imp.names.length) + imp.addPackageAccess(sc.scopesym); + } + + override void visit(Module m) + { + //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", m, m.toChars(), m.parent); + if (m._scope) + return; // already done + if (m.filetype == FileType.ddoc) + { + error(m.loc, "%s `%s` is a Ddoc file, cannot import it", m.kind, m.toPrettyChars); + return; + } + + /* Note that modules get their own scope, from scratch. + * This is so regardless of where in the syntax a module + * gets imported, it is unaffected by context. + * Ignore prevsc. + */ + Scope* sc = Scope.createGlobal(m, global.errorSink); // create root scope + + if (m.md && m.md.msg) + m.md.msg = semanticString(sc, m.md.msg, "deprecation message"); + + // Add import of "object", even for the "object" module. + // If it isn't there, some compiler rewrites, like + // classinst == classinst -> .object.opEquals(classinst, classinst) + // would fail inside object.d. + if (m.filetype != FileType.c && + (m.members.length == 0 || + (*m.members)[0].ident != Id.object || + (*m.members)[0].isImport() is null)) + { + auto im = new Import(Loc.initial, null, Id.object, null, 0); + m.members.shift(im); + } + if (!m.symtab) + { + // Add all symbols into module's symbol table + m.symtab = new DsymbolTable(); + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.addMember(sc, sc.scopesym); + } + } + // anything else should be run after addMember, so version/debug symbols are defined + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * before any semantic() on any of them. + */ + m.setScope(sc); // remember module scope for semantic + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.setScope(sc); + } + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.importAll(sc); + } + sc = sc.pop(); + sc.pop(); // 2 pops because Scope.createGlobal() created 2 + } + + override void visit(AttribDeclaration atb) + { + Dsymbols* d = atb.include(sc); + //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); + if (d) + { + Scope* sc2 = atb.newScope(sc); + d.foreachDsymbol( s => s.importAll(sc2) ); + if (sc2 != sc) + sc2.pop(); + } + } + + // do not evaluate condition before semantic pass + override void visit(StaticIfDeclaration _) {} + // do not evaluate aggregate before semantic pass + override void visit(StaticForeachDeclaration _) {} +} + +extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion) +{ + scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion); + d.accept(v); +} + +private extern(C++) class SetFieldOffsetVisitor : Visitor +{ + alias visit = Visitor.visit; + + AggregateDeclaration ad; + FieldState* fieldState; + bool isunion; + + this(AggregateDeclaration ad, FieldState* fieldState, bool isunion) + { + this.ad = ad; + this.fieldState = fieldState; + this.isunion = isunion; + } + + override void visit(Dsymbol d) {} + + override void visit(Nspace ns) + { + //printf("Nspace::setFieldOffset() %s\n", toChars()); + if (ns._scope) // if fwd reference + dsymbolSemantic(ns, null); // try to resolve it + ns.members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); + } + + override void visit(VarDeclaration vd) + { + //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), vd.toChars()); + + if (vd.aliasTuple) + { + // If this variable was really a tuple, set the offsets for the tuple fields + vd.aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); + return; + } + + if (!vd.isField()) + return; + assert(!(vd.storage_class & (STC.static_ | STC.extern_ | STC.parameter))); + + //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); + + /* Fields that are tuples appear both as part of TupleDeclarations and + * as members. That means ignore them if they are already a field. + */ + if (vd.offset) + { + // already a field + fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 + return; + } + for (size_t i = 0; i < ad.fields.length; i++) + { + if (ad.fields[i] == vd) + { + // already a field + fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 + return; + } + } + + // Check for forward referenced types which will fail the size() call + Type t = vd.type.toBasetype(); + if (vd.storage_class & STC.ref_) + { + // References are the size of a pointer + t = Type.tvoidptr; + } + Type tv = t.baseElemOf(); + if (tv.ty == Tstruct) + { + auto ts = cast(TypeStruct)tv; + assert(ts.sym != ad); // already checked in ad.determineFields() + if (!ts.sym.determineSize(vd.loc)) + { + vd.type = Type.terror; + vd.errors = true; + return; + } + } + + // List in ad.fields. Even if the type is error, it's necessary to avoid + // pointless error diagnostic "more initializers than fields" on struct literal. + ad.fields.push(vd); + + if (t.ty == Terror) + return; + + /* If coming after a bit field in progress, + * advance past the field + */ + fieldState.inFlight = false; + + const sz = t.size(vd.loc); + assert(sz != SIZE_INVALID && sz < uint.max); + uint memsize = cast(uint)sz; // size of member + uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + vd.offset = placeField( + fieldState.offset, + memsize, memalignsize, vd.alignment, + ad.structsize, ad.alignsize, + isunion); + + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); + } + + override void visit(BitFieldDeclaration bfd) + { + enum log = false; + static if (log) + { + printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), bfd.toChars()); + void print(const FieldState* fieldState) + { + fieldState.print(); + printf(" fieldWidth = %d bits\n", bfd.fieldWidth); + } + print(fieldState); + } + + Type t = bfd.type.toBasetype(); + const bool anon = bfd.isAnonymous(); + + // List in ad.fields. Even if the type is error, it's necessary to avoid + // pointless error diagnostic "more initializers than fields" on struct literal. + if (!anon) + ad.fields.push(bfd); + + if (t.ty == Terror) + return; + + const sz = t.size(bfd.loc); + assert(sz != SIZE_INVALID && sz < uint.max); + uint memsize = cast(uint)sz; // size of member + uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); + + if (bfd.fieldWidth == 0 && !anon) + error(bfd.loc, "named bit fields cannot have 0 width"); + if (bfd.fieldWidth > memsize * 8) + error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth); + + const style = target.c.bitFieldStyle; + + void startNewField() + { + if (log) printf("startNewField()\n"); + uint alignsize; + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + if (bfd.fieldWidth > 32) + alignsize = memalignsize; + else if (bfd.fieldWidth > 16) + alignsize = 4; + else if (bfd.fieldWidth > 8) + alignsize = 2; + else + alignsize = 1; + } + else + alignsize = memsize; // not memalignsize + + uint dummy; + bfd.offset = placeField( + fieldState.offset, + memsize, alignsize, bfd.alignment, + ad.structsize, + (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, + isunion); + + fieldState.inFlight = true; + fieldState.fieldOffset = bfd.offset; + fieldState.bitOffset = 0; + fieldState.fieldSize = memsize; + } + + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + if (bfd.fieldWidth == 0) + { + if (!isunion) + { + // Use type of zero width field to align to next field + fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + + if (ad.alignsize == 0) + ad.alignsize = 1; + if (!anon && + ad.alignsize < memalignsize) + ad.alignsize = memalignsize; + } + else if (style == TargetC.BitFieldStyle.MS) + { + if (ad.alignsize == 0) + ad.alignsize = 1; + if (bfd.fieldWidth == 0) + { + if (fieldState.inFlight && !isunion) + { + // documentation says align to next int + //const alsz = cast(uint)Type.tint32.size(); + const alsz = memsize; // but it really does this + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + } + else if (style == TargetC.BitFieldStyle.DM) + { + if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) + return; // this probably should be a bug in DMC + if (ad.alignsize == 0) + ad.alignsize = 1; + if (bfd.fieldWidth == 0) + { + if (fieldState.inFlight && !isunion) + { + const alsz = memsize; + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + } + + if (!fieldState.inFlight) + { + //printf("not in flight\n"); + startNewField(); + } + else if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + // If the bit-field spans more units of alignment than its type, + // start a new field at the next alignment boundary. + if (fieldState.bitOffset == fieldState.fieldSize * 8 && + fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8) + { + if (log) printf("more units of alignment than its type\n"); + startNewField(); // the bit field is full + } + else + { + // if alignment boundary is crossed + uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; + uint end = start + bfd.fieldWidth; + //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); + if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) + { + if (log) printf("alignment is crossed\n"); + startNewField(); + } + } + } + else if (style == TargetC.BitFieldStyle.DM || + style == TargetC.BitFieldStyle.MS) + { + if (memsize != fieldState.fieldSize || + fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8) + { + //printf("new field\n"); + startNewField(); + } + } + else + assert(0); + + bfd.offset = fieldState.fieldOffset; + bfd.bitOffset = fieldState.bitOffset; + + const pastField = bfd.bitOffset + bfd.fieldWidth; + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + auto size = (pastField + 7) / 8; + fieldState.fieldSize = size; + //printf(" offset: %d, size: %d\n", offset, size); + if (isunion) + { + const newstructsize = bfd.offset + size; + if (newstructsize > ad.structsize) + ad.structsize = newstructsize; + } + else + ad.structsize = bfd.offset + size; + } + else + fieldState.fieldSize = memsize; + //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); + //print(fieldState); + + if (!isunion) + { + fieldState.offset = bfd.offset + fieldState.fieldSize; + fieldState.bitOffset = pastField; + } + + //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); + } + + override void visit(TemplateMixin tm) + { + //printf("TemplateMixin.setFieldOffset() %s\n", tm.toChars()); + if (tm._scope) // if fwd reference + dsymbolSemantic(tm, null); // try to resolve it + + tm.members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } ); + } + + override void visit(AttribDeclaration atd) + { + atd.include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); + } + + override void visit(AnonDeclaration anond) + { + //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", anond); + if (anond.decl) + { + /* This works by treating an AnonDeclaration as an aggregate 'member', + * so in order to place that member we need to compute the member's + * size and alignment. + */ + size_t fieldstart = ad.fields.length; + + /* Hackishly hijack ad's structsize and alignsize fields + * for use in our fake anon aggregate member. + */ + uint savestructsize = ad.structsize; + uint savealignsize = ad.alignsize; + ad.structsize = 0; + ad.alignsize = 0; + + FieldState fs; + anond.decl.foreachDsymbol( (s) + { + s.setFieldOffset(ad, &fs, anond.isunion); + if (anond.isunion) + fs.offset = 0; + }); + + /* https://issues.dlang.org/show_bug.cgi?id=13613 + * If the fields in this.members had been already + * added in ad.fields, just update *poffset for the subsequent + * field offset calculation. + */ + if (fieldstart == ad.fields.length) + { + ad.structsize = savestructsize; + ad.alignsize = savealignsize; + fieldState.offset = ad.structsize; + return; + } + + anond.anonstructsize = ad.structsize; + anond.anonalignsize = ad.alignsize; + ad.structsize = savestructsize; + ad.alignsize = savealignsize; + + // 0 sized structs are set to 1 byte + if (anond.anonstructsize == 0) + { + anond.anonstructsize = 1; + anond.anonalignsize = 1; + } + + assert(anond._scope); + auto alignment = anond._scope.alignment(); + + /* Given the anon 'member's size and alignment, + * go ahead and place it. + */ + anond.anonoffset = placeField( + fieldState.offset, + anond.anonstructsize, anond.anonalignsize, alignment, + ad.structsize, ad.alignsize, + isunion); + + // Add to the anon fields the base offset of this anonymous aggregate + //printf("anon fields, anonoffset = %d\n", anonoffset); + foreach (const i; fieldstart .. ad.fields.length) + { + VarDeclaration v = ad.fields[i]; + //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); + v.offset += anond.anonoffset; + } + } + } +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 326d663..4a195e3 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -28,7 +28,7 @@ * arguments, and uses it if found. * - Otherwise, the rest of semantic is run on the `TemplateInstance`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d) @@ -56,9 +56,11 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -75,6 +77,7 @@ import dmd.common.outbuffer; import dmd.rootobject; import dmd.semantic2; import dmd.semantic3; +import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; @@ -150,7 +153,7 @@ extern (C++) bool isError(const RootObject o) if (const e = isExpression(o)) return (e.op == EXP.error || !e.type || e.type.ty == Terror); if (const v = isTuple(o)) - return arrayObjectIsError(&v.objects); + return arrayObjectIsError(v.objects); const s = isDsymbol(o); assert(s); if (s.errors) @@ -161,9 +164,9 @@ extern (C++) bool isError(const RootObject o) /************************************** * Are any of the Objects an error? */ -bool arrayObjectIsError(const Objects* args) +bool arrayObjectIsError(const ref Objects args) { - foreach (const o; *args) + foreach (const o; args) { if (isError(o)) return true; @@ -187,6 +190,13 @@ inout(Type) getType(inout RootObject o) } +/*********************************** + * If oarg represents a Dsymbol, return that Dsymbol + * Params: + * oarg = argument to check + * Returns: + * Dsymbol if a symbol, null if not + */ Dsymbol getDsymbol(RootObject oarg) { //printf("getDsymbol()\n"); @@ -256,8 +266,11 @@ private Expression getExpression(RootObject o) } /****************************** - * If o1 matches o2, return true. - * Else, return false. + * See if two objects match + * Params: + * o1 = first object + * o2 = second object + * Returns: true if they match */ private bool match(RootObject o1, RootObject o2) { @@ -343,7 +356,7 @@ private bool match(RootObject o1, RootObject o2) printf("\tu1 = %s\n", u1.toChars()); printf("\tu2 = %s\n", u2.toChars()); } - if (!arrayObjectMatch(&u1.objects, &u2.objects)) + if (!arrayObjectMatch(u1.objects, u2.objects)) goto Lnomatch; goto Lmatch; @@ -362,15 +375,15 @@ Lnomatch: /************************************ * Match an array of them. */ -private bool arrayObjectMatch(Objects* oa1, Objects* oa2) +bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) { - if (oa1 == oa2) + if (&oa1 == &oa2) return true; if (oa1.length != oa2.length) return false; immutable oa1dim = oa1.length; - auto oa1d = (*oa1)[].ptr; - auto oa2d = (*oa2)[].ptr; + auto oa1d = oa1[].ptr; + auto oa2d = oa2[].ptr; foreach (j; 0 .. oa1dim) { RootObject o1 = oa1d[j]; @@ -386,12 +399,12 @@ private bool arrayObjectMatch(Objects* oa1, Objects* oa2) /************************************ * Return hash of Objects. */ -private size_t arrayObjectHash(Objects* oa1) +private size_t arrayObjectHash(ref Objects oa1) { import dmd.root.hash : mixHash; size_t hash = 0; - foreach (o1; *oa1) + foreach (o1; oa1) { /* Must follow the logic of match() */ @@ -407,7 +420,7 @@ private size_t arrayObjectHash(Objects* oa1) hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent)); } else if (auto u1 = isTuple(o1)) - hash = mixHash(hash, arrayObjectHash(&u1.objects)); + hash = mixHash(hash, arrayObjectHash(u1.objects)); } return hash; } @@ -575,9 +588,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; - private Expression lastConstraint; /// the constraint after the last failed evaluation - private Array!Expression lastConstraintNegs; /// its negative parts - private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` + Expression lastConstraint; /// the constraint after the last failed evaluation + Array!Expression lastConstraintNegs; /// its negative parts + Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { @@ -615,7 +628,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return; Dsymbol s; - if (!Dsymbol.oneMembers(members, &s, ident) || !s) + if (!Dsymbol.oneMembers(members, s, ident) || !s) return; onemember = s; @@ -672,7 +685,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol /********************************** * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return true if successful; i.e. no conflict. + * Params: + * s = symbol to be inserted + * Return: true if successful; i.e. no conflict. */ override bool overloadInsert(Dsymbol s) { @@ -730,55 +745,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol override const(char)* toChars() const { - return toCharsMaybeConstraints(true); - } - - /**************************** - * Similar to `toChars`, but does not print the template constraints - */ - const(char)* toCharsNoConstraints() const - { - return toCharsMaybeConstraints(false); - } - - const(char)* toCharsMaybeConstraints(bool includeConstraints) const - { - OutBuffer buf; HdrGenState hgs; - - buf.writestring(ident == Id.ctor ? "this" : ident.toString()); - buf.writeByte('('); - foreach (i, const tp; *parameters) - { - if (i) - buf.writestring(", "); - toCBuffer(tp, buf, hgs); - } - buf.writeByte(')'); - - if (onemember) - { - const FuncDeclaration fd = onemember.isFuncDeclaration(); - if (fd && fd.type) - { - TypeFunction tf = cast(TypeFunction)fd.type; - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) - { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); - } - } - } - - if (includeConstraints && - constraint) - { - buf.writestring(" if ("); - toCBuffer(constraint, buf, hgs); - buf.writeByte(')'); - } - + OutBuffer buf; + toCharsMaybeConstraints(this, buf, hgs); return buf.extractChars(); } @@ -788,132 +757,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol } /**************************** - * Check to see if constraint is satisfied. - */ - extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) - { - /* Detect recursive attempts to instantiate this template declaration, - * https://issues.dlang.org/show_bug.cgi?id=4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (enclosing is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - - for (TemplatePrevious* p = previous; p; p = p.prev) - { - if (!arrayObjectMatch(p.dedargs, dedargs)) - continue; - //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); - /* It must be a subscope of p.sc, other scope chains are not recursive - * instantiations. - * the chain of enclosing scopes is broken by paramscope (its enclosing - * scope is _scope, but paramscope.callsc is the instantiating scope). So - * it's good enough to check the chain of callsc - */ - for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc) - { - // The first scx might be identical for nested eponymeous templates, e.g. - // template foo() { void foo()() {...} } - if (scx == p.sc && scx !is paramscope.callsc) - return false; - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = previous; - pr.sc = paramscope.callsc; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - Scope* scx = paramscope.push(ti); - scx.parent = ti; - scx.tinst = null; - scx.minst = null; - // Set SCOPE.constraint before declaring function parameters for the static condition - // (previously, this was immediately before calling evalStaticCondition), so the - // semantic pass knows not to issue deprecation warnings for these throw-away decls. - // https://issues.dlang.org/show_bug.cgi?id=21831 - scx.flags |= SCOPE.constraint; - - assert(!ti.symtab); - if (fd) - { - /* Declare all the function parameters as variables and add them to the scope - * Making parameters is similar to FuncDeclaration.semantic3 - */ - auto tf = fd.type.isTypeFunction(); - - scx.parent = fd; - - Parameters* fparameters = tf.parameterList.parameters; - const nfparams = tf.parameterList.length; - foreach (i, fparam; tf.parameterList) - { - fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); - fparam.storageClass |= STC.parameter; - if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams) - { - fparam.storageClass |= STC.variadic; - /* Don't need to set STC.scope_ because this will only - * be evaluated at compile time - */ - } - } - foreach (fparam; *fparameters) - { - if (!fparam.ident) - continue; - // don't add it, if it has no name - auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); - fparam.storageClass |= STC.parameter; - v.storage_class = fparam.storageClass; - v.dsymbolSemantic(scx); - if (!ti.symtab) - ti.symtab = new DsymbolTable(); - if (!scx.insert(v)) - .error(loc, "%s `%s` parameter `%s.%s` is already defined", kind, toPrettyChars, toChars(), v.toChars()); - else - v.parent = fd; - } - if (isstatic) - fd.storage_class |= STC.static_; - fd.declareThis(scx); - } - - lastConstraint = constraint.syntaxCopy(); - lastConstraintTiargs = ti.tiargs; - lastConstraintNegs.setDim(0); - - import dmd.staticcond; - - assert(ti.inst is null); - ti.inst = ti; // temporary instantiation to enable genIdent() - bool errors; - const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs); - if (result || errors) - { - lastConstraint = null; - lastConstraintTiargs = null; - lastConstraintNegs.setDim(0); - } - ti.inst = null; - ti.symtab = null; - scx = scx.pop(); - previous = pr.prev; // unlink from threaded list - if (errors) - return false; - return result; - } - - /**************************** * Destructively get the error message from the last constraint evaluation * Params: * tip = tip to show after printing all overloads @@ -940,7 +783,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol assert(parameters && lastConstraintTiargs); if (parameters.length > 0) { - formatParamsWithTiargs(*lastConstraintTiargs, buf); + formatParamsWithTiargs(*parameters, *lastConstraintTiargs, isVariadic() !is null, buf); buf.writenl(); } if (!full) @@ -973,1483 +816,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return buf.extractChars(); } - private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf) - { - buf.writestring(" with `"); - - // write usual arguments line-by-line - // skips trailing default ones - they are not present in `tiargs` - const bool variadic = isVariadic() !is null; - const end = cast(int)parameters.length - (variadic ? 1 : 0); - uint i; - for (; i < tiargs.length && i < end; i++) - { - if (i > 0) - { - buf.writeByte(','); - buf.writenl(); - buf.writestring(" "); - } - write(buf, (*parameters)[i]); - buf.writestring(" = "); - write(buf, tiargs[i]); - } - // write remaining variadic arguments on the last line - if (variadic) - { - if (i > 0) - { - buf.writeByte(','); - buf.writenl(); - buf.writestring(" "); - } - write(buf, (*parameters)[end]); - buf.writestring(" = "); - buf.writeByte('('); - if (cast(int)tiargs.length - end > 0) - { - write(buf, tiargs[end]); - foreach (j; parameters.length .. tiargs.length) - { - buf.writestring(", "); - write(buf, tiargs[j]); - } - } - buf.writeByte(')'); - } - buf.writeByte('`'); - } - - /****************************** - * Create a scope for the parameters of the TemplateInstance - * `ti` in the parent scope sc from the ScopeDsymbol paramsym. - * - * If paramsym is null a new ScopeDsymbol is used in place of - * paramsym. - * Params: - * ti = the TemplateInstance whose parameters to generate the scope for. - * sc = the parent scope of ti - * Returns: - * a scope for the parameters of ti - */ - Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc) - { - ScopeDsymbol paramsym = new ScopeDsymbol(); - paramsym.parent = _scope.parent; - Scope* paramscope = _scope.push(paramsym); - paramscope.tinst = ti; - paramscope.minst = sc.minst; - paramscope.callsc = sc; - paramscope.stc = 0; - return paramscope; - } - - /*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag) - { - enum LOGM = 0; - static if (LOGM) - { - printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); - } - version (none) - { - printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length); - if (ti.tiargs.length) - printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]); - } - MATCH nomatch() - { - static if (LOGM) - { - printf(" no match\n"); - } - return MATCH.nomatch; - } - MATCH m; - size_t dedtypes_dim = dedtypes.length; - - dedtypes.zero(); - - if (errors) - return MATCH.nomatch; - - size_t parameters_dim = parameters.length; - int variadic = isVariadic() !is null; - - // If more arguments than parameters, no match - if (ti.tiargs.length > parameters_dim && !variadic) - { - static if (LOGM) - { - printf(" no match: more arguments than parameters\n"); - } - return MATCH.nomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti.tiargs.length || variadic); - - assert(_scope); - - // Set up scope for template parameters - Scope* paramscope = scopeForTemplateParameters(ti,sc); - - // Attempt type deduction - m = MATCH.exact; - for (size_t i = 0; i < dedtypes_dim; i++) - { - MATCH m2; - TemplateParameter tp = (*parameters)[i]; - Declaration sparam; - - //printf("\targument [%d]\n", i); - static if (LOGM) - { - //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); - TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); - } - - m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); - //printf("\tm2 = %d\n", m2); - if (m2 == MATCH.nomatch) - { - version (none) - { - printf("\tmatchArg() for parameter %i failed\n", i); - } - return nomatch(); - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam.dsymbolSemantic(paramscope); - if (!paramscope.insert(sparam)) // TODO: This check can make more early - { - // in TemplateDeclaration.semantic, and - // then we don't need to make sparam if flags == 0 - return nomatch(); - } - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - foreach (i, ref dedtype; *dedtypes) - { - if (!dedtype) - { - assert(i < ti.tiargs.length); - dedtype = cast(Type)(*ti.tiargs)[i]; - } - } - } - - if (m > MATCH.nomatch && constraint && !flag) - { - if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error - ti.parent = ti.enclosing; - else - ti.parent = this.parent; - - // Similar to doHeaderInstantiation - FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null; - if (fd) - { - TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); - if (argumentList.hasNames) - return nomatch(); - Expressions* fargs = argumentList.arguments; - // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); - // if (!fargs) - // return nomatch(); - - fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); - fd.parent = ti; - fd.inferRetType = true; - - // Shouldn't run semantic on default arguments and return type. - foreach (ref param; *tf.parameterList.parameters) - param.defaultArg = null; - - tf.next = null; - tf.incomplete = true; - - // Resolve parameter types and 'auto ref's. - tf.fargs = fargs; - uint olderrors = global.startGagging(); - fd.type = tf.typeSemantic(loc, paramscope); - global.endGagging(olderrors); - if (fd.type.ty != Tfunction) - return nomatch(); - fd.originalType = fd.type; // for mangling - } - - // TODO: dedtypes => ti.tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) - return nomatch(); - } - - static if (LOGM) - { - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti.toChars()); - if (m > MATCH.nomatch) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter tp = (*parameters)[i]; - RootObject oarg; - printf(" [%d]", i); - if (i < ti.tiargs.length) - oarg = (*ti.tiargs)[i]; - else - oarg = null; - tp.print(oarg, (*dedtypes)[i]); - } - } - else - return nomatch(); - } - static if (LOGM) - { - printf(" match = %d\n", m); - } - - paramscope.pop(); - static if (LOGM) - { - printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m); - } - return m; - } - - /******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - extern (D) MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList) - { - enum LOG_LEASTAS = 0; - static if (LOG_LEASTAS) - { - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); - } - - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - auto tiargs = new Objects(); - tiargs.reserve(parameters.length); - foreach (tp; *parameters) - { - if (tp.dependent) - break; - RootObject p = tp.dummyArg(); - if (!p) //TemplateTupleParameter - break; - - tiargs.push(p); - } - scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance - - // Temporary Array to hold deduced types - Objects dedtypes = Objects(td2.parameters.length); - - // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1); - if (m > MATCH.nomatch) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - TemplateTupleParameter tp = isVariadic(); - if (tp && !tp.dependent && !td2.isVariadic()) - goto L1; - - static if (LOG_LEASTAS) - { - printf(" matches %d, so is least as specialized\n", m); - } - return m; - } - L1: - static if (LOG_LEASTAS) - { - printf(" doesn't match, so is not as specialized\n"); - } - return MATCH.nomatch; - } - - /************************************************* - * Match function arguments against a specific template function. - * - * Params: - * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments - * sc = instantiation scope - * fd = Partially instantiated function declaration, which is set to an instantiated function declaration - * tthis = 'this' argument if !NULL - * argumentList = arguments to function - * - * Returns: - * match pair of initial and inferred template arguments - */ - extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) - { - version (none) - { - printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) - { - Expression e = (*fargs)[i]; - printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); - } - printf("fd = %s\n", fd.toChars()); - printf("fd.type = %s\n", fd.type.toChars()); - if (tthis) - printf("tthis = %s\n", tthis.toChars()); - } - - assert(_scope); - - auto dedargs = new Objects(parameters.length); - dedargs.zero(); - - Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - dedtypes.setDim(parameters.length); - dedtypes.zero(); - - if (errors || fd.errors) - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - - // Set up scope for parameters - Scope* paramscope = scopeForTemplateParameters(ti,sc); - - MATCHpair nomatch() - { - paramscope.pop(); - //printf("\tnomatch\n"); - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - } - - MATCHpair matcherror() - { - // todo: for the future improvement - paramscope.pop(); - //printf("\terror\n"); - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - } - // Mark the parameter scope as deprecated if the templated - // function is deprecated (since paramscope.enclosing is the - // calling scope already) - paramscope.stc |= fd.storage_class & STC.deprecated_; - - TemplateTupleParameter tp = isVariadic(); - Tuple declaredTuple = null; - - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - printf("\tdedarg[%d] = ", i); - RootObject oarg = (*dedargs)[i]; - if (oarg) - printf("%s", oarg.toChars()); - printf("\n"); - } - } - - size_t ntargs = 0; // array size of tiargs - size_t inferStart = 0; // index of first parameter to infer - const Loc instLoc = ti.loc; - MATCH matchTiargs = MATCH.exact; - - if (auto tiargs = ti.tiargs) - { - // Set initial template arguments - ntargs = tiargs.length; - size_t n = parameters.length; - if (tp) - n--; - if (ntargs > n) - { - if (!tp) - return nomatch(); - - /* The extra initial template arguments - * now form the tuple argument. - */ - auto t = new Tuple(ntargs - n); - assert(parameters.length); - (*dedargs)[parameters.length - 1] = t; - - for (size_t i = 0; i < t.objects.length; i++) - { - t.objects[i] = (*tiargs)[n + i]; - } - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - else - n = ntargs; - - memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); - - for (size_t i = 0; i < n; i++) - { - assert(i < parameters.length); - Declaration sparam = null; - MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCH.nomatch) - return nomatch(); - if (m < matchTiargs) - matchTiargs = m; - - sparam.dsymbolSemantic(paramscope); - if (!paramscope.insert(sparam)) - return nomatch(); - } - if (n < parameters.length && !declaredTuple) - { - inferStart = n; - } - else - inferStart = parameters.length; - //printf("tiargs matchTiargs = %d\n", matchTiargs); - } - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - printf("\tdedarg[%d] = ", i); - RootObject oarg = (*dedargs)[i]; - if (oarg) - printf("%s", oarg.toChars()); - printf("\n"); - } - } - - ParameterList fparameters = fd.getParameterList(); // function parameter list - const nfparams = fparameters.length; // number of function parameters - const nfargs = argumentList.length; // number of function arguments - if (argumentList.hasNames) - return matcherror(); // TODO: resolve named args - Expressions* fargs = argumentList.arguments; // TODO: resolve named args - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * void foo(T, A...)(T t, A a); - * void main() { foo(1,2,3); } - */ - size_t fptupindex = IDX_NOTFOUND; - if (tp) // if variadic - { - // TemplateTupleParameter always makes most lesser matching. - matchTiargs = MATCH.convert; - - if (nfparams == 0 && nfargs != 0) // if no function parameters - { - if (!declaredTuple) - { - auto t = new Tuple(); - //printf("t = %p\n", t); - (*dedargs)[parameters.length - 1] = t; - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - } - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? - if (fparam.type.ty != Tident) - continue; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; - if (!tp.ident.equals(tid.ident) || tid.idents.length) - continue; - - if (fparameters.varargs != VarArg.none) // variadic function doesn't - return nomatch(); // go with variadic template - - goto L1; - } - fptupindex = IDX_NOTFOUND; - L1: - } - } - - MATCH match = MATCH.exact; - if (toParent().isModule()) - tthis = null; - if (tthis) - { - bool hasttp = false; - - // Match 'tthis' to any TemplateThisParameter's - foreach (param; *parameters) - { - if (auto ttp = param.isTemplateThisParameter()) - { - hasttp = true; - - Type t = new TypeIdentifier(Loc.initial, ttp.ident); - MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of tthis against attributes of fd - if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_)) - { - StorageClass stc = _scope.stc | fd.storage_class2; - // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 - Dsymbol p = parent; - while (p.isTemplateDeclaration() || p.isTemplateInstance()) - p = p.parent; - AggregateDeclaration ad = p.isAggregateDeclaration(); - if (ad) - stc |= ad.storage_class; - - ubyte mod = fd.type.mod; - if (stc & STC.immutable_) - mod = MODFlags.immutable_; - else - { - if (stc & (STC.shared_ | STC.synchronized_)) - mod |= MODFlags.shared_; - if (stc & STC.const_) - mod |= MODFlags.const_; - if (stc & STC.wild) - mod |= MODFlags.wild; - } - - ubyte thismod = tthis.mod; - if (hasttp) - mod = MODmerge(thismod, mod); - MATCH m = MODmethodConv(thismod, mod); - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - } - } - - // Loop through the function parameters - { - //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); - //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); - size_t argi = 0; - size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs - uint inoutMatch = 0; // for debugging only - for (size_t parami = 0; parami < nfparams; parami++) - { - Parameter fparam = fparameters[parami]; - - // Apply function parameter storage classes to parameter types - Type prmtype = fparam.type.addStorageClass(fparam.storageClass); - - Expression farg; - - /* See function parameters which wound up - * as part of a template tuple parameter. - */ - if (fptupindex != IDX_NOTFOUND && parami == fptupindex) - { - assert(prmtype.ty == Tident); - TypeIdentifier tid = cast(TypeIdentifier)prmtype; - if (!declaredTuple) - { - /* The types of the function arguments - * now form the tuple argument. - */ - declaredTuple = new Tuple(); - (*dedargs)[parameters.length - 1] = declaredTuple; - - /* Count function parameters with no defaults following a tuple parameter. - * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) - */ - size_t rem = 0; - for (size_t j = parami + 1; j < nfparams; j++) - { - Parameter p = fparameters[j]; - if (p.defaultArg) - { - break; - } - if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length])) - { - Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); - rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1; - } - else - { - ++rem; - } - } - - if (nfargs2 - argi < rem) - return nomatch(); - declaredTuple.objects.setDim(nfargs2 - argi - rem); - for (size_t i = 0; i < declaredTuple.objects.length; i++) - { - farg = (*fargs)[argi + i]; - - // Check invalid arguments to detect errors early. - if (farg.op == EXP.error || farg.type.ty == Terror) - return nomatch(); - - if (!fparam.isLazy() && farg.type.ty == Tvoid) - return nomatch(); - - Type tt; - MATCH m; - if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) - { - inoutMatch |= wm; - m = MATCH.constant; - } - else - { - m = deduceTypeHelper(farg.type, &tt, tid); - } - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - - /* Remove top const for dynamic array types and pointer types - */ - if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) - { - tt = tt.mutableOf(); - } - declaredTuple.objects[i] = tt; - } - declareParameter(paramscope, tp, declaredTuple); - } - else - { - // https://issues.dlang.org/show_bug.cgi?id=6810 - // If declared tuple is not a type tuple, - // it cannot be function parameter types. - for (size_t i = 0; i < declaredTuple.objects.length; i++) - { - if (!isType(declaredTuple.objects[i])) - return nomatch(); - } - } - assert(declaredTuple); - argi += declaredTuple.objects.length; - continue; - } - - // If parameter type doesn't depend on inferred template parameters, - // semantic it to get actual type. - if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.length])) - { - // should copy prmtype to avoid affecting semantic result - prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); - - if (prmtype.ty == Ttuple) - { - TypeTuple tt = cast(TypeTuple)prmtype; - size_t tt_dim = tt.arguments.length; - for (size_t j = 0; j < tt_dim; j++, ++argi) - { - Parameter p = (*tt.arguments)[j]; - if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && - parami + 1 == nfparams && argi < nfargs) - { - prmtype = p.type; - goto Lvarargs; - } - if (argi >= nfargs) - { - if (p.defaultArg) - continue; - - // https://issues.dlang.org/show_bug.cgi?id=19888 - if (fparam.defaultArg) - break; - - return nomatch(); - } - farg = (*fargs)[argi]; - if (!farg.implicitConvTo(p.type)) - return nomatch(); - } - continue; - } - } - - if (argi >= nfargs) // if not enough arguments - { - if (!fparam.defaultArg) - goto Lvarargs; - - /* https://issues.dlang.org/show_bug.cgi?id=2803 - * Before the starting of type deduction from the function - * default arguments, set the already deduced parameters into paramscope. - * It's necessary to avoid breaking existing acceptable code. Cases: - * - * 1. Already deduced template parameters can appear in fparam.defaultArg: - * auto foo(A, B)(A a, B b = A.stringof); - * foo(1); - * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' - * - * 2. If prmtype depends on default-specified template parameter, the - * default type should be preferred. - * auto foo(N = size_t, R)(R r, N start = 0) - * foo([1,2,3]); - * // at fparam `N start = 0`, N should be 'size_t' before - * // the deduction result from fparam.defaultArg. - */ - if (argi == nfargs) - { - foreach (ref dedtype; *dedtypes) - { - Type at = isType(dedtype); - if (at && at.ty == Tnone) - { - TypeDeduced xt = cast(TypeDeduced)at; - dedtype = xt.tded; // 'unbox' - } - } - for (size_t i = ntargs; i < dedargs.length; i++) - { - TemplateParameter tparam = (*parameters)[i]; - - RootObject oarg = (*dedargs)[i]; - RootObject oded = (*dedtypes)[i]; - if (oarg) - continue; - - if (oded) - { - if (tparam.specialization() || !tparam.isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, kind, toPrettyChars, tparam.ident.toChars()); - } - else - { - if (MATCH.convert < matchTiargs) - matchTiargs = MATCH.convert; - } - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - else - { - oded = tparam.defaultArg(instLoc, paramscope); - if (oded) - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - } - } - nfargs2 = argi + 1; - - /* If prmtype does not depend on any template parameters: - * - * auto foo(T)(T v, double x = 0); - * foo("str"); - * // at fparam == 'double x = 0' - * - * or, if all template parameters in the prmtype are already deduced: - * - * auto foo(R)(R range, ElementType!R sum = 0); - * foo([1,2,3]); - * // at fparam == 'ElementType!R sum = 0' - * - * Deducing prmtype from fparam.defaultArg is not necessary. - */ - if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope)) - { - ++argi; - continue; - } - - // Deduce prmtype from the defaultArg. - farg = fparam.defaultArg.syntaxCopy(); - farg = farg.expressionSemantic(paramscope); - farg = resolveProperties(paramscope, farg); - } - else - { - farg = (*fargs)[argi]; - } - { - // Check invalid arguments to detect errors early. - if (farg.op == EXP.error || farg.type.ty == Terror) - return nomatch(); - - Type att = null; - Lretry: - version (none) - { - printf("\tfarg.type = %s\n", farg.type.toChars()); - printf("\tfparam.type = %s\n", prmtype.toChars()); - } - Type argtype = farg.type; - - if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_) - return nomatch(); - - // https://issues.dlang.org/show_bug.cgi?id=12876 - // Optimize argument to allow CT-known length matching - farg = farg.optimize(WANTvalue, fparam.isReference()); - //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); - - RootObject oarg = farg; - if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) - { - /* Allow expressions that have CT-known boundaries and type [] to match with [dim] - */ - Type taai; - if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0)) - { - if (StringExp se = farg.isStringExp()) - { - argtype = se.type.nextOf().sarrayOf(se.len); - } - else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) - { - argtype = ae.type.nextOf().sarrayOf(ae.elements.length); - } - else if (SliceExp se = farg.isSliceExp()) - { - if (Type tsa = toStaticArrayType(se)) - argtype = tsa; - } - } - - oarg = argtype; - } - else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0) - { - /* The farg passing to the prmtype always make a copy. Therefore, - * we can shrink the set of the deduced type arguments for prmtype - * by adjusting top-qualifier of the argtype. - * - * prmtype argtype ta - * T <- const(E)[] const(E)[] - * T <- const(E[]) const(E)[] - * qualifier(T) <- const(E)[] const(E[]) - * qualifier(T) <- const(E[]) const(E[]) - */ - Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); - if (ta != argtype) - { - Expression ea = farg.copy(); - ea.type = ta; - oarg = ea; - } - } - - if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs) - goto Lvarargs; - - uint im = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart); - //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); - inoutMatch |= im; - - /* If no match, see if the argument can be matched by using - * implicit conversions. - */ - if (m == MATCH.nomatch && prmtype.deco) - m = farg.implicitConvTo(prmtype); - - if (m == MATCH.nomatch) - { - AggregateDeclaration ad = isAggregate(farg.type); - if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype)) - { - // https://issues.dlang.org/show_bug.cgi?id=12537 - // The isRecursiveAliasThis() call above - - /* If a semantic error occurs while doing alias this, - * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), - * just regard it as not a match. - * - * We also save/restore sc.func.flags to avoid messing up - * attribute inference in the evaluation. - */ - const oldflags = sc.func ? sc.func.flags : 0; - auto e = resolveAliasThis(sc, farg, true); - if (sc.func) - sc.func.flags = oldflags; - if (e) - { - farg = e; - goto Lretry; - } - } - } - - if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) - { - if (!farg.isLvalue()) - { - 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] - } - else if (global.params.rvalueRefParam == FeatureState.enabled) - { - // Allow implicit conversion to ref - } - else - return nomatch(); - } - } - if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) - { - if (!farg.isLvalue()) - return nomatch(); - if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 - return nomatch(); - } - if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid) - m = MATCH.convert; - if (m != MATCH.nomatch) - { - if (m < match) - match = m; // pick worst match - argi++; - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction.callMatch() - */ - if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams)) - return nomatch(); - - /* Check for match with function parameter T... - */ - Type tb = prmtype.toBasetype(); - switch (tb.ty) - { - // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). - case Tsarray: - case Taarray: - { - // Perhaps we can do better with this, see TypeFunction.callMatch() - if (tb.ty == Tsarray) - { - TypeSArray tsa = cast(TypeSArray)tb; - dinteger_t sz = tsa.dim.toInteger(); - if (sz != nfargs - argi) - return nomatch(); - } - else if (tb.ty == Taarray) - { - TypeAArray taa = cast(TypeAArray)tb; - Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t); - - size_t i = templateParameterLookup(taa.index, parameters); - if (i == IDX_NOTFOUND) - { - Expression e; - Type t; - Dsymbol s; - Scope *sco; - - uint errors = global.startGagging(); - /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 - * The parameter isn't part of the template - * ones, let's try to find it in the - * instantiation scope 'sc' and the one - * belonging to the template itself. */ - sco = sc; - taa.index.resolve(instLoc, sco, e, t, s); - if (!e) - { - sco = paramscope; - taa.index.resolve(instLoc, sco, e, t, s); - } - global.endGagging(errors); - - if (!e) - return nomatch(); - - e = e.ctfeInterpret(); - e = e.implicitCastTo(sco, Type.tsize_t); - e = e.optimize(WANTvalue); - if (!dim.equals(e)) - return nomatch(); - } - else - { - // This code matches code in TypeInstance.deduceType() - TemplateParameter tprm = (*parameters)[i]; - TemplateValueParameter tvp = tprm.isTemplateValueParameter(); - if (!tvp) - return nomatch(); - Expression e = cast(Expression)(*dedtypes)[i]; - if (e) - { - if (!dim.equals(e)) - return nomatch(); - } - else - { - Type vt = tvp.valType.typeSemantic(Loc.initial, sc); - MATCH m = dim.implicitConvTo(vt); - if (m == MATCH.nomatch) - return nomatch(); - (*dedtypes)[i] = dim; - } - } - } - goto case Tarray; - } - case Tarray: - { - TypeArray ta = cast(TypeArray)tb; - Type tret = fparam.isLazyArray(); - for (; argi < nfargs; argi++) - { - Expression arg = (*fargs)[argi]; - assert(arg); - - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - if (tret) - { - if (ta.next.equals(arg.type)) - { - m = MATCH.exact; - } - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - { - if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - } - } - } - else - { - uint wm = 0; - m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); - inoutMatch |= wm; - } - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - return nomatch(); - } - assert(0); - } - //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); - if (argi != nfargs2 && fparameters.varargs == VarArg.none) - return nomatch(); - } - - Lmatch: - foreach (ref dedtype; *dedtypes) - { - Type at = isType(dedtype); - if (at) - { - if (at.ty == Tnone) - { - TypeDeduced xt = cast(TypeDeduced)at; - at = xt.tded; // 'unbox' - } - dedtype = at.merge2(); - } - } - for (size_t i = ntargs; i < dedargs.length; i++) - { - TemplateParameter tparam = (*parameters)[i]; - //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); - - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - RootObject oarg = (*dedargs)[i]; - RootObject oded = (*dedtypes)[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg.toChars()); - //if (oded) printf("oded: %s\n", oded.toChars()); - if (oarg) - continue; - - if (oded) - { - if (tparam.specialization() || !tparam.isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars()); - } - else - { - // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 - if (MATCH.convert < matchTiargs) - matchTiargs = MATCH.convert; - } - } - else - { - oded = tparam.defaultArg(instLoc, paramscope); - if (!oded) - { - // if tuple parameter and - // tuple parameter was not in function parameter list and - // we're one or more arguments short (i.e. no tuple argument) - if (tparam == tp && - fptupindex == IDX_NOTFOUND && - ntargs <= dedargs.length - 1) - { - // make tuple argument an empty tuple - oded = new Tuple(); - } - else - return nomatch(); - } - if (isError(oded)) - return matcherror(); - ntargs++; - - /* At the template parameter T, the picked default template argument - * X!int should be matched to T in order to deduce dependent - * template parameter A. - * auto foo(T : X!A = X!int, A...)() { ... } - * foo(); // T <-- X!int, A <-- (int) - */ - if (tparam.specialization()) - { - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars()); - } - } - oded = declareParameter(paramscope, tparam, oded); - (*dedargs)[i] = oded; - } - - /* https://issues.dlang.org/show_bug.cgi?id=7469 - * As same as the code for 7469 in findBestMatch, - * expand a Tuple in dedargs to normalize template arguments. - */ - if (auto d = dedargs.length) - { - if (auto va = isTuple((*dedargs)[d - 1])) - { - dedargs.setDim(d - 1); - dedargs.insert(d - 1, &va.objects); - } - } - ti.tiargs = dedargs; // update to the normalized template arguments. - - // Partially instantiate function for constraint and fd.leastAsSpecialized() - { - assert(paramscope.scopesym); - Scope* sc2 = _scope; - sc2 = sc2.push(paramscope.scopesym); - sc2 = sc2.push(ti); - sc2.parent = ti; - sc2.tinst = ti; - sc2.minst = sc.minst; - sc2.stc |= fd.storage_class & STC.deprecated_; - - fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); - - sc2 = sc2.pop(); - sc2 = sc2.pop(); - - if (!fd) - return nomatch(); - } - - if (constraint) - { - if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) - return nomatch(); - } - - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - RootObject o = (*dedargs)[i]; - printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); - } - } - - paramscope.pop(); - //printf("\tmatch %d\n", match); - return MATCHpair(matchTiargs, match); - } - - /************************************************** - * Declare template parameter tp with value o, and install it in the scope sc. - */ - extern (D) RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o) - { - //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); - Type ta = isType(o); - Expression ea = isExpression(o); - Dsymbol sa = isDsymbol(o); - Tuple va = isTuple(o); - - Declaration d; - VarDeclaration v = null; - - if (ea) - { - if (ea.op == EXP.type) - ta = ea.type; - else if (auto se = ea.isScopeExp()) - sa = se.sds; - else if (auto te = ea.isThisExp()) - sa = te.var; - else if (auto se = ea.isSuperExp()) - sa = se.var; - else if (auto fe = ea.isFuncExp()) - { - if (fe.td) - sa = fe.td; - else - sa = fe.fd; - } - } - - if (ta) - { - //printf("type %s\n", ta.toChars()); - auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta); - ad.storage_class |= STC.templateparameter; - d = ad; - } - else if (sa) - { - //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); - auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa); - ad.storage_class |= STC.templateparameter; - d = ad; - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer _init = new ExpInitializer(loc, ea); - TemplateValueParameter tvp = tp.isTemplateValueParameter(); - Type t = tvp ? tvp.valType : null; - v = new VarDeclaration(loc, t, tp.ident, _init); - v.storage_class = STC.manifest | STC.templateparameter; - d = v; - } - else if (va) - { - //printf("\ttuple\n"); - d = new TupleDeclaration(loc, tp.ident, &va.objects); - } - else - { - assert(0); - } - d.storage_class |= STC.templateparameter; - - if (ta) - { - Type t = ta; - // consistent with Type.checkDeprecated() - while (t.ty != Tenum) - { - if (!t.nextOf()) - break; - t = (cast(TypeNext)t).next; - } - if (Dsymbol s = t.toDsymbol(sc)) - { - if (s.isDeprecated()) - d.storage_class |= STC.deprecated_; - } - } - else if (sa) - { - if (sa.isDeprecated()) - d.storage_class |= STC.deprecated_; - } - - if (!sc.insert(d)) - .error(loc, "%s `%s` declaration `%s` is already defined", kind, toPrettyChars, tp.ident.toChars()); - d.dsymbolSemantic(sc); - /* So the caller's o gets updated with the result of semantic() being run on o - */ - if (v) - o = v._init.initializerToExpression(); - return o; - } - - /************************************************* - * Limited function template instantiation for using fd.leastAsSpecialized() - */ - extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs) - { - assert(fd); - version (none) - { - printf("doHeaderInstantiation this = %s\n", toChars()); - } - - // function body and contracts are not need - if (fd.isCtorDeclaration()) - fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy()); - else - fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy()); - fd.parent = ti; - - assert(fd.type.ty == Tfunction); - auto tf = fd.type.isTypeFunction(); - tf.fargs = fargs; - - if (tthis) - { - // Match 'tthis' to any TemplateThisParameter's - bool hasttp = false; - foreach (tp; *parameters) - { - TemplateThisParameter ttp = tp.isTemplateThisParameter(); - if (ttp) - hasttp = true; - } - if (hasttp) - { - tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod)); - assert(!tf.deco); - } - } - - Scope* scx = sc2.push(); - - // Shouldn't run semantic on default arguments and return type. - foreach (ref params; *tf.parameterList.parameters) - params.defaultArg = null; - tf.incomplete = true; - - if (fd.isCtorDeclaration()) - { - // For constructors, emitting return type is necessary for - // isReturnIsolated() in functionResolve. - tf.isctor = true; - - Dsymbol parent = toParentDecl(); - Type tret; - AggregateDeclaration ad = parent.isAggregateDeclaration(); - if (!ad || parent.isUnionDeclaration()) - { - tret = Type.tvoid; - } - else - { - tret = ad.handleType(); - assert(tret); - tret = tret.addStorageClass(fd.storage_class | scx.stc); - tret = tret.addMod(tf.mod); - } - tf.next = tret; - if (ad && ad.isStructDeclaration()) - tf.isref = 1; - //printf("tf = %s\n", tf.toChars()); - } - else - tf.next = null; - fd.type = tf; - fd.type = fd.type.addSTC(scx.stc); - fd.type = fd.type.typeSemantic(fd.loc, scx); - scx = scx.pop(); - - if (fd.type.ty != Tfunction) - return null; - - fd.originalType = fd.type; // for mangling - //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod); - //printf("fd.needThis() = %d\n", fd.needThis()); - - return fd; - } - debug (FindExistingInstance) { __gshared uint nFound, nNotFound, nAdded, nRemoved; @@ -2591,571 +957,6 @@ extern (C++) final class TypeDeduced : Type } -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return matching result. - * Params: - * m = matching result - * dstart = the root of overloaded function templates - * loc = instantiation location - * sc = instantiation scope - * tiargs = initial list of template arguments - * tthis = if !NULL, the 'this' pointer argument - * argumentList= arguments to function - * pMessage = address to store error message, or null - */ -void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, ArgumentList argumentList, const(char)** pMessage = null) -{ - version (none) - { - printf("functionResolve() dstart = %s\n", dstart.toChars()); - printf(" tiargs:\n"); - if (tiargs) - { - for (size_t i = 0; i < tiargs.length; i++) - { - RootObject arg = (*tiargs)[i]; - printf("\t%s\n", arg.toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) - { - Expression arg = (*fargs)[i]; - printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); - //printf("\tty = %d\n", arg.type.ty); - } - //printf("stc = %llx\n", dstart._scope.stc); - //printf("match:t/f = %d/%d\n", ta_last, m.last); - } - - // results - int property = 0; // 0: uninitialized - // 1: seen @property - // 2: not @property - size_t ov_index = 0; - TemplateDeclaration td_best; - TemplateInstance ti_best; - MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch; - Type tthis_best; - - int applyFunction(FuncDeclaration fd) - { - // skip duplicates - if (fd == m.lastf) - return 0; - // explicitly specified tiargs never match to non template function - if (tiargs && tiargs.length > 0) - return 0; - - // constructors need a valid scope in order to detect semantic errors - if (!fd.isCtorDeclaration && - fd.semanticRun < PASS.semanticdone) - { - Ungag ungag = fd.ungagSpeculative(); - fd.dsymbolSemantic(null); - } - if (fd.semanticRun < PASS.semanticdone) - { - .error(loc, "forward reference to template `%s`", fd.toChars()); - return 1; - } - //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); - auto tf = cast(TypeFunction)fd.type; - - int prop = tf.isproperty ? 1 : 2; - if (property == 0) - property = prop; - else if (property != prop) - error(fd.loc, "cannot overload both property and non-property functions"); - - /* For constructors, qualifier check will be opposite direction. - * Qualified constructor always makes qualified object, then will be checked - * that it is implicitly convertible to tthis. - */ - Type tthis_fd = fd.needThis() ? tthis : null; - bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); - if (isCtorCall) - { - //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(), - // tf.mod, tthis_fd.mod, fd.isReturnIsolated()); - if (MODimplicitConv(tf.mod, tthis_fd.mod) || - tf.isWild() && tf.isShared() == tthis_fd.isShared() || - fd.isReturnIsolated()) - { - /* && tf.isShared() == tthis_fd.isShared()*/ - // Uniquely constructed object can ignore shared qualifier. - // TODO: Is this appropriate? - tthis_fd = null; - } - else - return 0; // MATCH.nomatch - } - /* Fix Issue 17970: - If a struct is declared as shared the dtor is automatically - considered to be shared, but when the struct is instantiated - the instance is no longer considered to be shared when the - function call matching is done. The fix makes it so that if a - struct declaration is shared, when the destructor is called, - the instantiated struct is also considered shared. - */ - if (auto dt = fd.isDtorDeclaration()) - { - auto dtmod = dt.type.toTypeFunction(); - auto shared_dtor = dtmod.mod & MODFlags.shared_; - auto shared_this = tthis_fd !is null ? - tthis_fd.mod & MODFlags.shared_ : 0; - if (shared_dtor && !shared_this) - tthis_fd = dtmod; - else if (shared_this && !shared_dtor && tthis_fd !is null) - tf.mod = tthis_fd.mod; - } - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc); - //printf("test1: mfa = %d\n", mfa); - if (mfa == MATCH.nomatch) - return 0; - - int firstIsBetter() - { - td_best = null; - ti_best = null; - ta_last = MATCH.exact; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m.count = 1; - return 0; - } - - if (mfa > m.last) return firstIsBetter(); - if (mfa < m.last) return 0; - - /* See if one of the matches overrides the other. - */ - assert(m.lastf); - if (m.lastf.overrides(fd)) return 0; - if (fd.overrides(m.lastf)) return firstIsBetter(); - - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); - MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) return firstIsBetter(); - if (c1 < c2) return 0; - } - - /* The 'overrides' check above does covariant checking only - * for virtual member functions. It should do it for all functions, - * but in order to not risk breaking code we put it after - * the 'leastAsSpecialized' check. - * In the future try moving it before. - * I.e. a not-the-same-but-covariant match is preferred, - * as it is more restrictive. - */ - if (!m.lastf.type.equals(fd.type)) - { - //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type)); - const lastCovariant = m.lastf.type.covariant(fd.type); - const firstCovariant = fd.type.covariant(m.lastf.type); - - if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no) - { - if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no) - { - return 0; - } - } - else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no) - { - return firstIsBetter(); - } - } - - /* If the two functions are the same function, like: - * int foo(int); - * int foo(int x) { ... } - * then pick the one with the body. - * - * If none has a body then don't care because the same - * real function would be linked to the decl (e.g from object file) - */ - if (tf.equals(m.lastf.type) && - fd.storage_class == m.lastf.storage_class && - fd.parent == m.lastf.parent && - fd.visibility == m.lastf.visibility && - fd._linkage == m.lastf._linkage) - { - if (fd.fbody && !m.lastf.fbody) - return firstIsBetter(); - if (!fd.fbody) - return 0; - } - - // https://issues.dlang.org/show_bug.cgi?id=14450 - // Prefer exact qualified constructor for the creating object type - if (isCtorCall && tf.mod != m.lastf.type.mod) - { - if (tthis.mod == tf.mod) return firstIsBetter(); - if (tthis.mod == m.lastf.type.mod) return 0; - } - - m.nextf = fd; - m.count++; - return 0; - } - - int applyTemplate(TemplateDeclaration td) - { - //printf("applyTemplate(): td = %s\n", td.toChars()); - if (td == td_best) // skip duplicates - return 0; - - if (!sc) - sc = td._scope; // workaround for Type.aliasthisOf - - if (td.semanticRun == PASS.initial && td._scope) - { - // Try to fix forward reference. Ungag errors while doing so. - Ungag ungag = td.ungagSpeculative(); - td.dsymbolSemantic(td._scope); - } - if (td.semanticRun == PASS.initial) - { - .error(loc, "forward reference to template `%s`", td.toChars()); - Lerror: - m.lastf = null; - m.count = 0; - m.last = MATCH.nomatch; - return 1; - } - //printf("td = %s\n", td.toChars()); - - if (argumentList.hasNames) - { - .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet"); - goto Lerror; - } - auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; - if (!f) - { - if (!tiargs) - tiargs = new Objects(); - auto ti = new TemplateInstance(loc, td, tiargs); - Objects dedtypes = Objects(td.parameters.length); - assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0); - //printf("matchWithInstance = %d\n", mta); - if (mta == MATCH.nomatch || mta < ta_last) // no match or less match - return 0; - - ti.templateInstanceSemantic(sc, argumentList); - if (!ti.inst) // if template failed to expand - return 0; - - Dsymbol s = ti.inst.toAlias(); - FuncDeclaration fd; - if (auto tdx = s.isTemplateDeclaration()) - { - Objects dedtypesX; // empty tiargs - - // https://issues.dlang.org/show_bug.cgi?id=11553 - // Check for recursive instantiation of tdx. - for (TemplatePrevious* p = tdx.previous; p; p = p.prev) - { - if (arrayObjectMatch(p.dedargs, &dedtypesX)) - { - //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); - /* It must be a subscope of p.sc, other scope chains are not recursive - * instantiations. - */ - for (Scope* scx = sc; scx; scx = scx.enclosing) - { - if (scx == p.sc) - { - error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars()); - goto Lerror; - } - } - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = tdx.previous; - pr.sc = sc; - pr.dedargs = &dedtypesX; - tdx.previous = ≺ // add this to threaded list - - fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); - - tdx.previous = pr.prev; // unlink from threaded list - } - else if (s.isFuncDeclaration()) - { - fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); - } - else - goto Lerror; - - if (!fd) - return 0; - - if (fd.type.ty != Tfunction) - { - m.lastf = fd; // to propagate "error match" - m.count = 1; - m.last = MATCH.nomatch; - return 1; - } - - Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; - - auto tf = cast(TypeFunction)fd.type; - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); - if (mfa < m.last) - return 0; - - if (mta < ta_last) goto Ltd_best2; - if (mta > ta_last) goto Ltd2; - - if (mfa < m.last) goto Ltd_best2; - if (mfa > m.last) goto Ltd2; - - // td_best and td are ambiguous - //printf("Lambig2\n"); - m.nextf = fd; - m.count++; - return 0; - - Ltd_best2: - return 0; - - Ltd2: - // td is the new best match - assert(td._scope); - td_best = td; - ti_best = null; - property = 0; // (backward compatibility) - ta_last = mta; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = 0; - m.nextf = null; - m.count = 1; - return 0; - } - - //printf("td = %s\n", td.toChars()); - for (size_t ovi = 0; f; f = f.overnext0, ovi++) - { - if (f.type.ty != Tfunction || f.errors) - goto Lerror; - - /* This is a 'dummy' instance to evaluate constraint properly. - */ - auto ti = new TemplateInstance(loc, td, tiargs); - ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. - - auto fd = f; - MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList); - MATCH mta = x.mta; - MATCH mfa = x.mfa; - //printf("match:t/f = %d/%d\n", mta, mfa); - if (!fd || mfa == MATCH.nomatch) - continue; - - Type tthis_fd = fd.needThis() ? tthis : null; - - bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); - if (isCtorCall) - { - // Constructor call requires additional check. - auto tf = cast(TypeFunction)fd.type; - assert(tf.next); - if (MODimplicitConv(tf.mod, tthis_fd.mod) || - tf.isWild() && tf.isShared() == tthis_fd.isShared() || - fd.isReturnIsolated()) - { - tthis_fd = null; - } - else - continue; // MATCH.nomatch - - // need to check here whether the constructor is the member of a struct - // declaration that defines a copy constructor. This is already checked - // in the semantic of CtorDeclaration, however, when matching functions, - // the template instance is not expanded. - // https://issues.dlang.org/show_bug.cgi?id=21613 - auto ad = fd.isThis(); - auto sd = ad.isStructDeclaration(); - if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti)) - continue; - } - - if (mta < ta_last) goto Ltd_best; - if (mta > ta_last) goto Ltd; - - if (mfa < m.last) goto Ltd_best; - if (mfa > m.last) goto Ltd; - - if (td_best) - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); - MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - assert(fd && m.lastf); - { - // Disambiguate by tf.callMatch - auto tf1 = fd.type.isTypeFunction(); - auto tf2 = m.lastf.type.isTypeFunction(); - MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc); - MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); - MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) goto Ltd; - if (c1 < c2) goto Ltd_best; - } - - // https://issues.dlang.org/show_bug.cgi?id=14450 - // Prefer exact qualified constructor for the creating object type - if (isCtorCall && fd.type.mod != m.lastf.type.mod) - { - if (tthis.mod == fd.type.mod) goto Ltd; - if (tthis.mod == m.lastf.type.mod) goto Ltd_best; - } - - m.nextf = fd; - m.count++; - continue; - - Ltd_best: // td_best is the best match so far - //printf("Ltd_best\n"); - continue; - - Ltd: // td is the new best match - //printf("Ltd\n"); - assert(td._scope); - td_best = td; - ti_best = ti; - property = 0; // (backward compatibility) - ta_last = mta; - m.last = mfa; - m.lastf = fd; - tthis_best = tthis_fd; - ov_index = ovi; - m.nextf = null; - m.count = 1; - continue; - } - return 0; - } - - auto td = dstart.isTemplateDeclaration(); - if (td && td.funcroot) - dstart = td.funcroot; - overloadApply(dstart, (Dsymbol s) - { - if (s.errors) - return 0; - if (auto fd = s.isFuncDeclaration()) - return applyFunction(fd); - if (auto td = s.isTemplateDeclaration()) - return applyTemplate(td); - return 0; - }, sc); - - //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf); - if (td_best && ti_best && m.count == 1) - { - // Matches to template function - assert(td_best.onemember && td_best.onemember.isFuncDeclaration()); - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert(td_best._scope); - if (!sc) - sc = td_best._scope; // workaround for Type.aliasthisOf - - auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); - ti.templateInstanceSemantic(sc, argumentList); - - m.lastf = ti.toAlias().isFuncDeclaration(); - if (!m.lastf) - goto Lnomatch; - if (ti.errors) - { - Lerror: - m.count = 1; - assert(m.lastf); - m.last = MATCH.nomatch; - return; - } - - // look forward instantiated overload function - // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic. - // it has filled overnext0d - while (ov_index--) - { - m.lastf = m.lastf.overnext0; - assert(m.lastf); - } - - tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null; - - if (m.lastf.type.ty == Terror) - goto Lerror; - auto tf = m.lastf.type.isTypeFunction(); - if (!tf.callMatch(tthis_best, argumentList, 0, null, sc)) - goto Lnomatch; - - /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, - * a template instance can be matched while instantiating - * that same template. Thus, the function type can be incomplete. Complete it. - * - * https://issues.dlang.org/show_bug.cgi?id=9208 - * For auto function, completion should be deferred to the end of - * its semantic3. Should not complete it in here. - */ - if (tf.next && !m.lastf.inferRetType) - { - m.lastf.type = tf.typeSemantic(loc, sc); - } - } - else if (m.lastf) - { - // Matches to non template function, - // or found matches were ambiguous. - assert(m.count >= 1); - } - else - { - Lnomatch: - m.count = 0; - m.lastf = null; - m.last = MATCH.nomatch; - } -} - /* ======================== Type ============================================ */ /**** @@ -3173,18 +974,17 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param return IDX_NOTFOUND; } -private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) +size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { - if (tparam.ty == Tident) + if (TypeIdentifier tident = tparam.isTypeIdentifier()) { - TypeIdentifier tident = cast(TypeIdentifier)tparam; //printf("\ttident = '%s'\n", tident.toChars()); return templateIdentifierLookup(tident.ident, parameters); } return IDX_NOTFOUND; } -private ubyte deduceWildHelper(Type t, Type* at, Type tparam) +ubyte deduceWildHelper(Type t, Type* at, Type tparam) { if ((tparam.mod & MODFlags.wild) == 0) return 0; @@ -3267,7 +1067,7 @@ private Type rawTypeMerge(Type t1, Type t2) return null; } -private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) +MATCH deduceTypeHelper(Type t, out Type at, Type tparam) { // 9*9 == 81 cases @@ -3297,7 +1097,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(U) shared(inout(const(T))) => shared(inout(const(T))) // foo(U) immutable(T) => immutable(T) { - *at = t; + at = t; return MATCH.exact; } case X(MODFlags.const_, MODFlags.const_): @@ -3317,7 +1117,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) shared(inout(const(T))) => T // foo(immutable(U)) immutable(T) => T { - *at = t.mutableOf().unSharedOf(); + at = t.mutableOf().unSharedOf(); return MATCH.exact; } case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_): @@ -3327,7 +1127,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(inout(U)) shared(inout(T)) => shared(T) // foo(inout(const(U))) shared(inout(const(T))) => shared(T) { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.exact; } case X(MODFlags.const_, 0): @@ -3345,13 +1145,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(const(U)) immutable(T) => T // foo(shared(const(U))) immutable(T) => T { - *at = t.mutableOf(); + at = t.mutableOf(); return MATCH.constant; } case X(MODFlags.const_, MODFlags.shared_): // foo(const(U)) shared(T) => shared(T) { - *at = t; + at = t; return MATCH.constant; } case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_): @@ -3361,13 +1161,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(U)) shared(inout(T)) => inout(T) // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.exact; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_): // foo(shared(const(U))) shared(T) => T { - *at = t.unSharedOf(); + at = t.unSharedOf(); return MATCH.constant; } case X(MODFlags.wildconst, MODFlags.immutable_): @@ -3379,13 +1179,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) // foo(shared(inout(const(U)))) immutable(T) => T // foo(shared(inout(const(U)))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild): // foo(shared(const(U))) shared(inout(T)) => T { - *at = t.unSharedOf().mutableOf(); + at = t.unSharedOf().mutableOf(); return MATCH.constant; } case X(MODFlags.wild, 0): @@ -3499,30 +1299,16 @@ __gshared Expression emptyArrayElement = null; * Output: * dedtypes = [ int ] // Array of Expression/Type's */ -MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) +MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false) { extern (C++) final class DeduceType : Visitor { alias visit = Visitor.visit; public: - Scope* sc; - Type tparam; - TemplateParameters* parameters; - Objects* dedtypes; - uint* wm; - size_t inferStart; - bool ignoreAliasThis; MATCH result; - extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe + extern (D) this() @safe { - this.sc = sc; - this.tparam = tparam; - this.parameters = parameters; - this.dedtypes = dedtypes; - this.wm = wm; - this.inferStart = inferStart; - this.ignoreAliasThis = ignoreAliasThis; result = MATCH.nomatch; } @@ -3537,7 +1323,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (tparam.ty == Tident) { // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, parameters); + size_t i = templateParameterLookup(tparam, ¶meters); if (i == IDX_NOTFOUND) { if (!sc) @@ -3548,7 +1334,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3561,9 +1347,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateParameter tp = (*parameters)[i]; + TemplateParameter tp = parameters[i]; - TypeIdentifier tident = cast(TypeIdentifier)tparam; + TypeIdentifier tident = tparam.isTypeIdentifier(); if (tident.idents.length > 0) { //printf("matching %s to %s\n", tparam.toChars(), t.toChars()); @@ -3601,21 +1387,21 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Type tt = s.getType(); if (!tt) goto Lnomatch; - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; if (at && at.ty == Tnone) at = (cast(TypeDeduced)at).tded; if (!at || tt.equals(at)) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; goto Lexact; } } if (tp.isTemplateAliasParameter()) { - Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i]; + Dsymbol s2 = cast(Dsymbol)dedtypes[i]; if (!s2 || s == s2) { - (*dedtypes)[i] = s; + dedtypes[i] = s; goto Lexact; } } @@ -3637,7 +1423,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param +/ if (auto ta = tp.isTemplateAliasParameter()) { - (*dedtypes)[i] = t; + dedtypes[i] = t; goto Lexact; } // (23578) - ensure previous behaviour for non-alias template params @@ -3646,14 +1432,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; *wm |= wx; result = MATCH.constant; return; @@ -3662,11 +1448,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; if (result > MATCH.constant) result = MATCH.constant; // limit level for inout matches } @@ -3676,29 +1462,29 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs type if (tt.equals(at)) { - (*dedtypes)[i] = tt; // Prefer current type match + dedtypes[i] = tt; // Prefer current type match goto Lconst; } if (tt.implicitConvTo(at.constOf())) { - (*dedtypes)[i] = at.constOf().mutableOf(); + dedtypes[i] = at.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } if (at.implicitConvTo(tt.constOf())) { - (*dedtypes)[i] = tt.constOf().mutableOf(); + dedtypes[i] = tt.constOf().mutableOf(); *wm |= MODFlags.const_; goto Lconst; } goto Lnomatch; } - else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(t, tt, tparam)) { // type vs (none) if (!at) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = m; return; } @@ -3706,11 +1492,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // type vs expressions if (at.ty == Tnone) { - TypeDeduced xt = cast(TypeDeduced)at; + auto xt = cast(TypeDeduced)at; result = xt.matchAll(tt); if (result > MATCH.nomatch) { - (*dedtypes)[i] = tt; + dedtypes[i] = tt; } return; } @@ -3740,7 +1526,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Loc loc; if (parameters.length) { - TemplateParameter tp = (*parameters)[0]; + TemplateParameter tp = parameters[0]; loc = tp.loc; } @@ -3757,9 +1543,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param MATCH m = t.implicitConvTo(tparam); if (m == MATCH.nomatch && !ignoreAliasThis) { - if (t.ty == Tclass) + if (auto tc = t.isTypeClass()) { - TypeClass tc = cast(TypeClass)t; if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3770,9 +1555,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } } - else if (t.ty == Tstruct) + else if (auto ts = t.isTypeStruct()) { - TypeStruct ts = cast(TypeStruct)t; if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT)) { if (auto ato = t.aliasthisOf()) @@ -3822,9 +1606,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(TypeVector t) { - if (tparam.ty == Tvector) + if (auto tp = tparam.isTypeVector()) { - TypeVector tp = cast(TypeVector)tparam; result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm); return; } @@ -3851,25 +1634,23 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateParameter tp = null; Expression edim = null; size_t i; - if (tparam.ty == Tsarray) + if (auto tsa = tparam.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)tparam; if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { Identifier id = tsa.dim.isVarExp().var.ident; - i = templateIdentifierLookup(id, parameters); + i = templateIdentifierLookup(id, ¶meters); assert(i != IDX_NOTFOUND); - tp = (*parameters)[i]; + tp = parameters[i]; } else edim = tsa.dim; } - else if (tparam.ty == Taarray) + else if (auto taa = tparam.isTypeAArray()) { - TypeAArray taa = cast(TypeAArray)tparam; - i = templateParameterLookup(taa.index, parameters); + i = templateParameterLookup(taa.index, ¶meters); if (i != IDX_NOTFOUND) - tp = (*parameters)[i]; + tp = parameters[i]; else { Loc loc; @@ -3878,7 +1659,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // so we use that for the resolution (better error message). if (inferStart < parameters.length) { - TemplateParameter loctp = (*parameters)[inferStart]; + TemplateParameter loctp = parameters[inferStart]; loc = loctp.loc; } @@ -3889,7 +1670,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param edim = s ? getValue(s) : getValue(e); } } - if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) + if (tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) { result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); return; @@ -3903,7 +1684,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check that index type must match if (tparam && tparam.ty == Taarray) { - TypeAArray tp = cast(TypeAArray)tparam; + TypeAArray tp = tparam.isTypeAArray(); if (!deduceType(t.index, sc, tp.index, parameters, dedtypes)) { result = MATCH.nomatch; @@ -3936,7 +1717,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // https://issues.dlang.org/show_bug.cgi?id=15243 // Resolve parameter type if it's not related with template parameters - if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length])) + if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length])) { auto tx = fparam.type.typeSemantic(Loc.initial, sc); if (tx.ty == Terror) @@ -3948,7 +1729,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - size_t nfargs = t.parameterList.length; + const size_t nfargs = t.parameterList.length; size_t nfparams = tp.parameterList.length; /* See if tuple match @@ -3963,7 +1744,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param assert(fparam.type); if (fparam.type.ty != Tident) goto L1; - TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); if (tid.idents.length) goto L1; @@ -3974,7 +1755,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param { if (tupi == parameters.length) goto L1; - TemplateParameter tx = (*parameters)[tupi]; + TemplateParameter tx = parameters[tupi]; TemplateTupleParameter tup = tx.isTemplateTupleParameter(); if (tup && tup.ident.equals(tid.ident)) break; @@ -3987,7 +1768,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* See if existing tuple, and whether it matches or not */ - RootObject o = (*dedtypes)[tupi]; + RootObject o = dedtypes[tupi]; if (o) { // Existing deduced argument must be a tuple, and must match @@ -4016,7 +1797,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param Parameter arg = t.parameterList[nfparams - 1 + i]; tup.objects[i] = arg.type; } - (*dedtypes)[tupi] = tup; + dedtypes[tupi] = tup; } nfparams--; // don't consider the last parameter for type deduction goto L2; @@ -4053,7 +1834,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tident) { - TypeIdentifier tp = cast(TypeIdentifier)tparam; + TypeIdentifier tp = tparam.isTypeIdentifier(); for (size_t i = 0; i < t.idents.length; i++) { RootObject id1 = t.idents[i]; @@ -4076,7 +1857,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration(); assert(tempdecl); - TypeInstance tp = cast(TypeInstance)tparam; + TypeInstance tp = tparam.isTypeInstance(); //printf("tempinst.tempdecl = %p\n", tempdecl); //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl); @@ -4087,7 +1868,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Handle case of: * template Foo(T : sa!(T), alias sa) */ - size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); + size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking @@ -4132,15 +1913,15 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param goto Lnomatch; } - TemplateParameter tpx = (*parameters)[i]; - if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null)) + TemplateParameter tpx = parameters[i]; + if (!tpx.matchArg(sc, tempdecl, i, ¶meters, dedtypes, null)) goto Lnomatch; } else if (tempdecl != tp.tempinst.tempdecl) goto Lnomatch; L2: - if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes)) + if (!resolveTemplateInstantiation(sc, ¶meters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes)) goto Lnomatch; } visit(cast(Type)t); @@ -4151,198 +1932,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param result = MATCH.nomatch; } - /******************** - * Match template `parameters` to the target template instance. - * Example: - * struct Temp(U, int Z) {} - * void foo(T)(Temp!(T, 3)); - * foo(Temp!(int, 3)()); - * Input: - * this.parameters = template params of foo -> [T] - * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3] - * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3] - * tempdecl = <struct Temp!(T, int Z)> -> [T, Z] - * tp = <Temp!(T, 3)> - * Output: - * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] - */ - private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) - { - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst.tiargs[%zu]\n", i); - RootObject o1 = null; - if (i < tiargs.length) - o1 = (*tiargs)[i]; - else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) - { - // Pick up default arg - o1 = (*tdtypes)[i]; - } - else if (i >= tp.tempinst.tiargs.length) - break; - //printf("\ttest: o1 = %s\n", o1.toChars()); - if (i >= tp.tempinst.tiargs.length) - { - size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); - while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) - { - i++; - } - if (i >= dim) - break; // match if all remained parameters are dependent - return false; - } - - RootObject o2 = (*tp.tempinst.tiargs)[i]; - Type t2 = isType(o2); - //printf("\ttest: o2 = %s\n", o2.toChars()); - size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) - ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; - if (j != IDX_NOTFOUND && j == parameters.length - 1 && - (*parameters)[j].isTemplateTupleParameter()) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (is(X Y == A!(Z), Z...)) {} - * deduce that Z is a tuple(int, float) - */ - - /* Create tuple from remaining args - */ - size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; - auto vt = new Tuple(vtdim); - for (size_t k = 0; k < vtdim; k++) - { - RootObject o; - if (k < tiargs.length) - o = (*tiargs)[i + k]; - else // Pick up default arg - o = (*tdtypes)[i + k]; - vt.objects[k] = o; - } - - Tuple v = cast(Tuple)(*dedtypes)[j]; - if (v) - { - if (!match(v, vt)) - return false; - } - else - (*dedtypes)[j] = vt; - break; - } - else if (!o1) - break; - - Type t1 = isType(o1); - Dsymbol s1 = isDsymbol(o1); - Dsymbol s2 = isDsymbol(o2); - Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); - Expression e2 = isExpression(o2); - version (none) - { - Tuple v1 = isTuple(o1); - Tuple v2 = isTuple(o2); - if (t1) - printf("t1 = %s\n", t1.toChars()); - if (t2) - printf("t2 = %s\n", t2.toChars()); - if (e1) - printf("e1 = %s\n", e1.toChars()); - if (e2) - printf("e2 = %s\n", e2.toChars()); - if (s1) - printf("s1 = %s\n", s1.toChars()); - if (s2) - printf("s2 = %s\n", s2.toChars()); - if (v1) - printf("v1 = %s\n", v1.toChars()); - if (v2) - printf("v2 = %s\n", v2.toChars()); - } - - if (t1 && t2) - { - if (!deduceType(t1, sc, t2, parameters, dedtypes)) - return false; - } - else if (e1 && e2) - { - Le: - e1 = e1.ctfeInterpret(); - - /* If it is one of the template parameters for this template, - * we should not attempt to interpret it. It already has a value. - */ - if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); - if (j != IDX_NOTFOUND) - goto L1; - // The template parameter was not from this template - // (it may be from a parent template, for example) - } - - e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 - e2 = e2.ctfeInterpret(); - - //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); - //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); - if (!e1.equals(e2)) - { - if (!e2.implicitConvTo(e1.type)) - return false; - - e2 = e2.implicitCastTo(sc, e1.type); - e2 = e2.ctfeInterpret(); - if (!e1.equals(e2)) - return false; - } - } - else if (e1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (e2) - goto Le; - return false; - } - if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) - return false; - } - else if (s1 && s2) - { - Ls: - if (!s1.equals(s2)) - return false; - } - else if (s1 && t2 && t2.ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == IDX_NOTFOUND) - { - t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); - if (s2) - goto Ls; - return false; - } - if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) - return false; - } - else - return false; - } - return true; - } - override void visit(TypeStruct t) { /* If this struct is a template struct, and we're matching @@ -4368,7 +1957,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4391,7 +1980,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tstruct) { - TypeStruct tp = cast(TypeStruct)tparam; + TypeStruct tp = tparam.isTypeStruct(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4410,7 +1999,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tenum) { - TypeEnum tp = cast(TypeEnum)tparam; + TypeEnum tp = tparam.isTypeEnum(); if (t.sym == tp.sym) visit(cast(Type)t); else @@ -4428,59 +2017,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param visit(cast(Type)t); } - /* Helper for TypeClass.deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ - static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches) - { - TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - auto tmpdedtypes = new Objects(dedtypes.length); - memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); - - auto t = new TypeInstance(Loc.initial, parti); - MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); - if (m > MATCH.nomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches == 0) - memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); - else - for (size_t k = 0; k < tmpdedtypes.length; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if ((*tmpdedtypes)[k] != (*best)[k]) - (*best)[k] = (*dedtypes)[k]; - } - ++numBaseClassMatches; - } - } - - // Now recursively test the inherited interfaces - foreach (ref bi; b.baseInterfaces) - { - deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); - } - } - override void visit(TypeClass t) { //printf("TypeClass.deduceType(this = %s)\n", t.toChars()); @@ -4509,7 +2045,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* Match things like: * S!(T).foo */ - TypeInstance tpi = cast(TypeInstance)tparam; + TypeInstance tpi = tparam.isTypeInstance(); if (tpi.idents.length) { RootObject id = tpi.idents[tpi.idents.length - 1]; @@ -4547,12 +2083,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param while (s && s.baseclasses.length > 0) { // Test the base class - deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); // Test the interfaces inherited by the base class foreach (b; s.interfaces) { - deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches); } s = (*s.baseclasses)[0].sym; } @@ -4572,7 +2108,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Extra check if (tparam && tparam.ty == Tclass) { - TypeClass tp = cast(TypeClass)tparam; + TypeClass tp = tparam.isTypeClass(); //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp)); if (wm && t.deduceWild(tparam, false)) @@ -4589,8 +2125,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); - size_t i = templateParameterLookup(tparam, parameters); - if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0) + size_t i = templateParameterLookup(tparam, ¶meters); + if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) { @@ -4602,13 +2138,13 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return; } - TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter(); + TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter(); if (!tp) return; // nomatch if (e == emptyArrayElement) { - if ((*dedtypes)[i]) + if (dedtypes[i]) { result = MATCH.exact; return; @@ -4630,14 +2166,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param tb.ty == Tstruct && tb.hasPointers(); } - Type at = cast(Type)(*dedtypes)[i]; + Type at = cast(Type)dedtypes[i]; Type tt; if (ubyte wx = deduceWildHelper(e.type, &tt, tparam)) { *wm |= wx; result = MATCH.constant; } - else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam)) + else if (MATCH m = deduceTypeHelper(e.type, tt, tparam)) { result = m; } @@ -4658,7 +2194,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // expression vs (none) if (!at) { - (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); + dedtypes[i] = new TypeDeduced(tt, e, tparam); return; } @@ -4716,7 +2252,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(tt, e, tparam); else - (*dedtypes)[i] = tt; + dedtypes[i] = tt; result = match1; return; } @@ -4736,7 +2272,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (xt) xt.update(t, e, tparam); else - (*dedtypes)[i] = t; + dedtypes[i] = t; pt = tt.addMod(tparam.mod); if (*wm) @@ -4870,7 +2406,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Parameter types inference from 'tof' assert(e.td._scope); - TypeFunction tf = cast(TypeFunction)e.fd.type; + TypeFunction tf = e.fd.type.isTypeFunction(); //printf("\ttof = %s\n", tof.toChars()); //printf("\ttf = %s\n", tf.toChars()); const dim = tf.parameterList.length; @@ -4895,7 +2431,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (!pto) break; Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774 - if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length])) + if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length])) return; t = t.typeSemantic(e.loc, sc); if (t.ty == Terror) @@ -4929,7 +2465,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // Allow conversion from implicit function pointer to delegate if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate) { - TypeFunction tf = cast(TypeFunction)t.nextOf(); + TypeFunction tf = t.nextOf().isTypeFunction(); t = (new TypeDelegate(tf)).merge(); } //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars()); @@ -4959,7 +2495,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param } } - scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis); + scope DeduceType v = new DeduceType(); if (Type t = isType(o)) t.accept(v); else if (Expression e = isExpression(o)) @@ -4972,6 +2508,254 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param return v.result; } + +/* Helper for TypeClass.deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches) +{ + TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + auto tmpdedtypes = new Objects(dedtypes.length); + memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof); + + auto t = new TypeInstance(Loc.initial, parti); + MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes); + if (m > MATCH.nomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches == 0) + memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof); + else + for (size_t k = 0; k < tmpdedtypes.length; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if ((*tmpdedtypes)[k] != best[k]) + best[k] = dedtypes[k]; + } + ++numBaseClassMatches; + } + } + + // Now recursively test the inherited interfaces + foreach (ref bi; b.baseInterfaces) + { + deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); + } +} + +/******************** + * Match template `parameters` to the target template instance. + * Example: + * struct Temp(U, int Z) {} + * void foo(T)(Temp!(T, 3)); + * foo(Temp!(int, 3)()); + * Input: + * sc = context + * parameters = template params of foo -> [T] + * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3] + * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3] + * tempdecl = <struct Temp!(T, int Z)> -> [T, Z] + * tp = <Temp!(T, 3)> + * Output: + * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int] + */ +private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes) +{ + for (size_t i = 0; 1; i++) + { + //printf("\ttest: tempinst.tiargs[%zu]\n", i); + RootObject o1 = null; + if (i < tiargs.length) + o1 = (*tiargs)[i]; + else if (i < tdtypes.length && i < tp.tempinst.tiargs.length) + { + // Pick up default arg + o1 = (*tdtypes)[i]; + } + else if (i >= tp.tempinst.tiargs.length) + break; + //printf("\ttest: o1 = %s\n", o1.toChars()); + if (i >= tp.tempinst.tiargs.length) + { + size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); + while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) + { + i++; + } + if (i >= dim) + break; // match if all remained parameters are dependent + return false; + } + + RootObject o2 = (*tp.tempinst.tiargs)[i]; + Type t2 = isType(o2); + //printf("\ttest: o2 = %s\n", o2.toChars()); + size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1) + ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; + if (j != IDX_NOTFOUND && j == parameters.length - 1 && + (*parameters)[j].isTemplateTupleParameter()) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (is(X Y == A!(Z), Z...)) {} + * deduce that Z is a tuple(int, float) + */ + + /* Create tuple from remaining args + */ + size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i; + auto vt = new Tuple(vtdim); + for (size_t k = 0; k < vtdim; k++) + { + RootObject o; + if (k < tiargs.length) + o = (*tiargs)[i + k]; + else // Pick up default arg + o = (*tdtypes)[i + k]; + vt.objects[k] = o; + } + + Tuple v = cast(Tuple)(*dedtypes)[j]; + if (v) + { + if (!match(v, vt)) + return false; + } + else + (*dedtypes)[j] = vt; + break; + } + else if (!o1) + break; + + Type t1 = isType(o1); + Dsymbol s1 = isDsymbol(o1); + Dsymbol s2 = isDsymbol(o2); + Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); + Expression e2 = isExpression(o2); + version (none) + { + Tuple v1 = isTuple(o1); + Tuple v2 = isTuple(o2); + if (t1) + printf("t1 = %s\n", t1.toChars()); + if (t2) + printf("t2 = %s\n", t2.toChars()); + if (e1) + printf("e1 = %s\n", e1.toChars()); + if (e2) + printf("e2 = %s\n", e2.toChars()); + if (s1) + printf("s1 = %s\n", s1.toChars()); + if (s2) + printf("s2 = %s\n", s2.toChars()); + if (v1) + printf("v1 = %s\n", v1.toChars()); + if (v2) + printf("v2 = %s\n", v2.toChars()); + } + + if (t1 && t2) + { + if (!deduceType(t1, sc, t2, *parameters, *dedtypes)) + return false; + } + else if (e1 && e2) + { + Le: + e1 = e1.ctfeInterpret(); + + /* If it is one of the template parameters for this template, + * we should not attempt to interpret it. It already has a value. + */ + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); + if (j != IDX_NOTFOUND) + goto L1; + // The template parameter was not from this template + // (it may be from a parent template, for example) + } + + e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 + e2 = e2.ctfeInterpret(); + + //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); + //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); + if (!e1.equals(e2)) + { + if (!e2.implicitConvTo(e1.type)) + return false; + + e2 = e2.implicitCastTo(sc, e1.type); + e2 = e2.ctfeInterpret(); + if (!e1.equals(e2)) + return false; + } + } + else if (e1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (e2) + goto Le; + return false; + } + if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null)) + return false; + } + else if (s1 && s2) + { + Ls: + if (!s1.equals(s2)) + return false; + } + else if (s1 && t2 && t2.ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == IDX_NOTFOUND) + { + t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2); + if (s2) + goto Ls; + return false; + } + if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null)) + return false; + } + else + return false; + } + return true; +} + + /*********************************************************** * Check whether the type t representation relies on one or more the template parameters. * Params: @@ -4991,7 +2775,7 @@ bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0) * t = Tested type, if null, returns false. * tparams = Template parameters. */ -private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams) +bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams) { bool visitVector(TypeVector t) { @@ -5625,7 +3409,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter if (e) { e = e.syntaxCopy(); - if ((e = e.expressionSemantic(sc)) is null) + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; + e = e.expressionSemantic(sc2); + sc2.pop(); + if (e is null) return null; if (auto te = e.isTemplateExp()) { @@ -6029,9 +3817,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol return "template instance"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { - *ps = null; + ps = null; return true; } @@ -6176,7 +3964,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars()); - if (!arrayObjectMatch(&tdtypes, &ti.tdtypes)) + if (!arrayObjectMatch(tdtypes, ti.tdtypes)) goto Lnotequals; /* Template functions may have different instantiations based on @@ -6221,7 +4009,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!hash) { hash = cast(size_t)cast(void*)enclosing; - hash += arrayObjectHash(&tdtypes); + hash += arrayObjectHash(tdtypes); hash += hash == 0; } return hash; @@ -6465,7 +4253,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol */ Identifier id = name; Dsymbol scopesym; - Dsymbol s = sc.search(loc, id, &scopesym); + Dsymbol s = sc.search(loc, id, scopesym); if (!s) { s = sc.search_correct(id); @@ -6691,6 +4479,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!tiargs) return true; bool err = false; + + // The arguments are not treated as part of a default argument, + // because they are evaluated at compile time. + sc = sc.push(); + sc.inDefaultArg = false; + for (size_t j = 0; j < tiargs.length; j++) { RootObject o = (*tiargs)[j]; @@ -6716,10 +4510,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol } Ltype: - if (ta.ty == Ttuple) + if (TypeTuple tt = ta.isTypeTuple()) { // Expand tuple - TypeTuple tt = cast(TypeTuple)ta; size_t dim = tt.arguments.length; tiargs.remove(j); if (dim) @@ -6912,7 +4705,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } FuncDeclaration fd = sa.isFuncDeclaration(); if (fd) - fd.functionSemantic(); + functionSemantic(fd); } else if (isParameter(o)) { @@ -6923,6 +4716,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); } + sc.pop(); version (none) { printf("-TemplateInstance.semanticTiargs()\n"); @@ -6982,7 +4776,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2)) + if (!matchWithInstance(sc, tempdecl, this, tdtypes, argumentList, 2)) { .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars); return false; @@ -7032,7 +4826,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0); + MATCH m = matchWithInstance(sc, td, this, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7041,8 +4835,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol // Disambiguate by picking the most specialized TemplateDeclaration { - MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); - MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -7140,7 +4934,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol // Only one template, so we can give better error message const(char)* msg = "does not match template declaration"; const(char)* tip; - const tmsg = tdecl.toCharsNoConstraints(); + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(tdecl, buf, hgs); + const tmsg = buf.peekChars(); const cmsg = tdecl.getConstraintEvalError(tip); if (cmsg) { @@ -7158,7 +4956,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol // print additional information, e.g. `foo` is not a type foreach (i, param; *tdecl.parameters) { - MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null); + MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null); auto arg = (*tiargs)[i]; auto sym = arg.isDsymbol; auto exp = arg.isExpression; @@ -7262,7 +5060,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol * to instantiate the template. */ //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length); - auto tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); if (tf.parameterList.length) { auto tp = td.isVariadic(); @@ -7308,7 +5106,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol return 1; } } - MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0); + MATCH m = matchWithInstance(sc, td, this, dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -7546,7 +5344,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol { TemplateParameter tp = (*tempdecl.parameters)[i]; //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl.declareParameter(sc, tp, o); + declareParameter(tempdecl, sc, tp, o); } } @@ -7599,7 +5397,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (members.length) { Dsymbol sa; - if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa) + if (Dsymbol.oneMembers(members, sa, tempdecl.ident) && sa) aliasdecl = sa; } done = true; @@ -7820,7 +5618,7 @@ extern (C++) final class TemplateMixin : TemplateInstance return "mixin"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { return Dsymbol.oneMember(ps, ident); } @@ -7831,15 +5629,6 @@ extern (C++) final class TemplateMixin : TemplateInstance return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("TemplateMixin.setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, null); // try to resolve it - - members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } ); - } - override const(char)* toChars() const { OutBuffer buf; @@ -8001,7 +5790,7 @@ struct TemplateInstanceBox * dedtypes[] deduced arguments to template instance * *psparam set to symbol declared and initialized to dedtypes[i] */ -MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8024,7 +5813,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si { assert(i < dedtypes.length); // It might have already been deduced - oarg = (*dedtypes)[i]; + oarg = dedtypes[i]; if (!oarg) return matchArgNoMatch(); } @@ -8040,7 +5829,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si assert(i + 1 == dedtypes.length); // must be the last one Tuple ovar; - if (Tuple u = isTuple((*dedtypes)[i])) + if (Tuple u = isTuple(dedtypes[i])) { // It has already been deduced ovar = u; @@ -8068,7 +5857,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si return matchArgParameter(); } -MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) +MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam) { MATCH matchArgNoMatch() { @@ -8096,7 +5885,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars()); - MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes); + MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes); if (m2 == MATCH.nomatch) { //printf("\tfailed deduceType\n"); @@ -8105,9 +5894,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ if (m2 < m) m = m2; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357 return matchArgNoMatch(); @@ -8122,10 +5911,10 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced type - Type t = cast(Type)(*dedtypes)[i]; + Type t = cast(Type)dedtypes[i]; if (!t.equals(ta)) { @@ -8139,7 +5928,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ m = MATCH.convert; } } - (*dedtypes)[i] = ta; + dedtypes[i] = ta; if (psparam) *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta); @@ -8244,15 +6033,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } else { - if ((*dedtypes)[i]) + if (dedtypes[i]) { // Must match already deduced value - Expression e = cast(Expression)(*dedtypes)[i]; + Expression e = cast(Expression)dedtypes[i]; if (!ei || !ei.equals(e)) return matchArgNoMatch(); } } - (*dedtypes)[i] = ei; + dedtypes[i] = ei; if (psparam) { @@ -8363,7 +6152,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ return matchArgNoMatch(); Type t = new TypeInstance(Loc.initial, ti); - MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); + MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes); if (m2 == MATCH.nomatch) return matchArgNoMatch(); } @@ -8384,14 +6173,14 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ } } } - else if ((*dedtypes)[i]) + else if (dedtypes[i]) { // Must match already deduced symbol - RootObject si = (*dedtypes)[i]; + RootObject si = dedtypes[i]; if (!sa || si != sa) return matchArgNoMatch(); } - (*dedtypes)[i] = sa; + dedtypes[i] = sa; if (psparam) { @@ -8424,15 +6213,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ Tuple ovar = isTuple(oarg); if (!ovar) return MATCH.nomatch; - if ((*dedtypes)[i]) + if (dedtypes[i]) { - Tuple tup = isTuple((*dedtypes)[i]); + Tuple tup = isTuple(dedtypes[i]); if (!tup) return MATCH.nomatch; if (!match(tup, ovar)) return MATCH.nomatch; } - (*dedtypes)[i] = ovar; + dedtypes[i] = ovar; if (psparam) *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects); @@ -8466,21 +6255,24 @@ struct TemplateStats /******************************* * Add this instance + * Params: + * td = template declaration + * ti = instance of td + * listInstances = keep track of instances of templates */ static void incInstance(const TemplateDeclaration td, - const TemplateInstance ti) + const TemplateInstance ti, + bool listInstances) { void log(ref TemplateStats ts) { if (ts.allInstances is null) ts.allInstances = new TemplateInstances(); - if (global.params.v.templatesListInstances) + if (listInstances) ts.allInstances.push(cast() ti); } - // message(ti.loc, "incInstance %p %p", td, ti); - if (!global.params.v.templates) - return; + // message(ti.loc, "incInstance %p %p", td, ti); if (!td) return; assert(ti); @@ -8503,8 +6295,6 @@ struct TemplateStats const TemplateInstance ti) { // message(ti.loc, "incUnique %p %p", td, ti); - if (!global.params.v.templates) - return; if (!td) return; assert(ti); @@ -8515,7 +6305,13 @@ struct TemplateStats } } -extern (C++) void printTemplateStats() +/******************************** + * Print informational statistics on template instantiations. + * Params: + * listInstances = list instances of templates + * eSink = where the print is sent + */ +extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) { static struct TemplateDeclarationStats { @@ -8532,11 +6328,12 @@ extern (C++) void printTemplateStats() } } - if (!global.params.v.templates) - return; + const stats_length = TemplateStats.stats.length; + if (!stats_length) + return; // nothing to report Array!(TemplateDeclarationStats) sortedStats; - sortedStats.reserve(TemplateStats.stats.length); + sortedStats.reserve(stats_length); foreach (td_, ref ts; TemplateStats.stats) { sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts)); @@ -8544,37 +6341,42 @@ extern (C++) void printTemplateStats() sortedStats.sort!(TemplateDeclarationStats.compare); + OutBuffer buf; foreach (const ref ss; sortedStats[]) { - if (global.params.v.templatesListInstances && - ss.ts.allInstances) + buf.reset(); + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(ss.td, buf, hgs); + const tchars = buf.peekChars(); + if (listInstances && ss.ts.allInstances) { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, - ss.td.toCharsNoConstraints()); + tchars); foreach (const ti; (*ss.ts.allInstances)[]) { if (ti.tinst) // if has enclosing instance - message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars()); else - message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); + eSink.message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars()); } } else { - message(ss.td.loc, + eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, - ss.td.toCharsNoConstraints()); + tchars); } } } /// Pair of MATCHes -private struct MATCHpair +struct MATCHpair { MATCH mta; /// match template parameters by initial template arguments MATCH mfa; /// match template parameters by inferred template arguments @@ -8588,7 +6390,7 @@ private struct MATCHpair } } -private void write(ref OutBuffer buf, RootObject obj) +void write(ref OutBuffer buf, RootObject obj) { if (obj) { diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 9f85574..4a1ff05 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -2,7 +2,7 @@ * This module contains the implementation of the C++ header generation available through * the command line switch -Hc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) @@ -30,6 +30,7 @@ import dmd.location; import dmd.root.filename; import dmd.visitor; import dmd.tokens; +import dmd.typesem; import dmd.common.outbuffer; import dmd.utils; @@ -779,6 +780,17 @@ public: } } + if (tf && tf.next) + { + // Ensure return type is declared before a function that returns that is declared. + if (auto sty = tf.next.isTypeStruct()) + ensureDeclared(sty.sym); + //else if (auto cty = tf.next.isTypeClass()) + // includeSymbol(cty.sym); // classes are returned by pointer only need to forward declare + //else if (auto ety = tf.next.isTypeEnum()) + // ensureDeclared(ety.sym); + } + writeProtection(fd.visibility.kind); if (tf && tf.linkage == LINK.c) @@ -3284,7 +3296,7 @@ ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t) @safe */ ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name) { - if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors)) + if (auto mem = sym.search(Loc.initial, name, ASTCodegen.SearchOpt.ignoreErrors)) return mem; // search doesn't work for declarations inside of uninstantiated diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d index 31725c8..2e3b352 100644 --- a/gcc/d/dmd/dversion.d +++ b/gcc/d/dmd/dversion.d @@ -4,7 +4,7 @@ * Specification: $(LINK2 https://dlang.org/spec/version.html#version-specification, Version Specification), * $(LINK2 https://dlang.org/spec/version.html#debug_specification, Debug Specification). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d) diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d index c31883f..af74c3b 100644 --- a/gcc/d/dmd/entity.d +++ b/gcc/d/dmd/entity.d @@ -3,7 +3,7 @@ * * Specification $(LINK2 https://dlang.org/spec/entity.html, Named Character Entities) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d) diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index 5f91ead..650bf3e 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -46,14 +46,12 @@ public: bool inuse(bool v); EnumDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; Type *getType() override; const char *kind() const override; bool isDeprecated() const override; // is Dsymbol deprecated? Visibility visible() override; bool isSpecial() const; - Expression *getDefaultValue(const Loc &loc); - Type *getMemtype(const Loc &loc); EnumDeclaration *isEnumDeclaration() override { return this; } diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d new file mode 100644 index 0000000..3886ca2 --- /dev/null +++ b/gcc/d/dmd/enumsem.d @@ -0,0 +1,720 @@ +/** + * Does the semantic passes on enums. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/enumsem.d, _enumsem.d) + * Documentation: https://dlang.org/phobos/dmd_enumsem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/enumsem.d + */ + +module dmd.enumsem; + +import core.stdc.stdio; +import core.stdc.string; + +import dmd.aggregate; +import dmd.aliasthis; +import dmd.arraytypes; +import dmd.astcodegen; +import dmd.astenums; +import dmd.attrib; +import dmd.blockexit; +import dmd.clone; +import dmd.cond; +import dmd.compiler; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.denum; +import dmd.dimport; +import dmd.dinterpret; +import dmd.dmangle; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.dversion; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.expressionsem; +import dmd.func; +import dmd.funcsem; +import dmd.globals; +import dmd.id; +import dmd.identifier; +import dmd.importc; +import dmd.init; +import dmd.initsem; +import dmd.intrange; +import dmd.hdrgen; +import dmd.location; +import dmd.mtype; +import dmd.mustuse; +import dmd.nogc; +import dmd.nspace; +import dmd.objc; +import dmd.opover; +import dmd.optimize; +import dmd.parse; +import dmd.root.array; +import dmd.root.filename; +import dmd.common.outbuffer; +import dmd.root.rmem; +import dmd.rootobject; +import dmd.root.utf; +import dmd.semantic2; +import dmd.semantic3; +import dmd.sideeffect; +import dmd.statementsem; +import dmd.staticassert; +import dmd.tokens; +import dmd.utils; +import dmd.statement; +import dmd.target; +import dmd.templateparamsem; +import dmd.typesem; +import dmd.visitor; + + +/********************************* + * Perform semantic analysis on enum declaration `em` + */ +void enumSemantic(Scope* sc, EnumDeclaration ed) +{ + //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); + //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); + if (ed.semanticRun >= PASS.semanticdone) + return; // semantic() already completed + if (ed.semanticRun == PASS.semantic) + { + assert(ed.memtype); + error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); + ed.errors = true; + ed.semanticRun = PASS.semanticdone; + return; + } + Scope* scx = null; + if (ed._scope) + { + sc = ed._scope; + scx = ed._scope; // save so we don't make redundant copies + ed._scope = null; + } + + if (!sc) + return; + + ed.parent = sc.parent; + ed.type = ed.type.typeSemantic(ed.loc, sc); + + ed.visibility = sc.visibility; + if (sc.stc & STC.deprecated_) + ed.isdeprecated = true; + ed.userAttribDecl = sc.userAttribDecl; + ed.cppnamespace = sc.namespace; + + ed.semanticRun = PASS.semantic; + UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); + checkMustUseReserved(ed); + + if (!ed.members && !ed.memtype) // enum ident; + { + ed.semanticRun = PASS.semanticdone; + return; + } + + if (!ed.symtab) + ed.symtab = new DsymbolTable(); + + /* The separate, and distinct, cases are: + * 1. enum { ... } + * 2. enum : memtype { ... } + * 3. enum ident { ... } + * 4. enum ident : memtype { ... } + * 5. enum ident : memtype; + * 6. enum ident; + */ + + if (ed.memtype) + { + ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); + + /* Check to see if memtype is forward referenced + */ + if (auto te = ed.memtype.isTypeEnum()) + { + auto sym = te.toDsymbol(sc).isEnumDeclaration(); + // Special enums like __c_[u]long[long] are fine to forward reference + // see https://issues.dlang.org/show_bug.cgi?id=20599 + if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) + { + // memtype is forward referenced, so try again later + deferDsymbolSemantic(sc, ed, scx); + //printf("\tdeferring %s\n", toChars()); + ed.semanticRun = PASS.initial; + return; + } + else + // Ensure that semantic is run to detect. e.g. invalid forward references + sym.dsymbolSemantic(sc); + } + if (ed.memtype.ty == Tvoid) + { + .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars); + ed.memtype = Type.terror; + } + if (ed.memtype.ty == Terror) + { + ed.errors = true; + // poison all the members + ed.members.foreachDsymbol( (s) { s.errors = true; } ); + ed.semanticRun = PASS.semanticdone; + return; + } + } + + if (!ed.members) // enum ident : memtype; + { + ed.semanticRun = PASS.semanticdone; + return; + } + + if (ed.members.length == 0) + { + .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars()); + ed.errors = true; + ed.semanticRun = PASS.semanticdone; + return; + } + + if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done + ed.semanticRun = PASS.semanticdone; + + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } + + Scope* sce; + if (ed.isAnonymous()) + sce = sc; + else + { + sce = sc.push(ed); + sce.parent = ed; + } + sce = sce.startCTFE(); + sce.setNoFree(); // needed for getMaxMinValue() + + /* Each enum member gets the sce scope + */ + ed.members.foreachDsymbol( (s) + { + EnumMember em = s.isEnumMember(); + if (em) + em._scope = sce; + }); + + /* addMember() is not called when the EnumDeclaration appears as a function statement, + * so we have to do what addMember() does and install the enum members in the right symbol + * table + */ + addEnumMembersToSymtab(ed, sc, sc.getScopesym()); + + if (sc.flags & SCOPE.Cfile) + { + /* C11 6.7.2.2 + */ + Type commonType = ed.memtype; + if (!commonType) + commonType = Type.tint32; + ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 + + // C11 6.7.2.2-2 value must be representable as an int. + // The sizemask represents all values that int will fit into, + // from 0..uint.max. We want to cover int.min..uint.max. + IntRange ir = IntRange.fromType(commonType); + + void emSemantic(EnumMember em, ref ulong nextValue) + { + static void errorReturn(EnumMember em) + { + em.value = ErrorExp.get(); + em.errors = true; + em.semanticRun = PASS.semanticdone; + } + + em.semanticRun = PASS.semantic; + em.type = commonType; + em._linkage = LINK.c; + em.storage_class |= STC.manifest; + if (em.value) + { + Expression e = em.value; + assert(e.dyncast() == DYNCAST.expression); + + /* To merge the type of e with commonType, add 0 of type commonType + */ + if (!ed.memtype) + e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); + + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.integralPromotions(sc); + e = e.ctfeInterpret(); + if (e.op == EXP.error) + return errorReturn(em); + auto ie = e.isIntegerExp(); + if (!ie) + { + // C11 6.7.2.2-2 + .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars()); + return errorReturn(em); + } + if (ed.memtype && !ir.contains(getIntRange(ie))) + { + // C11 6.7.2.2-2 + .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars()); + return errorReturn(em); + } + nextValue = ie.toInteger(); + if (!ed.memtype) + commonType = e.type; + em.value = new IntegerExp(em.loc, nextValue, commonType); + } + else + { + // C11 6.7.2.2-3 add 1 to value of previous enumeration constant + bool first = (em == (*em.ed.members)[0]); + if (!first) + { + Expression max = getProperty(commonType, null, em.loc, Id.max, 0); + if (nextValue == max.toInteger()) + { + .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars()); + return errorReturn(em); + } + nextValue += 1; + } + em.value = new IntegerExp(em.loc, nextValue, commonType); + } + em.type = commonType; + em.semanticRun = PASS.semanticdone; + } + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + emSemantic(em, nextValue); + }); + + if (!ed.memtype) + { + // cast all members to commonType + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + { + em.type = commonType; + em.value = em.value.castTo(sc, commonType); + } + }); + } + + ed.memtype = commonType; + ed.semanticRun = PASS.semanticdone; + return; + } + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + em.dsymbolSemantic(em._scope); + }); + //printf("ed.defaultval = %lld\n", ed.defaultval); + + //if (ed.defaultval) printf("ed.defaultval: %s %s\n", ed.defaultval.toChars(), ed.defaultval.type.toChars()); + //printf("members = %s\n", members.toChars()); +} + +Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc) +{ + Expression handleErrors(){ + ed.defaultval = ErrorExp.get(); + return ed.defaultval; + } + //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); + // https://issues.dlang.org/show_bug.cgi?id=23904 + // Return ed.defaultval only if it is not ErrorExp. + // A speculative context may set ed.defaultval to ErrorExp; + // subsequent non-speculative contexts need to be able + // to print the error. + if (ed.defaultval && !ed.defaultval.isErrorExp()) + return ed.defaultval; + + if (ed.isCsymbol()) + return ed.memtype.defaultInit(loc, true); + + if (ed._scope) + dsymbolSemantic(ed, ed._scope); + if (ed.errors) + return handleErrors(); + if (!ed.members) + { + if (ed.isSpecial()) + { + /* Allow these special enums to not need a member list + */ + return ed.defaultval = ed.memtype.defaultInit(loc); + } + + error(loc, "%s `%s` is opaque and has no default initializer", ed.kind, ed.toPrettyChars); + return handleErrors(); + } + + foreach (const i; 0 .. ed.members.length) + { + EnumMember em = (*ed.members)[i].isEnumMember(); + if (em) + { + if (em.semanticRun < PASS.semanticdone) + { + error(loc, "%s `%s` forward reference of `%s.init`", ed.kind, ed.toPrettyChars, ed.toChars()); + return handleErrors(); + } + + ed.defaultval = em.value; + return ed.defaultval; + } + } + return handleErrors(); +} + +Type getMemtype(EnumDeclaration ed, const ref Loc loc) +{ + if (ed._scope) + { + /* Enum is forward referenced. We don't need to resolve the whole thing, + * just the base type + */ + if (ed.memtype) + { + Loc locx = loc.isValid() ? loc : ed.loc; + ed.memtype = ed.memtype.typeSemantic(locx, ed._scope); + } + else + { + // Run semantic to get the type from a possible first member value + dsymbolSemantic(ed, ed._scope); + } + } + if (!ed.memtype) + { + if (!ed.isAnonymous() && (ed.members || ed.semanticRun >= PASS.semanticdone)) + ed.memtype = Type.tint32; + else + { + Loc locx = loc.isValid() ? loc : ed.loc; + error(locx, "is forward referenced looking for base type"); + return Type.terror; + } + } + return ed.memtype; +} + +/********************************* + * Perform semantic analysis on enum member `em` + */ +void enumMemberSemantic(Scope* sc, EnumMember em) +{ + //printf("EnumMember::semantic() %s\n", em.toChars()); + + void errorReturn() + { + em.errors = true; + em.semanticRun = PASS.semanticdone; + } + + if (em.errors || em.semanticRun >= PASS.semanticdone) + return; + if (em.semanticRun == PASS.semantic) + { + .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars); + return errorReturn(); + } + assert(em.ed); + + em.ed.dsymbolSemantic(sc); + if (em.ed.errors) + return errorReturn(); + if (em.errors || em.semanticRun >= PASS.semanticdone) + return; + + if (em._scope) + sc = em._scope; + if (!sc) + return; + + em.semanticRun = PASS.semantic; + + em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); + em._linkage = LINK.d; + em.storage_class |= STC.manifest; + + // https://issues.dlang.org/show_bug.cgi?id=9701 + if (em.ed.isAnonymous()) + { + if (em.userAttribDecl) + em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; + else + em.userAttribDecl = em.ed.userAttribDecl; + } + + // Eval UDA in this same scope. Issues 19344, 20835, 21122 + if (em.userAttribDecl) + { + // Set scope but avoid extra sc.uda attachment inside setScope() + auto inneruda = em.userAttribDecl.userAttribDecl; + em.userAttribDecl.setScope(sc); + em.userAttribDecl.userAttribDecl = inneruda; + em.userAttribDecl.dsymbolSemantic(sc); + } + + // The first enum member is special + bool first = (em == (*em.ed.members)[0]); + + if (em.origType) + { + em.origType = em.origType.typeSemantic(em.loc, sc); + em.type = em.origType; + assert(em.value); // "type id;" is not a valid enum member declaration + } + + if (em.value) + { + Expression e = em.value; + assert(e.dyncast() == DYNCAST.expression); + if (em.ed.memtype) + e = inferType(e, em.ed.memtype); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.ctfeInterpret(); + if (e.op == EXP.error) + return errorReturn(); + if (first && !em.ed.memtype && !em.ed.isAnonymous()) + { + em.ed.memtype = e.type; + if (em.ed.memtype.ty == Terror) + { + em.ed.errors = true; + return errorReturn(); + } + if (em.ed.memtype.ty != Terror) + { + /* https://issues.dlang.org/show_bug.cgi?id=11746 + * All of named enum members should have same type + * with the first member. If the following members were referenced + * during the first member semantic, their types should be unified. + */ + em.ed.members.foreachDsymbol( (s) + { + EnumMember enm = s.isEnumMember(); + if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) + return; + + //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); + Expression ev = enm.value; + ev = ev.implicitCastTo(sc, em.ed.memtype); + ev = ev.ctfeInterpret(); + ev = ev.castTo(sc, em.ed.type); + if (ev.op == EXP.error) + em.ed.errors = true; + enm.value = ev; + }); + + if (em.ed.errors) + { + em.ed.memtype = Type.terror; + return errorReturn(); + } + } + } + + if (em.ed.memtype && !em.origType) + { + e = e.implicitCastTo(sc, em.ed.memtype); + e = e.ctfeInterpret(); + + // save origValue for better json output + em.origValue = e; + + if (!em.ed.isAnonymous()) + { + e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 + e = e.ctfeInterpret(); + } + } + else if (em.origType) + { + e = e.implicitCastTo(sc, em.origType); + e = e.ctfeInterpret(); + assert(em.ed.isAnonymous()); + + // save origValue for better json output + em.origValue = e; + } + em.value = e; + // https://issues.dlang.org/show_bug.cgi?id=24311 + // First enum member is .init value, which gets put into static segment + if (first) + lowerStaticAAs(e, sc); + } + else if (first) + { + Type t; + if (em.ed.memtype) + t = em.ed.memtype; + else + { + t = Type.tint32; + if (!em.ed.isAnonymous()) + em.ed.memtype = t; + } + const errors = global.startGagging(); + Expression e = new IntegerExp(em.loc, 0, t); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate 0 value of type `%s` for `%s`", + t.toChars(), em.toChars()); + } + // save origValue for better json output + em.origValue = e; + + if (!em.ed.isAnonymous()) + { + e = e.castTo(sc, em.ed.type); + e = e.ctfeInterpret(); + } + em.value = e; + } + else + { + /* Find the previous enum member, + * and set this to be the previous value + 1 + */ + EnumMember emprev = null; + em.ed.members.foreachDsymbol( (s) + { + if (auto enm = s.isEnumMember()) + { + if (enm == em) + return 1; // found + emprev = enm; + } + return 0; // continue + }); + + assert(emprev); + if (emprev.semanticRun < PASS.semanticdone) // if forward reference + emprev.dsymbolSemantic(emprev._scope); // resolve it + if (emprev.errors) + return errorReturn(); + + auto errors = global.startGagging(); + Expression eprev = emprev.value; + assert(eprev); + // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 + Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) + ? em.ed.memtype + : eprev.type; + /* + https://issues.dlang.org/show_bug.cgi?id=20777 + Previously this used getProperty, which doesn't consider anything user defined, + this construct does do that and thus fixes the bug. + */ + Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + emax = emax.expressionSemantic(sc); + emax = emax.ctfeInterpret(); + + // check that (eprev != emax) + Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); + e = e.expressionSemantic(sc); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + // display an introductory error before showing what actually failed + error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); + // rerun to show errors + Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + } + // now any errors are for generating a value + if (e.toInteger()) + { + auto mt = em.ed.memtype; + if (!mt) + mt = eprev.type; + .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, + emprev.ed.toChars(), emprev.toChars(), mt.toChars()); + return errorReturn(); + } + errors = global.startGagging(); + // Now set e to (eprev + 1) + e = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e = e.expressionSemantic(sc); + e = e.castTo(sc, eprev.type); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); + // rerun to show errors + Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e2 = e2.expressionSemantic(sc); + e2 = e2.castTo(sc, eprev.type); + e2 = e2.ctfeInterpret(); + } + // save origValue (without cast) for better json output + if (e.op != EXP.error) // avoid duplicate diagnostics + { + assert(emprev.origValue); + em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); + em.origValue = em.origValue.expressionSemantic(sc); + em.origValue = em.origValue.ctfeInterpret(); + } + + if (e.op == EXP.error) + return errorReturn(); + if (e.type.isfloating()) + { + // Check that e != eprev (not always true for floats) + Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); + etest = etest.expressionSemantic(sc); + etest = etest.ctfeInterpret(); + if (etest.toInteger()) + { + .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars); + return errorReturn(); + } + } + em.value = e; + } + if (!em.origType) + em.type = em.value.type; + + assert(em.origValue); + em.semanticRun = PASS.semanticdone; +} diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index 542b97b..79efc6e 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -1,7 +1,7 @@ /** * Functions for raising errors. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d) diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h index 759ad27..308e81e 100644 --- a/gcc/d/dmd/errors.h +++ b/gcc/d/dmd/errors.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d index ce23517..afea689 100644 --- a/gcc/d/dmd/errorsink.d +++ b/gcc/d/dmd/errorsink.d @@ -1,7 +1,7 @@ /** * Provides an abstraction for what to do with error messages. * - * Copyright: Copyright (C) 2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2023-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d) @@ -61,6 +61,20 @@ class ErrorSinkNull : ErrorSink } /***************************************** + * Ignores the messages, but sets `sawErrors` for any calls to `error()` + */ +class ErrorSinkLatch : ErrorSinkNull +{ + nothrow: + extern (C++): + override: + + bool sawErrors; + + void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; } +} + +/***************************************** * Simplest implementation, just sends messages to stderr. * See also: ErrorSinkCompiler. */ diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index f928b08..3e17ff4 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -1,7 +1,7 @@ /** * Most of the logic to implement scoped pointers and scoped references is here. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/escape.d, _escape.d) @@ -34,6 +34,7 @@ import dmd.mtype; import dmd.printast; import dmd.rootobject; import dmd.tokens; +import dmd.typesem : hasPointers, parameterStorageClass; import dmd.visitor; import dmd.arraytypes; @@ -1296,7 +1297,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { if (log) { - printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class))); + printf("byref `%s` %s\n", v.toChars(), ScopeRefToChars(buildScopeRef(v.storage_class))); } // 'featureState' tells us whether to emit an error or a deprecation, diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index cd93e54..82de837 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d) @@ -21,7 +21,6 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; import dmd.dclass; import dmd.declaration; import dmd.dimport; @@ -49,6 +48,7 @@ import dmd.root.string; import dmd.root.utf; import dmd.target; import dmd.tokens; +import dmd.typesem; import dmd.visitor; enum LOGSEMANTIC = false; @@ -191,39 +191,6 @@ extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null) } /**************************************** - * Expand alias this tuples. - */ -TupleDeclaration isAliasThisTuple(Expression e) -{ - if (!e.type) - return null; - - Type t = e.type.toBasetype(); - while (true) - { - if (Dsymbol s = t.toDsymbol(null)) - { - if (auto ad = s.isAggregateDeclaration()) - { - s = ad.aliasthis ? ad.aliasthis.sym : null; - if (s && s.isVarDeclaration()) - { - TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); - if (td && td.isexp) - return td; - } - if (Type att = t.aliasthisOf()) - { - t = att; - continue; - } - } - } - return null; - } -} - -/**************************************** * If `s` is a function template, i.e. the only member of a template * and that member is a function, return that template. * Params: @@ -421,10 +388,7 @@ extern (C++) abstract class Expression : ASTNode override const(char)* toChars() const { - OutBuffer buf; - HdrGenState hgs; - toCBuffer(this, buf, hgs); - return buf.extractChars(); + return .toChars(this); } /********************************** @@ -758,6 +722,7 @@ extern (C++) abstract class Expression : ASTNode 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(InterpExp) isInterpExp() { return op == EXP.interpolated ? 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; } @@ -1536,6 +1501,7 @@ extern (C++) final class StringExp : Expression char* string; // if sz == 1 wchar* wstring; // if sz == 2 dchar* dstring; // if sz == 4 + ulong* lstring; // if sz == 8 } // (const if ownedByCtfe == OwnedBy.code) size_t len; // number of code units ubyte sz = 1; // 1: char, 2: wchar, 4: dchar @@ -1699,6 +1665,13 @@ extern (C++) final class StringExp : Expression */ dchar getCodeUnit(size_t i) const pure { + assert(this.sz <= dchar.sizeof); + return cast(dchar) getIndex(i); + } + + /// Returns: integer at index `i` + dinteger_t getIndex(size_t i) const pure + { assert(i < len); final switch (sz) { @@ -1708,6 +1681,8 @@ extern (C++) final class StringExp : Expression return wstring[i]; case 4: return dstring[i]; + case 8: + return lstring[i]; } } @@ -1719,6 +1694,11 @@ extern (C++) final class StringExp : Expression */ extern (D) void setCodeUnit(size_t i, dchar c) { + return setIndex(i, c); + } + + extern (D) void setIndex(size_t i, long c) + { assert(i < len); final switch (sz) { @@ -1729,7 +1709,10 @@ extern (C++) final class StringExp : Expression wstring[i] = cast(wchar)c; break; case 4: - dstring[i] = c; + dstring[i] = cast(dchar) c; + break; + case 8: + lstring[i] = c; break; } } @@ -1884,6 +1867,28 @@ extern (C++) final class StringExp : Expression } } +extern (C++) final class InterpExp : Expression +{ + char postfix = NoPostfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe = OwnedBy.code; + InterpolatedSet* interpolatedSet; + + enum char NoPostfix = 0; + + extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope + { + super(loc, EXP.interpolated); + this.interpolatedSet = set; + this.postfix = postfix; + } + + override void accept(Visitor v) + { + v.visit(this); + } +} + + /*********************************************************** * A sequence of expressions * @@ -2240,7 +2245,7 @@ extern (C++) final class StructLiteralExp : Expression // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after union { - Symbol* sym; /// back end symbol to initialize with literal + void* sym; /// back end symbol to initialize with literal (used as a Symbol*) /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. StructLiteralExp inlinecopy; @@ -3847,7 +3852,7 @@ extern (C++) final class CastExp : UnaExp if (!e1.isLvalue()) return false; return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) || - e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf()); + e1.type.mutableOf.unSharedOf().equals(to.mutableOf().unSharedOf()); } override void accept(Visitor v) @@ -5531,6 +5536,7 @@ private immutable ubyte[EXP.max+1] expSize = [ EXP.preMinusMinus: __traits(classInstanceSize, PreExp), EXP.identifier: __traits(classInstanceSize, IdentifierExp), EXP.string_: __traits(classInstanceSize, StringExp), + EXP.interpolated: __traits(classInstanceSize, InterpExp), EXP.this_: __traits(classInstanceSize, ThisExp), EXP.super_: __traits(classInstanceSize, SuperExp), EXP.halt: __traits(classInstanceSize, HaltExp), diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index b4ace74b..f713d25 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -38,6 +38,7 @@ class TemplateDeclaration; class ClassDeclaration; class OverloadSet; class StringExp; +class InterpExp; class LoweredAssignExp; #ifdef IN_GCC typedef union tree_node Symbol; @@ -54,6 +55,7 @@ Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc); MATCH implicitConvTo(Expression *e, Type *t); Expression *toLvalue(Expression *_this, Scope *sc, const char* action); Expression *modifiableLvalue(Expression* exp, Scope *sc); +Expression *optimize(Expression *exp, int result, bool keepLvalue = false); typedef unsigned char OwnedBy; enum @@ -107,8 +109,6 @@ public: Expression *addressOf(); Expression *deref(); - Expression *optimize(int result, bool keepLvalue = false); - int isConst(); virtual bool isIdentical(const Expression *e) const; virtual Optional<bool> toBool(); @@ -129,6 +129,7 @@ public: SuperExp* isSuperExp(); NullExp* isNullExp(); StringExp* isStringExp(); + InterpExp* isInterpExp(); TupleExp* isTupleExp(); ArrayLiteralExp* isArrayLiteralExp(); AssocArrayLiteralExp* isAssocArrayLiteralExp(); @@ -352,7 +353,7 @@ class StringExp final : public Expression public: utf8_t postfix; // 'c', 'w', 'd' OwnedBy ownedByCtfe; - void *string; // char, wchar, or dchar data + void *string; // char, wchar, dchar, or long data size_t len; // number of chars, wchars, or dchars unsigned char sz; // 1: char, 2: wchar, 4: dchar d_bool committed; // if type is committed @@ -362,6 +363,7 @@ public: static StringExp *create(const Loc &loc, const void *s, d_size_t len); bool equals(const RootObject * const o) const override; char32_t getCodeUnit(d_size_t i) const; + dinteger_t getIndex(d_size_t i) const; StringExp *toStringExp() override; Optional<bool> toBool() override; bool isLvalue() override; @@ -370,6 +372,16 @@ public: void writeTo(void* dest, bool zero, int tyto = 0) const; }; +class InterpExp final : public Expression +{ +public: + utf8_t postfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe; + void* interpolatedSet; + + void accept(Visitor* v) override { v->visit(this); } +}; + // Tuple class TupleExp final : public Expression @@ -434,7 +446,7 @@ public: union { - Symbol *sym; // back end symbol to initialize with literal + Symbol *sym; // back end symbol to initialize with literal (used as a Symbol*) // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. StructLiteralExp *inlinecopy; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 1664bf2..d7377db 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d) @@ -42,10 +42,12 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.errorsink; +import dmd.enumsem; import dmd.escape; import dmd.expression; import dmd.file_manager; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -83,6 +85,7 @@ import dmd.traits; import dmd.typesem; import dmd.typinf; import dmd.utils; +import dmd.utils : arrayCastBigEndian; import dmd.visitor; enum LOGSEMANTIC = false; @@ -384,7 +387,6 @@ private Expression reorderSettingAAElem(BinExp exp, Scope* sc) return Expression.combine(e0, be); } - private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) { auto e1 = binExp.e1; @@ -563,6 +565,39 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) return e0; } +/**************************************** + * Expand alias this tuples. + */ +TupleDeclaration isAliasThisTuple(Expression e) +{ + if (!e.type) + return null; + + Type t = e.type.toBasetype(); + while (true) + { + if (Dsymbol s = t.toDsymbol(null)) + { + if (auto ad = s.isAggregateDeclaration()) + { + s = ad.aliasthis ? ad.aliasthis.sym : null; + if (s && s.isVarDeclaration()) + { + TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); + if (td && td.isexp) + return td; + } + if (Type att = t.aliasthisOf()) + { + t = att; + continue; + } + } + } + return null; + } +} + /************************************** * Runs semantic on ae.arguments. Declares temporary variables * if '$' was used. @@ -875,7 +910,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) Loc loc = ue.loc; // TODO: merge with Scope.search.searchScopes() - Dsymbol searchScopes(int flags) + Dsymbol searchScopes(SearchOptFlags flags) { Dsymbol s = null; for (Scope* scx = sc; scx; scx = scx.enclosing) @@ -883,7 +918,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) if (!scx.scopesym) continue; if (scx.scopesym.isModule()) - flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed s = scx.scopesym.search(loc, ident, flags); if (s) { @@ -910,18 +945,18 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) return s; } - int flags = 0; + SearchOptFlags flags = SearchOpt.all; Dsymbol s; if (sc.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; // First look in local scopes - s = searchScopes(flags | SearchLocalsOnly); + s = searchScopes(flags | SearchOpt.localsOnly); if (!s) { // Second look in imported modules - s = searchScopes(flags | SearchImportsOnly); + s = searchScopes(flags | SearchOpt.importsOnly); } if (!s) @@ -1547,7 +1582,7 @@ Lagain: if (auto f = s.isFuncDeclaration()) { f = f.toAliasFunc(); - if (!f.functionSemantic()) + if (!functionSemantic(f)) return ErrorExp.get(); if (!hasOverloads && f.checkForwardRef(loc)) @@ -2834,7 +2869,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, // If inferring return type, and semantic3() needs to be run if not already run if (!tf.next && fd.inferRetType) { - fd.functionSemantic(); + functionSemantic(fd); } else if (fd && fd.parent) { @@ -3743,7 +3778,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Dsymbol scopesym; - Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); + Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) { if (s.errors) @@ -4113,6 +4148,84 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; } + override void visit(InterpExp e) + { + // the lexer breaks up into an odd/even array of literals and expression code + // we need to turn that into: + /+ + tuple( + .object.imported!"core.interpolation".InterpolationHeader(), + ... + .object.imported!"core.interpolation".InterpolationFooter() + ) + + There the ... loops through them all, making the even ones + .object.imported!"core.interpolation".InterpolatedLiteral!str() + and making the odd ones + .object.imported!"core.interpolation".InterpolatedExpression!str(), + the code represented by str + + Empty string literals are skipped as they provide no additional information. + +/ + + if (e.postfix) + error(e.loc, "String postfixes on interpolated expression sequences are not allowed."); + + Expression makeNonTemplateItem(Identifier which) { + Expression id = new IdentifierExp(e.loc, Id.empty); + id = new DotIdExp(e.loc, id, Id.object); + auto moduleNameArgs = new Objects(); + moduleNameArgs.push(new StringExp(e.loc, "core.interpolation")); + id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs); + id = new DotIdExp(e.loc, id, which); + id = new CallExp(e.loc, id, new Expressions()); + return id; + } + + Expression makeTemplateItem(Identifier which, string arg) { + Expression id = new IdentifierExp(e.loc, Id.empty); + id = new DotIdExp(e.loc, id, Id.object); + auto moduleNameArgs = new Objects(); + moduleNameArgs.push(new StringExp(e.loc, "core.interpolation")); + id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs); + auto tiargs = new Objects(); + auto templateStringArg = new StringExp(e.loc, arg); + // banning those instead of forwarding them + // templateStringArg.postfix = e.postfix; // forward the postfix to these literals + tiargs.push(templateStringArg); + id = new DotTemplateInstanceExp(e.loc, id, which, tiargs); + id = new CallExp(e.loc, id, new Expressions()); + return id; + } + + auto arguments = new Expressions(); + arguments.push(makeNonTemplateItem(Id.InterpolationHeader)); + + foreach (idx, str; e.interpolatedSet.parts) + { + if (idx % 2 == 0) + { + if (str.length > 0) + arguments.push(makeTemplateItem(Id.InterpolatedLiteral, str)); + } + else + { + arguments.push(makeTemplateItem(Id.InterpolatedExpression, str)); + Expressions* mix = new Expressions(); + mix.push(new StringExp(e.loc, str)); + // FIXME: i'd rather not use MixinExp but idk how to do it lol + arguments.push(new MixinExp(e.loc, mix)); + } + } + + arguments.push(makeNonTemplateItem(Id.InterpolationFooter)); + + auto loweredTo = new TupleExp(e.loc, arguments); + visit(loweredTo); + + result = loweredTo; + } + override void visit(StringExp e) { static if (LOGSEMANTIC) @@ -4130,7 +4243,33 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor size_t u; dchar c; - switch (e.postfix) + if (e.hexString) + { + const data = cast(const ubyte[]) e.peekString(); + switch (e.postfix) + { + case 'd': + e.sz = 4; + e.type = Type.tdstring; + break; + case 'w': + e.sz = 2; + e.type = Type.twstring; + break; + case 'c': + default: + e.type = Type.tstring; + e.sz = 1; + break; + } + if ((e.len % e.sz) != 0) + error(e.loc, "hex string with `%s` type needs to be multiple of %d bytes, not %d", + e.type.toChars(), e.sz, cast(int) e.len); + + e.setData(arrayCastBigEndian(data, e.sz).ptr, e.len / e.sz, e.sz); + e.committed = true; + } + else switch (e.postfix) { case 'd': for (u = 0; u < e.len;) @@ -5115,7 +5254,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (global.params.betterC || !sc.needsCodegen()) + if (!global.params.useGC && sc.needsCodegen()) + { + version(IN_GCC) + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars()); + else + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars()); + return setError(); + } + + if (!sc.needsCodegen()) goto LskipNewArrayLowering; /* Class types may inherit base classes that have errors. @@ -5325,7 +5473,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (fd) { //printf("L%d fd = %s\n", __LINE__, f.toChars()); - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return setError(); } @@ -6142,7 +6290,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto ad2 = b.sym; ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); ue.e1 = ue.e1.expressionSemantic(sc); - auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length); + auto vi = findVtblIndex(exp.f, ad2.vtbl[]); assert(vi >= 0); exp.f = ad2.vtbl[vi].isFuncDeclaration(); assert(exp.f); @@ -6432,8 +6580,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + void errorHelper(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6447,8 +6594,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); - return setError(); } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch) + return setError(); + // Purity and safety check should run after testing arguments matching if (exp.f) { @@ -6505,8 +6655,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; - const(char)* failMessage; - if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) + + void errorHelper2(const(char)* failMessage) scope { OutBuffer buf; buf.writeByte('('); @@ -6521,12 +6671,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match"); } - .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", - exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); + .error(exp.loc, "%s `%s` is not callable using argument types `%s`", + exp.f.kind(), exp.f.toChars(), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); + .errorSupplemental(exp.f.loc, "`%s%s` declared here", exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList)); exp.f = null; } + + if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch) + exp.f = null; } if (!exp.f || exp.f.errors) return setError(); @@ -6744,7 +6898,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -6812,11 +6967,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (sc.func.fes) { - deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + deprecationSupplemental(s2.loc, "declared here"); + } else { error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + errorSupplemental(s2.loc, "declared here"); return setError(); } } @@ -6986,7 +7144,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (!tup && !sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -7036,7 +7195,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc2.tinst = null; sc2.minst = null; sc2.flags |= SCOPE.fullinst; - Type t = e.targ.trySemantic(e.loc, sc2); + Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2); sc2.pop(); if (!t) // errors, so condition is false return no(); @@ -7266,7 +7425,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Objects dedtypes = Objects(e.parameters.length); dedtypes.zero(); - MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); + MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal); if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) { @@ -7287,13 +7446,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TemplateParameter tp = (*e.parameters)[i]; Declaration s = null; - m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); + m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s); if (m == MATCH.nomatch) return no(); s.dsymbolSemantic(sc); if (!sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -7431,7 +7591,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = (cast(BinExp)e).reorderSettingAAElem(sc); } - private Expression compileIt(MixinExp exp) + private Expression compileIt(MixinExp exp, Scope *sc) { OutBuffer buf; if (expressionsToString(buf, sc, exp.exps)) @@ -7472,7 +7632,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("MixinExp::semantic('%s')\n", exp.toChars()); } - auto e = compileIt(exp); + // The expression is not treated as part of a default argument, + // because it is evaluated at compile time. + Scope* sc2 = sc.push(); + sc2.inDefaultArg = false; + + auto e = compileIt(exp, sc2); + sc2.pop(); if (!e) return setError(); result = e.expressionSemantic(sc); @@ -7491,7 +7657,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor se = se.toUTF8(sc); auto namez = se.toStringz(); - if (!global.filePath) + if (!global.filePath.length) { error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr); return setError(); @@ -7522,12 +7688,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - auto resolvedNamez = FileName.searchPath(global.filePath, namez, false); + auto resolvedNamez = FileName.searchPath(global.filePath[], namez, false); if (!resolvedNamez) { error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):"); - foreach (idx, path; *global.filePath) + foreach (idx, path; global.filePath[]) { const attr = FileName.exists(path); const(char)* err = attr == 2 ? "" : @@ -7569,7 +7735,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { auto fileName = FileName(resolvedNamez); - if (auto fmResult = global.fileManager.lookup(fileName)) + if (auto fmResult = global.fileManager.getFileContents(fileName)) { se = new StringExp(e.loc, fmResult); } @@ -7589,6 +7755,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AssertExp::semantic('%s')\n", exp.toChars()); } + if (auto e = exp.e1.isStringExp()) + { + // deprecated in 2.107 + deprecation(e.loc, "assert condition cannot be a string literal"); + deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour", + e.toChars()); + } const generateMsg = !exp.msg && sc.needsCodegen() && // let ctfe interpreter handle the error message @@ -7708,7 +7881,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // if the assert condition is a mixin expression, try to compile it if (auto ce = exp.e1.isMixinExp()) { - if (auto e1 = compileIt(ce)) + if (auto e1 = compileIt(ce, sc)) exp.e1 = e1; } @@ -8105,7 +8278,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (FuncDeclaration fd = exp.var.isFuncDeclaration()) { // for functions, do checks after overload resolution - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return setError(); /* https://issues.dlang.org/show_bug.cgi?id=13843 @@ -8872,7 +9045,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor bool err = false; if (cd.dtor) { - err |= !cd.dtor.functionSemantic(); + err |= !functionSemantic(cd.dtor); err |= cd.dtor.checkPurity(exp.loc, sc); err |= cd.dtor.checkSafety(exp.loc, sc); err |= cd.dtor.checkNogc(exp.loc, sc); @@ -13911,45 +14084,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("FileInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(LineInitExp e) { e.type = Type.tint32; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(ModuleInitExp e) { //printf("ModuleInitExp::semantic()\n"); e.type = Type.tstring; - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(FuncInitExp e) { //printf("FuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - result = e; + result = e.resolveLoc(e.loc, sc); } override void visit(PrettyFuncInitExp e) { //printf("PrettyFuncInitExp::semantic()\n"); e.type = Type.tstring; - if (sc.func) - { - result = e.resolveLoc(Loc.initial, sc); - return; - } - - result = e; + result = e.resolveLoc(e.loc, sc); } } @@ -14208,15 +14370,15 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) if (auto ie = eright.isScopeExp()) // also used for template alias's { - auto flags = SearchLocalsOnly; + SearchOptFlags flags = SearchOpt.localsOnly; /* Disable access to another module's private imports. * The check for 'is sds our current module' is because * the current module should have access to its own imports. */ if (ie.sds.isModule() && ie.sds != sc._module) - flags |= IgnorePrivateImports; + flags |= SearchOpt.ignorePrivateImports; if (sc.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); /* Check for visibility before resolving aliases because public * aliases to private symbols are public. @@ -14302,7 +14464,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) if (auto f = s.isFuncDeclaration()) { //printf("it's a function\n"); - if (!f.functionSemantic()) + if (!functionSemantic(f)) return ErrorExp.get(); Expression e; if (f.needThis()) @@ -15034,14 +15196,34 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) */ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { + // Don't replace the special keywords, while we are inside a default + // argument. They are replaced later when copied to the call site. + if (sc.inDefaultArg) + return exp; + + exp.loc = loc; + Expression visit(Expression exp) { + if (auto binExp = exp.isBinExp()) + { + binExp.e1 = binExp.e1.resolveLoc(loc, sc); + binExp.e2 = binExp.e2.resolveLoc(loc, sc); + return binExp; + } if (auto unaExp = exp.isUnaExp()) { unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); return unaExp; } - exp.loc = loc; + return exp; + } + + Expression visitCond(CondExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.e2 = exp.e2.resolveLoc(loc, sc); + exp.econd = exp.econd.resolveLoc(loc, sc); return exp; } @@ -15049,6 +15231,109 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) { exp.e1 = exp.e1.resolveLoc(loc, sc); exp.e2 = exp.e2.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + return exp; + } + + Expression visitStructLiteral(StructLiteralExp exp) + { + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitNew(NewExp exp) + { + if (exp.thisexp) + exp.thisexp = exp.thisexp.resolveLoc(loc, sc); + if (exp.argprefix) + exp.argprefix = exp.argprefix.resolveLoc(loc, sc); + if (exp.lowering) + exp.lowering = exp.lowering.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitCall(CallExp exp) + { + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitArray(ArrayExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + + foreach (ref element; *exp.arguments) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitSlice(SliceExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitInterval(IntervalExp exp) + { + exp.lwr = exp.lwr.resolveLoc(loc, sc); + exp.upr = exp.upr.resolveLoc(loc, sc); + + return exp; + } + + Expression visitArrayLiteral(ArrayLiteralExp exp) + { + if (exp.basis) + exp.basis = exp.basis.resolveLoc(loc, sc); + + foreach (ref element; *exp.elements) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + return exp; + } + + Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp) + { + foreach (ref element; *exp.keys) + { + if (element) + element = element.resolveLoc(loc, sc); + } + + foreach (ref element; *exp.values) + { + if (element) + element = element.resolveLoc(loc, sc); + } + return exp; } @@ -15065,20 +15350,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitLineInit(LineInitExp _) + Expression visitLineInit(LineInitExp exp) { Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); return e.expressionSemantic(sc); } - Expression visitModuleInit(ModuleInitExp _) + Expression visitModuleInit(ModuleInitExp exp) { const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); Expression e = new StringExp(loc, s); return e.expressionSemantic(sc); } - Expression visitFuncInit(FuncInitExp _) + Expression visitFuncInit(FuncInitExp exp) { const(char)* s; if (sc.callsc && sc.callsc.func) @@ -15091,7 +15376,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) return e.expressionSemantic(sc); } - Expression visitPrettyFunc(PrettyFuncInitExp _) + Expression visitPrettyFunc(PrettyFuncInitExp exp) { FuncDeclaration fd = (sc.callsc && sc.callsc.func) ? sc.callsc.func @@ -15119,7 +15404,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) switch(exp.op) { default: return visit(exp); + case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp()); + case EXP.new_: return visitNew(exp.isNewExp()); case EXP.concatenate: return visitCat(exp.isCatExp()); + case EXP.call: return visitCall(exp.isCallExp()); + case EXP.question: return visitCond(exp.isCondExp()); + case EXP.array: return visitArray(exp.isArrayExp()); + case EXP.slice: return visitSlice(exp.isSliceExp()); + case EXP.interval: return visitInterval(exp.isIntervalExp()); + case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp()); + case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp()); case EXP.file: case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp()); case EXP.line: return visitLineInit(exp.isLineInitExp); @@ -16038,7 +16332,8 @@ VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f */ bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object) { - auto rootSymbol = sc.search(loc, Id.empty, null); + Dsymbol pscopesym; + auto rootSymbol = sc.search(loc, Id.empty, pscopesym); if (auto moduleSymbol = rootSymbol.search(loc, module_)) if (moduleSymbol.search(loc, id)) return true; @@ -16178,7 +16473,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) em.checkDisabled(loc, sc); if (em.depdecl && !em.depdecl._scope) + { em.depdecl._scope = sc; + em.depdecl._scope.setNoFree(); + } em.checkDeprecated(loc, sc); if (em.errors) diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index a0e5d05..c696a5c 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -1,7 +1,7 @@ /** * Read a file from disk and store it in memory. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d, _file_manager.d) * Documentation: https://dlang.org/phobos/dmd_file_manager.html @@ -10,6 +10,7 @@ module dmd.file_manager; +import core.stdc.stdio; import dmd.root.stringtable : StringTable; import dmd.root.file : File, Buffer; import dmd.root.filename : FileName, isDirSeparator; @@ -71,7 +72,7 @@ private struct PathStack final class FileManager { - private StringTable!(const(ubyte)[]) files; + private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name private StringTable!(bool) packageStatus; // check if the package path of the given path exists. The input path is @@ -246,98 +247,140 @@ nothrow: } /** - * Looks up the given filename from the internal file buffer table. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + * Retrieve the cached contents of the file given by `filename`. + * If the file has not been read before, read it and add the contents + * to the file cache. + * Params: + * filename = the name of the file + * Returns: + * the contents of the file, or `null` if it could not be read or was empty */ - const(ubyte)[] lookup(FileName filename) + const(ubyte)[] getFileContents(FileName filename) { const name = filename.toString; - if (auto val = files.lookup(name)) - return val.value; + if (auto val = files.lookup(name)) // if `name` is cached + return val.value; // return its contents - if (name == "__stdin.d") + if (name == "__stdin.d") // special name for reading from stdin { - auto buffer = readFromStdin().extractSlice(); + const ubyte[] buffer = readFromStdin().extractSlice(); if (this.files.insert(name, buffer) is null) + // this.files already contains the name assert(0, "stdin: Insert after lookup failure should never return `null`"); return buffer; } - if (FileName.exists(name) != 1) + if (FileName.exists(name) != 1) // if not an ordinary file return null; auto readResult = File.read(name); if (!readResult.success) return null; - auto fb = readResult.extractSlice(); + const ubyte[] fb = readResult.extractSlice(); if (files.insert(name, fb) is null) assert(0, "Insert after lookup failure should never return `null`"); return fb; } - /** - * Looks up the given filename from the internal file buffer table, and returns the lines within the file. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + /********************************** + * Take `text` and turn it into an InputRange that emits + * slices into `text` for each line. + * Params: + * text = array of characters + * Returns: + * InputRange accessing `text` as a sequence of lines + * Reference: + * `std.string.splitLines()` */ - const(char)[][] getLines(FileName file) + auto splitLines(const char[] text) { - const(char)[][] lines; - if (const buffer = lookup(file)) + struct Range { - const slice = buffer; - size_t start, end; - for (auto i = 0; i < slice.length; i++) + @safe: + @nogc: + nothrow: + pure: + private: + + const char[] text; + size_t index; // index of start of line + size_t eolIndex; // index of end of line before newline characters + size_t nextIndex; // index past end of line + + public this(const char[] text) { - const c = slice[i]; - if (c == '\n' || c == '\r') + this.text = text; + } + + public bool empty() { return index == text.length; } + + public void popFront() { advance(); index = nextIndex; } + + public const(char)[] front() { advance(); return text[index .. eolIndex]; } + + private void advance() + { + if (index != nextIndex) // if already advanced + return; + + for (size_t i = index; i < text.length; ++i) { - if (i != 0) + switch (text[i]) { - end = i; - // Appending lines one at a time will certainly be slow - lines ~= cast(const(char)[])slice[start .. end]; - } - // Check for Windows-style CRLF newlines - if (c == '\r') - { - if (slice.length > i + 1 && slice[i + 1] == '\n') - { - // This is a CRLF sequence, skip over two characters - start = i + 2; - i++; - } - else - { - // Just a CR sequence - start = i + 1; - } - } - else - { - // The next line should start after the LF sequence - start = i + 1; + case '\v', '\f', '\n': + eolIndex = i; + nextIndex = i + 1; + return; + + case '\r': + if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n" + { + eolIndex = i; + nextIndex = i + 2; + return; + } + eolIndex = i; + nextIndex = i + 1; + return; + + /* Manually decode: + * NEL is C2 85 + */ + case 0xC2: + if (i + 1 < text.length && text[i + 1] == 0x85) + { + eolIndex = i; + nextIndex = i + 2; + return; + } + break; + + /* Manually decode: + * lineSep is E2 80 A8 + * paraSep is E2 80 A9 + */ + case 0xE2: + if (i + 2 < text.length && + text[i + 1] == 0x80 && + (text[i + 2] == 0xA8 || text[i + 2] == 0xA9) + ) + { + eolIndex = i; + nextIndex = i + 3; + return; + } + break; + + default: + break; } } } - - if (slice[$ - 1] != '\r' && slice[$ - 1] != '\n') - { - end = slice.length; - lines ~= cast(const(char)[])slice[start .. end]; - } } - return lines; + return Range(text); } /** diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index dc4b20b..53b3c04 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -1,7 +1,7 @@ /** * Utility to visit every variable in an expression. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 351faa47..ddf21a2 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -8,7 +8,7 @@ * - `invariant` * - `unittest` * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d) @@ -39,6 +39,7 @@ import dmd.dtemplate; import dmd.errors; import dmd.escape; import dmd.expression; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -57,6 +58,7 @@ import dmd.semantic3; import dmd.statement_rewrite_walker; import dmd.statement; import dmd.statementsem; +import dmd.templatesem; import dmd.tokens; import dmd.visitor; @@ -466,185 +468,6 @@ extern (C++) class FuncDeclaration : Declaration return f; } - /**************************************************** - * Resolve forward reference of function signature - - * parameter types, return type, and attributes. - * Returns: - * false if any errors exist in the signature. - */ - final bool functionSemantic() - { - //printf("functionSemantic() %p %s\n", this, toChars()); - if (!_scope) - return !errors; - - this.cppnamespace = _scope.namespace; - - if (!originalType) // semantic not yet run - { - TemplateInstance spec = isSpeculative(); - uint olderrs = global.errors; - uint oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - dsymbolSemantic(this, _scope); - global.gag = oldgag; - if (spec && global.errors != olderrs) - spec.errors = (global.errors - olderrs != 0); - if (olderrs != global.errors) // if errors compiling this function - return false; - } - - // if inferring return type, sematic3 needs to be run - // - When the function body contains any errors, we cannot assume - // the inferred return type is valid. - // So, the body errors should become the function signature error. - if (inferRetType && type && !type.nextOf()) - return functionSemantic3(); - - TemplateInstance ti; - if (isInstantiated() && !isVirtualMethod() && - ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) - { - AggregateDeclaration ad = isMemberLocal(); - if (ad && ad.sizeok != Sizeok.done) - { - /* Currently dmd cannot resolve forward references per methods, - * then setting SIZOKfwd is too conservative and would break existing code. - * So, just stop method attributes inference until ad.dsymbolSemantic() done. - */ - //ad.sizeok = Sizeok.fwd; - } - else - return functionSemantic3() || !errors; - } - - if (storage_class & STC.inference) - return functionSemantic3() || !errors; - - return !errors; - } - - /**************************************************** - * Resolve forward reference of function body. - * Returns false if any errors exist in the body. - */ - final bool functionSemantic3() - { - if (semanticRun < PASS.semantic3 && _scope) - { - /* Forward reference - we need to run semantic3 on this function. - * If errors are gagged, and it's not part of a template instance, - * we need to temporarily ungag errors. - */ - TemplateInstance spec = isSpeculative(); - uint olderrs = global.errors; - uint oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - semantic3(this, _scope); - global.gag = oldgag; - - // If it is a speculatively-instantiated template, and errors occur, - // we need to mark the template as having errors. - if (spec && global.errors != olderrs) - spec.errors = (global.errors - olderrs != 0); - if (olderrs != global.errors) // if errors compiling this function - return false; - } - - return !errors && !this.hasSemantic3Errors(); - } - - /**************************************************** - * Check that this function type is properly resolved. - * If not, report "forward reference error" and return true. - */ - extern (D) final bool checkForwardRef(const ref Loc loc) - { - if (!functionSemantic()) - return true; - - /* No deco means the functionSemantic() call could not resolve - * forward referenes in the type of this function. - */ - if (!type.deco) - { - bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3); - .error(loc, "forward reference to %s`%s`", - (inSemantic3 ? "inferred return type of function " : "").ptr, - toChars()); - return true; - } - return false; - } - - // called from semantic3 - /** - * Creates and returns the hidden parameters for this function declaration. - * - * Hidden parameters include the `this` parameter of a class, struct or - * nested function and the selector parameter for Objective-C methods. - */ - extern (D) final void declareThis(Scope* sc) - { - const bool dualCtx = (toParent2() != toParentLocal()); - if (dualCtx) - this.hasDualContext = true; - auto ad = isThis(); - if (!dualCtx && !ad && !isNested()) - { - vthis = null; - objc.selectorParameter = null; - return; - } - - Type addModStc(Type t) - { - return t.addMod(type.mod).addStorageClass(storage_class); - } - - if (dualCtx || isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - Type tthis = addModStc(dualCtx ? - Type.tvoidptr.sarrayOf(2).pointerTo() : - Type.tvoid.pointerTo()); - vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null); - vthis.storage_class |= STC.parameter | STC.nodtor; - } - else if (ad) - { - Type thandle = addModStc(ad.handleType()); - vthis = new ThisDeclaration(loc, thandle); - vthis.storage_class |= STC.parameter; - if (thandle.ty == Tstruct) - { - vthis.storage_class |= STC.ref_; - } - } - - if (auto tf = type.isTypeFunction()) - { - if (tf.isreturn) - vthis.storage_class |= STC.return_; - if (tf.isScopeQual) - vthis.storage_class |= STC.scope_; - if (tf.isreturnscope) - vthis.storage_class |= STC.returnScope; - } - - vthis.dsymbolSemantic(sc); - if (!sc.insert(vthis)) - assert(0); - vthis.parent = this; - if (ad) - objc.selectorParameter = .objc.createSelectorParameter(this, sc); - } - override final bool equals(const RootObject o) const { if (this == o) @@ -695,6 +518,7 @@ extern (C++) class FuncDeclaration : Declaration int result = 0; if (fd.ident == ident) { + import dmd.typesem : covariant; const cov = type.covariant(fd.type); if (cov != Covariant.distinct) { @@ -707,152 +531,6 @@ extern (C++) class FuncDeclaration : Declaration return result; } - /************************************************* - * Find index of function in vtbl[0..length] that - * this function overrides. - * Prefer an exact match to a covariant one. - * Params: - * vtbl = vtable to use - * dim = maximal vtable dimension - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - final int findVtblIndex(Dsymbols* vtbl, int dim) - { - //printf("findVtblIndex() %s\n", toChars()); - FuncDeclaration mismatch = null; - StorageClass mismatchstc = 0; - int mismatchvi = -1; - int exactvi = -1; - int bestvi = -1; - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration(); - if (fdv && fdv.ident == ident) - { - if (type.equals(fdv.type)) // if exact match - { - if (fdv.parent.isClassDeclaration()) - { - if (fdv.isFuture()) - { - bestvi = vi; - continue; // keep looking - } - return vi; // no need to look further - } - - if (exactvi >= 0) - { - .error(loc, "%s `%s` cannot determine overridden function", kind, toPrettyChars); - return exactvi; - } - exactvi = vi; - bestvi = vi; - continue; - } - - StorageClass stc = 0; - const cov = type.covariant(fdv.type, &stc); - //printf("\tbaseclass cov = %d\n", cov); - final switch (cov) - { - case Covariant.distinct: - // types are distinct - break; - - case Covariant.yes: - bestvi = vi; // covariant, but not identical - break; - // keep looking for an exact match - - case Covariant.no: - mismatchvi = vi; - mismatchstc = stc; - mismatch = fdv; // overrides, but is not covariant - break; - // keep looking for an exact match - - case Covariant.fwdref: - return -2; // forward references - } - } - } - if (_linkage == LINK.cpp && bestvi != -1) - { - StorageClass stc = 0; - FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration(); - assert(fdv && fdv.ident == ident); - if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no) - { - /* https://issues.dlang.org/show_bug.cgi?id=22351 - * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not. - * For now, continue to allow D covariant rules to apply when `override` has been used, - * but issue a deprecation warning that this behaviour will change in the future. - * Otherwise, follow the C++ covariant rules, which will create a new vtable entry. - */ - if (isOverride()) - { - /* @@@DEPRECATED_2.110@@@ - * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch, - * but also the `cppCovariant` parameter from Type.covariant, and update the function - * so that both `LINK.cpp` covariant conditions within are always checked. - */ - .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated", - fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(), - toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars()); - - const char* where = type.isNaked() ? "parameters" : "type"; - deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the " - ~ "overriding function %s", where); - } - else - { - // Treat as if Covariant.no - mismatchvi = bestvi; - mismatchstc = stc; - mismatch = fdv; - bestvi = -1; - } - } - } - if (bestvi == -1 && mismatch) - { - //type.print(); - //mismatch.type.print(); - //printf("%s %s\n", type.deco, mismatch.type.deco); - //printf("stc = %llx\n", mismatchstc); - if (mismatchstc) - { - // Fix it by modifying the type to add the storage classes - type = type.addStorageClass(mismatchstc); - bestvi = mismatchvi; - } - } - return bestvi; - } - - /********************************* - * If function a function in a base class, - * return that base class. - * Returns: - * base class if overriding, null if not - */ - extern (D) final BaseClass* overrideInterface() - { - for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass) - { - foreach (b; cd.interfaces) - { - auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length); - if (v >= 0) - return b; - } - } - return null; - } - /**************************************************** * Overload this FuncDeclaration with the new one f. * Return true if successful; i.e. no conflict. @@ -947,6 +625,7 @@ extern (C++) class FuncDeclaration : Declaration */ if (t.ty == Tfunction) { + import dmd.typesem : covariant; auto tf = cast(TypeFunction)f.type; if (tf.covariant(t) == Covariant.yes && tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant) @@ -1100,20 +779,24 @@ extern (C++) class FuncDeclaration : Declaration } /************************************* - * Determine partial specialization order of 'this' vs g. + * Determine partial specialization order of functions `f` vs `g`. * This is very similar to TemplateDeclaration::leastAsSpecialized(). + * Params: + * f = first function + * g = second function + * names = names of parameters * Returns: * match 'this' is at least as specialized as g * 0 g is more specialized than 'this' */ - final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names) + static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { import core.stdc.stdio : printf; - printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null"); - printf("%s, %s\n", type.toChars(), g.type.toChars()); + printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null"); + printf("%s, %s\n", f.type.toChars(), g.type.toChars()); } /* This works by calling g() with f()'s parameters, and @@ -1121,15 +804,15 @@ extern (C++) class FuncDeclaration : Declaration * as g() is. */ - TypeFunction tf = type.toTypeFunction(); + TypeFunction tf = f.type.toTypeFunction(); TypeFunction tg = g.type.toTypeFunction(); /* If both functions have a 'this' pointer, and the mods are not * the same and g's is not const, then this is less specialized. */ - if (needThis() && g.needThis() && tf.mod != tg.mod) + if (f.needThis() && g.needThis() && tf.mod != tg.mod) { - if (isCtorDeclaration()) + if (f.isCtorDeclaration()) { if (!MODimplicitConv(tg.mod, tf.mod)) return MATCH.nomatch; @@ -1157,6 +840,7 @@ extern (C++) class FuncDeclaration : Declaration args.push(e); } + import dmd.typesem : callMatch; MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); if (m > MATCH.nomatch) { @@ -1190,7 +874,7 @@ extern (C++) class FuncDeclaration : Declaration * * Returns: the `LabelDsymbol` for `ident` */ - final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial) + final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc) { Dsymbol s; if (!labtab) @@ -1466,6 +1150,9 @@ extern (C++) class FuncDeclaration : Declaration final PURE isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + + import dmd.typesem : purityLevel; + TypeFunction tf = type.toTypeFunction(); if (purityInprocess) setImpure(); @@ -1777,6 +1464,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = t.toDsymbol(null).isStructDeclaration(); const tName = t.toChars.toDString; const entry = parentTypes.insert(tName, t); @@ -1858,6 +1546,7 @@ extern (C++) class FuncDeclaration : Declaration case Tstruct: /* Drill down and check the struct's fields */ + import dmd.typesem : toDsymbol; auto sym = tp.toDsymbol(null).isStructDeclaration(); foreach (v; sym.fields) { @@ -2722,6 +2411,7 @@ extern (C++) class FuncDeclaration : Declaration { Type t1 = fdv.type.nextOf().toBasetype(); Type t2 = this.type.nextOf().toBasetype(); + import dmd.typesem : isBaseOf; if (t1.isBaseOf(t2, null)) { /* Making temporary reference variable is necessary @@ -3026,7 +2716,7 @@ Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 // For the correct mangling, // run attribute inference on inv if needed. - inv.functionSemantic(); + functionSemantic(inv); } //e = new DsymbolExp(Loc.initial, inv); @@ -3289,7 +2979,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); } - if (tiargs && arrayObjectIsError(tiargs)) + if (tiargs && arrayObjectIsError(*tiargs)) return null; if (fargs !is null) foreach (arg; *fargs) @@ -3305,7 +2995,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, if (m.count == 1) // exactly one match { if (!(flags & FuncResolveFlag.quiet)) - m.lastf.functionSemantic(); + functionSemantic(m.lastf); return m.lastf; } if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) @@ -3375,12 +3065,18 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, // all of overloads are templates if (td) { - const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`"; if (!od && !td.overnext) - msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`"; - .error(loc, msg, + { + .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`", + td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + else + { + .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + if (!global.gag || global.params.v.showGaggedErrors) printCandidates(loc, td, sc.isDeprecated()); @@ -3436,17 +3132,20 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + bool calledHelper; + void errorHelper(const(char)* failMessage) scope { .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), tf.modToChars(), fargsBuf.peekChars()); errorSupplemental(loc, failMessage); - return null; + calledHelper = true; } + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper); + if (calledHelper) + return null; + if (fd.isCtorDeclaration()) .error(loc, "%s%s `%s` cannot construct a %sobject", funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); @@ -3500,10 +3199,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } } } - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); - if (failMessage) + + void errorHelper2(const(char)* failMessage) scope + { errorSupplemental(loc, failMessage); + } + + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2); } return null; } @@ -3557,7 +3259,11 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (!print) return true; - const tmsg = td.toCharsNoConstraints(); + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(td, buf, hgs); + const tmsg = buf.peekChars(); const cmsg = td.getConstraintEvalError(constraintsTip); // add blank space if there are multiple candidates @@ -3619,6 +3325,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) */ Type getIndirection(Type t) { + import dmd.typesem : hasPointers; t = t.baseElemOf(); if (t.ty == Tarray || t.ty == Tpointer) return t.nextOf().toBasetype(); @@ -3665,6 +3372,7 @@ private bool traverseIndirections(Type ta, Type tb) static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass) { + import dmd.typesem : hasPointers; //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); ta = ta.baseElemOf(); tb = tb.baseElemOf(); @@ -3701,6 +3409,7 @@ private bool traverseIndirections(Type ta, Type tb) else *found = true; + import dmd.typesem : toDsymbol; AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); foreach (v; sym.fields) { @@ -4248,6 +3957,9 @@ extern (C++) class StaticCtorDeclaration : FuncDeclaration */ extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration { + /// Exclude this constructor from cyclic dependency check + bool standalone; + extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, "_sharedStaticCtor", stc); diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d new file mode 100644 index 0000000..9e706ee --- /dev/null +++ b/gcc/d/dmd/funcsem.d @@ -0,0 +1,1369 @@ +/** + * Does semantic analysis for functions. + * + * Specification: $(LINK2 https://dlang.org/spec/function.html, Functions) + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/funcsem.d, _funcsem.d) + * Documentation: https://dlang.org/phobos/dmd_funcsem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/funcsem.d + */ + +module dmd.funcsem; + +import core.stdc.stdio; + +import dmd.aggregate; +import dmd.arraytypes; +import dmd.astenums; +import dmd.attrib; +import dmd.blockexit; +import dmd.gluelayer; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.delegatize; +import dmd.dinterpret; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.func; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.importc; +import dmd.init; +import dmd.location; +import dmd.mtype; +import dmd.mustuse; +import dmd.objc; +import dmd.opover; +import dmd.pragmasem; +import dmd.root.aav; +import dmd.common.outbuffer; +import dmd.rootobject; +import dmd.root.filename; +import dmd.root.string; +import dmd.root.stringtable; +import dmd.semantic2; +import dmd.semantic3; +import dmd.statement_rewrite_walker; +import dmd.statement; +import dmd.statementsem; +import dmd.target; +import dmd.tokens; +import dmd.typesem; +import dmd.visitor; + +/********************************** + * Main semantic routine for functions. + */ +void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl) +{ + version (none) + { + printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage); + if (funcdecl.isFuncLiteralDeclaration()) + printf("\tFuncLiteralDeclaration()\n"); + printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : ""); + printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); + } + + if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration()) + { + /* Member functions that have return types that are + * forward references can have semantic() run more than + * once on them. + * See test\interface2.d, test20 + */ + return; + } + + if (funcdecl.semanticRun >= PASS.semanticdone) + return; + assert(funcdecl.semanticRun <= PASS.semantic); + funcdecl.semanticRun = PASS.semantic; + + if (funcdecl._scope) + { + sc = funcdecl._scope; + funcdecl._scope = null; + } + + if (!sc || funcdecl.errors) + return; + + funcdecl.cppnamespace = sc.namespace; + funcdecl.parent = sc.parent; + Dsymbol parent = funcdecl.toParent(); + + funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function + + funcdecl.storage_class |= sc.stc & ~STC.ref_; + AggregateDeclaration ad = funcdecl.isThis(); + // Don't nest structs b/c of generated methods which should not access the outer scopes. + // https://issues.dlang.org/show_bug.cgi?id=16627 + if (ad && !funcdecl.isGenerated()) + { + funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); + ad.makeNested(); + } + if (sc.func) + funcdecl.storage_class |= sc.func.storage_class & STC.disable; + // Remove prefix storage classes silently. + if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested())) + funcdecl.storage_class &= ~STC.TYPECTOR; + + //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); + + if (sc.flags & SCOPE.compile) + funcdecl.skipCodegen = true; + + funcdecl._linkage = sc.linkage; + if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration()) + funcdecl._linkage = LINK.d; // so they are uniquely mangled + + if (auto fld = funcdecl.isFuncLiteralDeclaration()) + { + if (fld.treq) + { + Type treq = fld.treq; + assert(treq.nextOf().ty == Tfunction); + if (treq.ty == Tdelegate) + fld.tok = TOK.delegate_; + else if (treq.isPtrToFunction()) + fld.tok = TOK.function_; + else + assert(0); + funcdecl._linkage = treq.nextOf().toTypeFunction().linkage; + } + } + + // evaluate pragma(inline) + if (auto pragmadecl = sc.inlining) + funcdecl.inlining = evalPragmaInline(pragmadecl.loc, sc, pragmadecl.args); + + funcdecl.visibility = sc.visibility; + funcdecl.userAttribDecl = sc.userAttribDecl; + UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage); + checkMustUseReserved(funcdecl); + + if (!funcdecl.originalType) + funcdecl.originalType = funcdecl.type.syntaxCopy(); + + static TypeFunction getFunctionType(FuncDeclaration fd) + { + if (auto tf = fd.type.isTypeFunction()) + return tf; + + if (!fd.type.isTypeError()) + { + .error(fd.loc, "%s `%s` `%s` must be a function instead of `%s`", fd.kind, fd.toPrettyChars, fd.toChars(), fd.type.toChars()); + fd.type = Type.terror; + } + fd.errors = true; + return null; + } + + if (sc.flags & SCOPE.Cfile) + { + /* C11 allows a function to be declared with a typedef, D does not. + */ + if (auto ti = funcdecl.type.isTypeIdentifier()) + { + auto tj = ti.typeSemantic(funcdecl.loc, sc); + if (auto tjf = tj.isTypeFunction()) + { + /* Copy the type instead of just pointing to it, + * as we don't merge function types + */ + auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); + funcdecl.type = tjf2; + funcdecl.originalType = tjf2; + } + } + } + + if (!getFunctionType(funcdecl)) + return; + + if (!funcdecl.type.deco) + { + sc = sc.push(); + sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type + + TypeFunction tf = funcdecl.type.toTypeFunction(); + if (sc.func) + { + /* If the nesting parent is pure without inference, + * then this function defaults to pure too. + * + * auto foo() pure { + * auto bar() {} // become a weak purity function + * class C { // nested class + * auto baz() {} // become a weak purity function + * } + * + * static auto boo() {} // typed as impure + * // Even though, boo cannot call any impure functions. + * // See also Expression::checkPurity(). + * } + */ + if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis())) + { + FuncDeclaration fd = null; + for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2()) + { + if (AggregateDeclaration adx = p.isAggregateDeclaration()) + { + if (adx.isNested()) + continue; + break; + } + if ((fd = p.isFuncDeclaration()) !is null) + break; + } + + /* If the parent's purity is inferred, then this function's purity needs + * to be inferred first. + */ + if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated()) + { + tf.purity = PURE.fwdref; // default to pure + } + } + } + + if (tf.isref) + sc.stc |= STC.ref_; + if (tf.isScopeQual) + sc.stc |= STC.scope_; + if (tf.isnothrow) + sc.stc |= STC.nothrow_; + if (tf.isnogc) + sc.stc |= STC.nogc; + if (tf.isproperty) + sc.stc |= STC.property; + if (tf.purity == PURE.fwdref) + sc.stc |= STC.pure_; + + if (tf.trust != TRUST.default_) + { + sc.stc &= ~STC.safeGroup; + if (tf.trust == TRUST.safe) + sc.stc |= STC.safe; + else if (tf.trust == TRUST.system) + sc.stc |= STC.system; + else if (tf.trust == TRUST.trusted) + sc.stc |= STC.trusted; + } + + if (funcdecl.isCtorDeclaration()) + { + tf.isctor = true; + Type tret = ad.handleType(); + assert(tret); + tret = tret.addStorageClass(funcdecl.storage_class | sc.stc); + tret = tret.addMod(funcdecl.type.mod); + tf.next = tret; + if (ad.isStructDeclaration()) + sc.stc |= STC.ref_; + } + + // 'return' on a non-static class member function implies 'scope' as well + if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_)) + sc.stc |= STC.scope_; + + // If 'this' has no pointers, remove 'scope' as it has no meaning + // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`, + // but existing code relies on `hasPointers()` being called here to resolve forward references: + // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573 + if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers()) + { + sc.stc &= ~STC.scope_; + tf.isScopeQual = false; + if (tf.isreturnscope) + { + sc.stc &= ~(STC.return_ | STC.returnScope); + tf.isreturn = false; + tf.isreturnscope = false; + } + } + + sc.linkage = funcdecl._linkage; + + if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) + { + import core.bitop : popcnt; + auto mods = MODtoChars(tf.mod); + .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods); + if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1) + .errorSupplemental(funcdecl.loc, + "did you mean to use `%s(%s)` as the return type?", mods, tf.next.toChars()); + + tf.mod = 0; // remove qualifiers + } + + /* Apply const, immutable, wild and shared storage class + * to the function type. Do this before type semantic. + */ + auto stc = funcdecl.storage_class; + if (funcdecl.type.isImmutable()) + stc |= STC.immutable_; + if (funcdecl.type.isConst()) + stc |= STC.const_; + if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_) + stc |= STC.shared_; + if (funcdecl.type.isWild()) + stc |= STC.wild; + funcdecl.type = funcdecl.type.addSTC(stc); + + funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc); + sc = sc.pop(); + } + + auto f = getFunctionType(funcdecl); + if (!f) + return; // funcdecl's type is not a function + + { + // Merge back function attributes into 'originalType'. + // It's used for mangling, ddoc, and json output. + TypeFunction tfo = funcdecl.originalType.toTypeFunction(); + tfo.mod = f.mod; + tfo.isScopeQual = f.isScopeQual; + tfo.isreturninferred = f.isreturninferred; + tfo.isscopeinferred = f.isscopeinferred; + tfo.isref = f.isref; + tfo.isnothrow = f.isnothrow; + tfo.isnogc = f.isnogc; + tfo.isproperty = f.isproperty; + tfo.purity = f.purity; + tfo.trust = f.trust; + + funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); + } + + // check pragma(crt_constructor) signature + if (funcdecl.isCrtCtor || funcdecl.isCrtDtor) + { + const idStr = funcdecl.isCrtCtor ? "crt_constructor" : "crt_destructor"; + if (f.nextOf().ty != Tvoid) + .error(funcdecl.loc, "%s `%s` must return `void` for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); + if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) + .error(funcdecl.loc, "%s `%s` must be `extern(C)` for `pragma(%s)` when taking parameters", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); + if (funcdecl.isThis()) + .error(funcdecl.loc, "%s `%s` cannot be a non-static member function for `pragma(%s)`", funcdecl.kind, funcdecl.toPrettyChars, idStr.ptr); + } + + if (funcdecl.overnext && funcdecl.isCsymbol()) + { + /* C does not allow function overloading, but it does allow + * redeclarations of the same function. If .overnext points + * to a redeclaration, ok. Error if it is an overload. + */ + auto fnext = funcdecl.overnext.isFuncDeclaration(); + funcDeclarationSemantic(sc, fnext); + auto fn = fnext.type.isTypeFunction(); + if (!fn || !cFuncEquivalence(f, fn)) + { + .error(funcdecl.loc, "%s `%s` redeclaration with different type", funcdecl.kind, funcdecl.toPrettyChars); + //printf("t1: %s\n", f.toChars()); + //printf("t2: %s\n", fn.toChars()); + } + funcdecl.overnext = null; // don't overload the redeclarations + } + + if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType) + .error(funcdecl.loc, "%s `%s` storage class `auto` has no effect if return type is not inferred", funcdecl.kind, funcdecl.toPrettyChars); + + if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested()) + { + /* Non-static nested functions have a hidden 'this' pointer to which + * the 'return' applies + */ + if (sc.scopesym && sc.scopesym.isAggregateDeclaration()) + .error(funcdecl.loc, "%s `%s` `static` member has no `this` to which `return` can apply", funcdecl.kind, funcdecl.toPrettyChars); + else + error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); + } + + if (funcdecl.isAbstract() && !funcdecl.isVirtual()) + { + const(char)* sfunc; + if (funcdecl.isStatic()) + sfunc = "static"; + else if (funcdecl.visibility.kind == Visibility.Kind.private_ || funcdecl.visibility.kind == Visibility.Kind.package_) + sfunc = visibilityToChars(funcdecl.visibility.kind); + else + sfunc = "final"; + .error(funcdecl.loc, "%s `%s` `%s` functions cannot be `abstract`", funcdecl.kind, funcdecl.toPrettyChars, sfunc); + } + + if (funcdecl.isOverride() && !funcdecl.isVirtual() && !funcdecl.isFuncLiteralDeclaration()) + { + Visibility.Kind kind = funcdecl.visible().kind; + if ((kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_) && funcdecl.isMember()) + .error(funcdecl.loc, "%s `%s` `%s` method is not virtual and cannot override", funcdecl.kind, funcdecl.toPrettyChars, visibilityToChars(kind)); + else + .error(funcdecl.loc, "%s `%s` cannot override a non-virtual function", funcdecl.kind, funcdecl.toPrettyChars); + } + + if (funcdecl.isAbstract() && funcdecl.isFinalFunc()) + .error(funcdecl.loc, "%s `%s` cannot be both `final` and `abstract`", funcdecl.kind, funcdecl.toPrettyChars); + + if (funcdecl.printf || funcdecl.scanf) + { + checkPrintfScanfSignature(funcdecl, f, sc); + } + + if (auto id = parent.isInterfaceDeclaration()) + { + funcdecl.storage_class |= STC.abstract_; + if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete()) + .error(funcdecl.loc, "%s `%s` constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); + if (funcdecl.fbody && funcdecl.isVirtual()) + .error(funcdecl.loc, "%s `%s` function body only allowed in `final` functions in interface `%s`", funcdecl.kind, funcdecl.toPrettyChars, id.toChars()); + } + + if (UnionDeclaration ud = parent.isUnionDeclaration()) + { + if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration()) + .error(funcdecl.loc, "%s `%s` destructors, postblits and invariants are not allowed in union `%s`", funcdecl.kind, funcdecl.toPrettyChars, ud.toChars()); + } + + if (StructDeclaration sd = parent.isStructDeclaration()) + { + if (funcdecl.isCtorDeclaration()) + { + goto Ldone; + } + } + + if (ClassDeclaration cd = parent.isClassDeclaration()) + { + parent = cd = objc.getParent(funcdecl, cd); + + if (funcdecl.isCtorDeclaration()) + { + goto Ldone; + } + + if (funcdecl.storage_class & STC.abstract_) + cd.isabstract = ThreeState.yes; + + // if static function, do not put in vtbl[] + if (!funcdecl.isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + // Suppress further errors if the return type is an error + if (funcdecl.type.nextOf() == Type.terror) + goto Ldone; + + bool may_override = false; + for (size_t i = 0; i < cd.baseclasses.length; i++) + { + BaseClass* b = (*cd.baseclasses)[i]; + ClassDeclaration cbd = b.type.toBasetype().isClassHandle(); + if (!cbd) + continue; + for (size_t j = 0; j < cbd.vtbl.length; j++) + { + FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration(); + if (!f2 || f2.ident != funcdecl.ident) + continue; + if (cbd.parent && cbd.parent.isTemplateInstance()) + { + if (!functionSemantic(f2)) + goto Ldone; + } + may_override = true; + } + } + if (may_override && funcdecl.type.nextOf() is null) + { + /* If same name function exists in base class but 'this' is auto return, + * cannot find index of base class's vtbl[] to override. + */ + .error(funcdecl.loc, "%s `%s` return type inference is not supported if may override base class function", funcdecl.kind, funcdecl.toPrettyChars); + } + + /* Find index of existing function in base class's vtbl[] to override + * (the index will be the same as in cd's current vtbl[]) + */ + int vi = cd.baseClass ? findVtblIndex(funcdecl, cd.baseClass.vtbl[]) : -1; + + bool doesoverride = false; + switch (vi) + { + case -1: + Lintro: + /* Didn't find one, so + * This is an 'introducing' function which gets a new + * slot in the vtbl[]. + */ + + // Verify this doesn't override previous final function + if (cd.baseClass) + { + Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident); + if (s) + { + if (auto f2 = s.isFuncDeclaration()) + { + f2 = f2.overloadExactMatch(funcdecl.type); + if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) + .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, f2.toPrettyChars()); + } + } + } + + /* These quirky conditions mimic what happens when virtual + inheritance is implemented by producing a virtual base table + with offsets to each of the virtual bases. + */ + if (target.cpp.splitVBasetable && cd.classKind == ClassKind.cpp && + cd.baseClass && cd.baseClass.vtbl.length) + { + /* if overriding an interface function, then this is not + * introducing and don't put it in the class vtbl[] + */ + funcdecl.interfaceVirtual = overrideInterface(funcdecl); + if (funcdecl.interfaceVirtual) + { + //printf("\tinterface function %s\n", toChars()); + cd.vtblFinal.push(funcdecl); + goto Linterfaces; + } + } + + if (funcdecl.isFinalFunc()) + { + // Don't check here, as it may override an interface function + //if (isOverride()) + // error("is marked as override, but does not override any function"); + cd.vtblFinal.push(funcdecl); + } + else + { + //printf("\tintroducing function %s\n", funcdecl.toChars()); + funcdecl.isIntroducing = true; + if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) + { + /* Overloaded functions with same name are grouped and in reverse order. + * Search for first function of overload group, and insert + * funcdecl into vtbl[] immediately before it. + */ + funcdecl.vtblIndex = cast(int)cd.vtbl.length; + bool found; + foreach (const i, s; cd.vtbl) + { + if (found) + // the rest get shifted forward + ++s.isFuncDeclaration().vtblIndex; + else if (s.ident == funcdecl.ident && s.parent == parent) + { + // found first function of overload group + funcdecl.vtblIndex = cast(int)i; + found = true; + ++s.isFuncDeclaration().vtblIndex; + } + } + cd.vtbl.insert(funcdecl.vtblIndex, funcdecl); + + debug foreach (const i, s; cd.vtbl) + { + // a C++ dtor gets its vtblIndex later (and might even be added twice to the vtbl), + // e.g. when compiling druntime with a debug compiler, namely with core.stdcpp.exception. + if (auto fd = s.isFuncDeclaration()) + assert(fd.vtblIndex == i || + (cd.classKind == ClassKind.cpp && fd.isDtorDeclaration) || + funcdecl.parent.isInterfaceDeclaration); // interface functions can be in multiple vtbls + } + } + else + { + // Append to end of vtbl[] + vi = cast(int)cd.vtbl.length; + cd.vtbl.push(funcdecl); + funcdecl.vtblIndex = vi; + } + } + break; + + case -2: + // can't determine because of forward references + funcdecl.errors = true; + return; + + default: + { + if (vi >= cd.vtbl.length) + { + /* the derived class cd doesn't have its vtbl[] allocated yet. + * https://issues.dlang.org/show_bug.cgi?id=21008 + */ + .error(funcdecl.loc, "%s `%s` circular reference to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); + funcdecl.errors = true; + return; + } + FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); + FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); + // This function is covariant with fdv + + if (fdc == funcdecl) + { + doesoverride = true; + break; + } + + auto vtf = getFunctionType(fdv); + if (vtf.trust > TRUST.system && f.trust == TRUST.system) + .error(funcdecl.loc, "%s `%s` cannot override `@safe` method `%s` with a `@system` attribute", funcdecl.kind, funcdecl.toPrettyChars, + fdv.toPrettyChars); + + if (fdc.toParent() == parent) + { + //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n", + // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(), + // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(), + // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars()); + + // fdc overrides fdv exactly, then this introduces new function. + if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod) + goto Lintro; + } + + if (fdv.isDeprecated && !funcdecl.isDeprecated) + deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`", + funcdecl.toPrettyChars, fdv.toPrettyChars); + + // This function overrides fdv + if (fdv.isFinalFunc()) + .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s`", funcdecl.kind, funcdecl.toPrettyChars, fdv.toPrettyChars()); + + if (!funcdecl.isOverride()) + { + if (fdv.isFuture()) + { + deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars()); + // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[] + goto Lintro; + } + else + { + // https://issues.dlang.org/show_bug.cgi?id=17349 + error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute", + fdv.toPrettyChars(), funcdecl.toPrettyChars()); + } + } + doesoverride = true; + if (fdc.toParent() == parent) + { + // If both are mixins, or both are not, then error. + // If either is not, the one that is not overrides the other. + bool thismixin = funcdecl.parent.isClassDeclaration() !is null; + bool fdcmixin = fdc.parent.isClassDeclaration() !is null; + if (thismixin == fdcmixin) + { + .error(funcdecl.loc, "%s `%s` multiple overrides of same function", funcdecl.kind, funcdecl.toPrettyChars); + } + /* + * https://issues.dlang.org/show_bug.cgi?id=711 + * + * If an overriding method is introduced through a mixin, + * we need to update the vtbl so that both methods are + * present. + */ + else if (thismixin) + { + /* if the mixin introduced the overriding method, then reintroduce it + * in the vtbl. The initial entry for the mixined method + * will be updated at the end of the enclosing `if` block + * to point to the current (non-mixined) function. + */ + auto vitmp = cast(int)cd.vtbl.length; + cd.vtbl.push(fdc); + fdc.vtblIndex = vitmp; + } + else if (fdcmixin) + { + /* if the current overriding function is coming from a + * mixined block, then push the current function in the + * vtbl, but keep the previous (non-mixined) function as + * the overriding one. + */ + auto vitmp = cast(int)cd.vtbl.length; + cd.vtbl.push(funcdecl); + funcdecl.vtblIndex = vitmp; + break; + } + else // fdc overrides fdv + { + // this doesn't override any function + break; + } + } + cd.vtbl[vi] = funcdecl; + funcdecl.vtblIndex = vi; + + /* Remember which functions this overrides + */ + funcdecl.foverrides.push(fdv); + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv.tintro) + funcdecl.tintro = fdv.tintro; + else if (!funcdecl.type.equals(fdv.type)) + { + auto tnext = funcdecl.type.nextOf(); + if (auto handle = tnext.isClassHandle()) + { + if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) + handle.dsymbolSemantic(null); + } + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv.type.nextOf().isBaseOf(tnext, &offset)) + { + funcdecl.tintro = fdv.type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + Linterfaces: + bool foundVtblMatch = false; + + for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass) + { + foreach (b; bcd.interfaces) + { + vi = findVtblIndex(funcdecl, b.sym.vtbl[]); + switch (vi) + { + case -1: + break; + + case -2: + // can't determine because of forward references + funcdecl.errors = true; + return; + + default: + { + auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi]; + Type ti = null; + + foundVtblMatch = true; + + /* Remember which functions this overrides + */ + funcdecl.foverrides.push(fdv); + + if (fdv.tintro) + ti = fdv.tintro; + else if (!funcdecl.type.equals(fdv.type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset)) + { + ti = fdv.type; + } + } + if (ti) + { + if (funcdecl.tintro) + { + if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null)) + { + .error(funcdecl.loc, "%s `%s` incompatible covariant types `%s` and `%s`", funcdecl.kind, funcdecl.toPrettyChars, funcdecl.tintro.toChars(), ti.toChars()); + } + } + else + { + funcdecl.tintro = ti; + } + } + } + } + } + } + if (foundVtblMatch) + { + goto L2; + } + + if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override)) + { + BaseClass* bc = null; + Dsymbol s = null; + for (size_t i = 0; i < cd.baseclasses.length; i++) + { + bc = (*cd.baseclasses)[i]; + s = bc.sym.search_correct(funcdecl.ident); + if (s) + break; + } + + if (s) + { + HdrGenState hgs; + OutBuffer buf; + + auto fd = s.isFuncDeclaration(); + functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, + new Identifier(funcdecl.toPrettyChars()), hgs, null); + const(char)* funcdeclToChars = buf.peekChars(); + + if (fd) + { + OutBuffer buf1; + + if (fd.ident == funcdecl.ident) + hgs.fullQual = true; + + // https://issues.dlang.org/show_bug.cgi?id=23745 + // If the potentially overridden function contains errors, + // inform the user to fix that one first + if (fd.errors) + { + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", + funcdecl.toChars(), fd.toPrettyChars()); + errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overridden", + fd.toPrettyChars()); + } + else + { + functionToBufferFull(cast(TypeFunction)(fd.type), buf1, + new Identifier(fd.toPrettyChars()), hgs, null); + + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", + funcdeclToChars, buf1.peekChars()); + } + } + else + { + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?", + funcdeclToChars, s.kind, s.toPrettyChars()); + errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overridden"); + } + } + else + .error(funcdecl.loc, "%s `%s` does not override any function", funcdecl.kind, funcdecl.toPrettyChars); + } + + L2: + objc.setSelector(funcdecl, sc); + objc.checkLinkage(funcdecl); + objc.addToClassMethodList(funcdecl, cd); + objc.setAsOptional(funcdecl, sc); + + /* Go through all the interface bases. + * Disallow overriding any final functions in the interface(s). + */ + foreach (b; cd.interfaces) + { + if (b.sym) + { + if (auto s = search_function(b.sym, funcdecl.ident)) + { + if (auto f2 = s.isFuncDeclaration()) + { + f2 = f2.overloadExactMatch(funcdecl.type); + if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_) + .error(funcdecl.loc, "%s `%s` cannot override `final` function `%s.%s`", funcdecl.kind, funcdecl.toPrettyChars, b.sym.toChars(), f2.toPrettyChars()); + } + } + } + } + + if (funcdecl.isOverride) + { + if (funcdecl.storage_class & STC.disable) + deprecation(funcdecl.loc, + "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class", + funcdecl.toPrettyChars); + + if (funcdecl.isDeprecated && !(funcdecl.foverrides.length && funcdecl.foverrides[0].isDeprecated)) + deprecation(funcdecl.loc, + "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class", + funcdecl.toPrettyChars); + } + + } + else if (funcdecl.isOverride() && !parent.isTemplateInstance()) + .error(funcdecl.loc, "%s `%s` `override` only applies to class member functions", funcdecl.kind, funcdecl.toPrettyChars); + + if (auto ti = parent.isTemplateInstance) + { + objc.setSelector(funcdecl, sc); + objc.setAsOptional(funcdecl, sc); + } + + objc.validateSelector(funcdecl); + objc.validateOptional(funcdecl); + // Reflect this.type to f because it could be changed by findVtblIndex + f = funcdecl.type.toTypeFunction(); + +Ldone: + if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody()) + .error(funcdecl.loc, "%s `%s` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract", funcdecl.kind, funcdecl.toPrettyChars); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (funcdecl.isVirtual()) + { + if (auto ti = parent.isTemplateInstance()) + { + // Take care of nested templates + while (1) + { + TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration cd = ti.tempdecl.isClassMember(); + if (cd) + { + .error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars()); + } + } + } + + funcdecl.checkMain(); // Check main() parameters and return type + + /* Purity and safety can be inferred for some functions by examining + * the function body. + */ + if (funcdecl.canInferAttributes(sc)) + funcdecl.initInferAttributes(); + + funcdecl.semanticRun = PASS.semanticdone; + + /* Save scope for possible later use (if we need the + * function internals) + */ + funcdecl._scope = sc.copy(); + funcdecl._scope.setNoFree(); + + __gshared bool printedMain = false; // semantic might run more than once + if (global.params.v.verbose && !printedMain) + { + const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null; + Module mod = sc._module; + + if (type && mod) + { + printedMain = true; + auto name = mod.srcfile.toChars(); + auto path = FileName.searchPath(global.path, name, true); + message("entry %-10s\t%s", type, path ? path : name); + } + } + + if (funcdecl.fbody && sc._module.isRoot() && + (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain())) + global.hasMainFunction = true; + + if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot()) + { + // check if `_d_cmain` is defined + bool cmainTemplateExists() + { + Dsymbol pscopesym; + auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym); + if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) + if (moduleSymbol.search(funcdecl.loc, Id.CMain)) + return true; + + return false; + } + + // Only mixin `_d_cmain` if it is defined + if (cmainTemplateExists()) + { + // add `mixin _d_cmain!();` to the declaring module + auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain); + auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null); + sc._module.members.push(tm); + } + } + + assert(funcdecl.type.ty != Terror || funcdecl.errors); + + // semantic for parameters' UDAs + foreach (i, param; f.parameterList) + { + if (param && param.userAttribDecl) + param.userAttribDecl.dsymbolSemantic(sc); + } +} + + +/**************************************************** + * Resolve forward reference of function signature - + * parameter types, return type, and attributes. + * Params: + * fd = function declaration + * Returns: + * false if any errors exist in the signature. + */ +public +extern (C++) +bool functionSemantic(FuncDeclaration fd) +{ + //printf("functionSemantic() %p %s\n", this, toChars()); + if (!fd._scope) + return !fd.errors; + + fd.cppnamespace = fd._scope.namespace; + + if (!fd.originalType) // semantic not yet run + { + TemplateInstance spec = fd.isSpeculative(); + uint olderrs = global.errors; + uint oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + dsymbolSemantic(fd, fd._scope); + global.gag = oldgag; + if (spec && global.errors != olderrs) + spec.errors = (global.errors - olderrs != 0); + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + // if inferring return type, sematic3 needs to be run + // - When the function body contains any errors, we cannot assume + // the inferred return type is valid. + // So, the body errors should become the function signature error. + if (fd.inferRetType && fd.type && !fd.type.nextOf()) + return fd.functionSemantic3(); + + TemplateInstance ti; + if (fd.isInstantiated() && !fd.isVirtualMethod() && + ((ti = fd.parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == fd.ident)) + { + AggregateDeclaration ad = fd.isMemberLocal(); + if (ad && ad.sizeok != Sizeok.done) + { + /* Currently dmd cannot resolve forward references per methods, + * then setting SIZOKfwd is too conservative and would break existing code. + * So, just stop method attributes inference until ad.dsymbolSemantic() done. + */ + //ad.sizeok = Sizeok.fwd; + } + else + return fd.functionSemantic3() || !fd.errors; + } + + if (fd.storage_class & STC.inference) + return fd.functionSemantic3() || !fd.errors; + + return !fd.errors; +} + +/**************************************************** + * Resolve forward reference of function body. + * Returns false if any errors exist in the body. + */ +public +extern (C++) +bool functionSemantic3(FuncDeclaration fd) +{ + if (fd.semanticRun < PASS.semantic3 && fd._scope) + { + /* Forward reference - we need to run semantic3 on this function. + * If errors are gagged, and it's not part of a template instance, + * we need to temporarily ungag errors. + */ + TemplateInstance spec = fd.isSpeculative(); + uint olderrs = global.errors; + uint oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + semantic3(fd, fd._scope); + global.gag = oldgag; + + // If it is a speculatively-instantiated template, and errors occur, + // we need to mark the template as having errors. + if (spec && global.errors != olderrs) + spec.errors = (global.errors - olderrs != 0); + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + return !fd.errors && !fd.hasSemantic3Errors(); +} + +// called from semantic3 +/** + * Creates and returns the hidden parameters for this function declaration. + * + * Hidden parameters include the `this` parameter of a class, struct or + * nested function and the selector parameter for Objective-C methods. + */ +extern (D) void declareThis(FuncDeclaration fd, Scope* sc) +{ + const bool dualCtx = (fd.toParent2() != fd.toParentLocal()); + if (dualCtx) + fd.hasDualContext = true; + auto ad = fd.isThis(); + if (!dualCtx && !ad && !fd.isNested()) + { + fd.vthis = null; + fd.objc.selectorParameter = null; + return; + } + + Type addModStc(Type t) + { + return t.addMod(fd.type.mod).addStorageClass(fd.storage_class); + } + + if (dualCtx || fd.isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + Type tthis = addModStc(dualCtx ? + Type.tvoidptr.sarrayOf(2).pointerTo() : + Type.tvoid.pointerTo()); + fd.vthis = new VarDeclaration(fd.loc, tthis, dualCtx ? Id.this2 : Id.capture, null); + fd.vthis.storage_class |= STC.parameter | STC.nodtor; + } + else if (ad) + { + Type thandle = addModStc(ad.handleType()); + fd.vthis = new ThisDeclaration(fd.loc, thandle); + fd.vthis.storage_class |= STC.parameter; + if (thandle.ty == Tstruct) + { + fd.vthis.storage_class |= STC.ref_; + } + } + + if (auto tf = fd.type.isTypeFunction()) + { + if (tf.isreturn) + fd.vthis.storage_class |= STC.return_; + if (tf.isScopeQual) + fd.vthis.storage_class |= STC.scope_; + if (tf.isreturnscope) + fd.vthis.storage_class |= STC.returnScope; + } + + fd.vthis.dsymbolSemantic(sc); + if (!sc.insert(fd.vthis)) + assert(0); + fd.vthis.parent = fd; + if (ad) + fd.objc.selectorParameter = .objc.createSelectorParameter(fd, sc); +} + +/**************************************************** + * Check that this function type is properly resolved. + * If not, report "forward reference error" and return true. + */ +extern (D) bool checkForwardRef(FuncDeclaration fd, const ref Loc loc) +{ + if (!functionSemantic(fd)) + return true; + + /* No deco means the functionSemantic() call could not resolve + * forward referenes in the type of this function. + */ + if (!fd.type.deco) + { + bool inSemantic3 = (fd.inferRetType && fd.semanticRun >= PASS.semantic3); + .error(loc, "forward reference to %s`%s`", + (inSemantic3 ? "inferred return type of function " : "").ptr, + fd.toChars()); + return true; + } + return false; +} + +/************************************************* + * Find index of function in vtbl[0..length] that + * this function overrides. + * Prefer an exact match to a covariant one. + * Params: + * fd = function + * vtbl = vtable to use + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ +int findVtblIndex(FuncDeclaration fd, Dsymbol[] vtbl) +{ + //printf("findVtblIndex() %s\n", toChars()); + import dmd.typesem : covariant; + + FuncDeclaration mismatch = null; + StorageClass mismatchstc = 0; + int mismatchvi = -1; + int exactvi = -1; + int bestvi = -1; + for (int vi = 0; vi < cast(int)vtbl.length; vi++) + { + FuncDeclaration fdv = vtbl[vi].isFuncDeclaration(); + if (fdv && fdv.ident == fd.ident) + { + if (fd.type.equals(fdv.type)) // if exact match + { + if (fdv.parent.isClassDeclaration()) + { + if (fdv.isFuture()) + { + bestvi = vi; + continue; // keep looking + } + return vi; // no need to look further + } + + if (exactvi >= 0) + { + .error(fd.loc, "%s `%s` cannot determine overridden function", fd.kind, fd.toPrettyChars); + return exactvi; + } + exactvi = vi; + bestvi = vi; + continue; + } + + StorageClass stc = 0; + const cov = fd.type.covariant(fdv.type, &stc); + //printf("\tbaseclass cov = %d\n", cov); + final switch (cov) + { + case Covariant.distinct: + // types are distinct + break; + + case Covariant.yes: + bestvi = vi; // covariant, but not identical + break; + // keep looking for an exact match + + case Covariant.no: + mismatchvi = vi; + mismatchstc = stc; + mismatch = fdv; // overrides, but is not covariant + break; + // keep looking for an exact match + + case Covariant.fwdref: + return -2; // forward references + } + } + } + if (fd._linkage == LINK.cpp && bestvi != -1) + { + StorageClass stc = 0; + FuncDeclaration fdv = vtbl[bestvi].isFuncDeclaration(); + assert(fdv && fdv.ident == fd.ident); + if (fd.type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no) + { + /* https://issues.dlang.org/show_bug.cgi?id=22351 + * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not. + * For now, continue to allow D covariant rules to apply when `override` has been used, + * but issue a deprecation warning that this behaviour will change in the future. + * Otherwise, follow the C++ covariant rules, which will create a new vtable entry. + */ + if (fd.isOverride()) + { + /* @@@DEPRECATED_2.110@@@ + * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch, + * but also the `cppCovariant` parameter from Type.covariant, and update the function + * so that both `LINK.cpp` covariant conditions within are always checked. + */ + .deprecation(fd.loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated", + fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(), + fd.toPrettyChars(), fd.type.toTypeFunction().parameterList.parametersTypeToChars(), fd.type.modToChars()); + + const char* where = fd.type.isNaked() ? "parameters" : "type"; + deprecationSupplemental(fd.loc, "Either remove `override`, or adjust the `const` qualifiers of the " + ~ "overriding function %s", where); + } + else + { + // Treat as if Covariant.no + mismatchvi = bestvi; + mismatchstc = stc; + mismatch = fdv; + bestvi = -1; + } + } + } + if (bestvi == -1 && mismatch) + { + //type.print(); + //mismatch.type.print(); + //printf("%s %s\n", type.deco, mismatch.type.deco); + //printf("stc = %llx\n", mismatchstc); + if (mismatchstc) + { + // Fix it by modifying the type to add the storage classes + fd.type = fd.type.addStorageClass(mismatchstc); + bestvi = mismatchvi; + } + } + return bestvi; +} + +/********************************* + * If function is a function in a base class, + * return that base class. + * Params: + * fd = function + * Returns: + * base class if overriding, null if not + */ +BaseClass* overrideInterface(FuncDeclaration fd) +{ + for (ClassDeclaration cd = fd.toParent2().isClassDeclaration(); cd; cd = cd.baseClass) + { + foreach (b; cd.interfaces) + { + auto v = findVtblIndex(fd, b.sym.vtbl[]); + if (v >= 0) + return b; + } + } + return null; +} diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 8d88207..af7b1fa 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -1,7 +1,7 @@ /** * Stores command line options and contains other miscellaneous declarations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d) @@ -15,7 +15,9 @@ import core.stdc.stdio; import core.stdc.stdint; import core.stdc.string; +import dmd.astenums; import dmd.root.array; +import dmd.root.file; import dmd.root.filename; import dmd.common.outbuffer; import dmd.errorsink; @@ -167,7 +169,7 @@ extern (C++) struct Param bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required bool ctfe_cov = false; // generate coverage data for ctfe - bool ignoreUnsupportedPragmas; // rather than error on them + bool ignoreUnsupportedPragmas = true; // rather than error on them bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information bool useExceptions = true; // support exception handling @@ -217,8 +219,8 @@ extern (C++) struct Param const(char)[] argv0; // program name Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings - Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules - Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules + Array!(const(char)*) imppath; // array of char*'s of where to look for import modules + Array!(const(char)*) fileImppath; // array of char*'s of where to look for file import modules const(char)[] objdir; // .obj/.lib file output directory const(char)[] objname; // .obj file output name const(char)[] libname; // .lib file output name @@ -275,11 +277,11 @@ extern (C++) struct Global { const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value - string copyright = "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved"; + string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved"; string written = "written by Walter Bright"; - Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path - Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path + Array!(const(char)*) path; /// Array of char*'s which form the import lookup path + Array!(const(char)*) filePath; /// Array of char*'s which form the file import lookup path private enum string _version = import("VERSION"); char[26] datetime; /// string returned by ctime() @@ -294,8 +296,8 @@ extern (C++) struct Global void* console; /// opaque pointer to console for controlling text attributes - Array!Identifier* versionids; /// command line versions and predefined versions - Array!Identifier* debugids; /// command line debug versions and predefined versions + Array!Identifier versionids; /// command line versions and predefined versions + Array!Identifier debugids; /// command line debug versions and predefined versions bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch) uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks @@ -308,7 +310,7 @@ extern (C++) struct Global ErrorSink errorSink; /// where the error messages go ErrorSink errorSinkNull; /// where the error messages are ignored - extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; + extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess; nothrow: diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 4284f85..f553ae6 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -202,8 +202,8 @@ struct Param DString argv0; // program name Array<const char *> modFileAliasStrings; // array of char*'s of -I module filename alias strings - Array<const char *> *imppath; // array of char*'s of where to look for import modules - Array<const char *> *fileImppath; // array of char*'s of where to look for file import modules + Array<const char *> imppath; // array of char*'s of where to look for import modules + Array<const char *> fileImppath; // array of char*'s of where to look for file import modules DString objdir; // .obj/.lib file output directory DString objname; // .obj file output name DString libname; // .lib file output name @@ -282,8 +282,8 @@ struct Global const DString copyright; const DString written; - Array<const char *> *path; // Array of char*'s which form the import lookup path - Array<const char *> *filePath; // Array of char*'s which form the file import lookup path + Array<const char *> path; // Array of char*'s which form the import lookup path + Array<const char *> filePath; // Array of char*'s which form the file import lookup path char datetime[26]; /// string returned by ctime() CompileEnv compileEnv; @@ -297,8 +297,8 @@ struct Global void* console; // opaque pointer to console for controlling text attributes - Array<class Identifier*>* versionids; // command line versions and predefined versions - Array<class Identifier*>* debugids; // command line debug versions and predefined versions + Array<class Identifier*> versionids; // command line versions and predefined versions + Array<class Identifier*> debugids; // command line debug versions and predefined versions d_bool hasMainFunction; unsigned varSequenceNumber; @@ -307,7 +307,7 @@ struct Global ErrorSink* errorSink; // where the error messages go ErrorSink* errorSinkNull; // where the error messages disappear - FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); + DArray<unsigned char> (*preprocess)(FileName, const Loc&, OutBuffer&); /* Start gagging. Return the current number of gagged errors */ diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d index 756c0e5..b3980eb 100644 --- a/gcc/d/dmd/gluelayer.d +++ b/gcc/d/dmd/gluelayer.d @@ -3,7 +3,7 @@ * * This 'glues' either the DMC or GCC back-end to the front-end. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d, _gluelayer.d) diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 0944ade..e4cbcc5 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -3,7 +3,7 @@ * * Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d) @@ -35,7 +35,6 @@ import dmd.dtemplate; import dmd.dversion; import dmd.expression; import dmd.func; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; @@ -50,8 +49,8 @@ import dmd.rootobject; import dmd.root.string; import dmd.statement; import dmd.staticassert; -import dmd.target; import dmd.tokens; +import dmd.typesem; import dmd.visitor; struct HdrGenState @@ -60,6 +59,9 @@ struct HdrGenState bool ddoc; /// true if generating Ddoc file bool fullDump; /// true if generating a full AST dump file bool importcHdr; /// true if generating a .di file from an ImportC file + bool doFuncBodies; /// include function bodies in output + bool vcg_ast; /// write out codegen-ast + bool skipConstraints; // skip constraints when doing templates bool fullQual; /// fully qualify types when printing int tpltMember; @@ -78,9 +80,10 @@ enum TEST_EMIT_ALL = 0; * Generate a header (.di) file for Module m. * Params: * m = Module to generate header for + * doFuncBodies = generate function definitions rather than just declarations * buf = buffer to write the data to */ -extern (C++) void genhdrfile(Module m, ref OutBuffer buf) +extern (C++) void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf) { buf.doindent = 1; buf.printf("// D import file generated from '%s'", m.srcfile.toChars()); @@ -88,6 +91,7 @@ extern (C++) void genhdrfile(Module m, ref OutBuffer buf) HdrGenState hgs; hgs.hdrgen = true; hgs.importcHdr = (m.filetype == FileType.c); + hgs.doFuncBodies = doFuncBodies; toCBuffer(m, buf, hgs); } @@ -108,6 +112,14 @@ public extern (C++) const(char)* toChars(const Statement s) return buf.extractSlice().ptr; } +public extern (C++) const(char)* toChars(const Expression e) +{ + HdrGenState hgs; + OutBuffer buf; + toCBuffer(e, buf, hgs); + return buf.extractChars(); +} + public extern (C++) const(char)* toChars(const Initializer i) { OutBuffer buf; @@ -116,6 +128,17 @@ public extern (C++) const(char)* toChars(const Initializer i) return buf.extractChars(); } +public extern (C++) const(char)* toChars(const Type t) +{ + OutBuffer buf; + buf.reserve(16); + HdrGenState hgs; + hgs.fullQual = (t.ty == Tclass && !t.mod); + + toCBuffer(t, buf, null, hgs); + return buf.extractChars(); +} + public const(char)[] toString(const Initializer i) { OutBuffer buf; @@ -128,16 +151,18 @@ public const(char)[] toString(const Initializer i) * Dumps the full contents of module `m` to `buf`. * Params: * buf = buffer to write to. + * vcg_ast = write out codegen ast * m = module to visit all members of. */ -extern (C++) void moduleToBuffer(ref OutBuffer buf, Module m) +extern (C++) void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m) { HdrGenState hgs; hgs.fullDump = true; + hgs.vcg_ast = vcg_ast; toCBuffer(m, buf, hgs); } -void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) +void moduleToBuffer2(Module m, ref OutBuffer buf, ref HdrGenState hgs) { if (m.md) { @@ -171,7 +196,7 @@ void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) } } -private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) +private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState hgs) { void visitDefaultCase(Statement s) { @@ -240,7 +265,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) auto d = ds.exp.isDeclarationExp().declaration; if (auto v = d.isVarDeclaration()) { - visitVarDecl(v, anywritten, buf, *hgs); + visitVarDecl(v, anywritten, buf, hgs); } else d.dsymbolToBuffer(buf, hgs); @@ -803,7 +828,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) buf.level++; while (t) { - buf.writestring(t.toChars()); + buf.writestring(t.toString()); if (t.next && t.value != TOK.min && t.value != TOK.comma && t.next.value != TOK.comma && @@ -844,9 +869,9 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) visit.VisitStatement(s); } -private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, HdrGenState* hgs) +private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { - toCBuffer(s, buf, *hgs); + toCBuffer(s, buf, hgs); } void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) @@ -860,13 +885,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { buf.writestring(s.kind()); buf.writeByte('('); - s.exp.expressionToBuffer(buf, &hgs); + s.exp.expressionToBuffer(buf, hgs); if (s.msgs) { foreach (m; (*s.msgs)[]) { buf.writestring(", "); - m.expressionToBuffer(buf, &hgs); + m.expressionToBuffer(buf, hgs); } } buf.writestring(");"); @@ -898,13 +923,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitEnumMember(EnumMember em) { if (em.type) - typeToBuffer(em.type, em.ident, buf, &hgs); + typeToBuffer(em.type, em.ident, buf, hgs); else buf.writestring(em.ident.toString()); if (em.value) { buf.writestring(" = "); - em.value.expressionToBuffer(buf, &hgs); + em.value.expressionToBuffer(buf, hgs); } } @@ -921,7 +946,8 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) } foreach (const pid; imp.packages) { - buf.printf("%s.", pid.toChars()); + buf.write(pid.toString()); + buf.writeByte('.'); } buf.writestring(imp.id.toString()); if (imp.names.length) @@ -997,7 +1023,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitDeprecatedDeclaration(DeprecatedDeclaration d) { buf.writestring("deprecated("); - d.msg.expressionToBuffer(buf, &hgs); + d.msg.expressionToBuffer(buf, hgs); buf.writestring(") "); visitAttribDeclaration(d); } @@ -1050,7 +1076,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (i) buf.writeByte(' '); - buf.printf("align (%s)", exp.toChars()); + buf.writestring("align ("); + toCBuffer(exp, buf, hgs); + buf.writeByte(')'); } if (d.decl && d.decl.length < 2) buf.writeByte(' '); @@ -1085,7 +1113,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.args && d.args.length) { buf.writestring(", "); - argsToBuffer(d.args, buf, &hgs); + argsToBuffer(d.args, buf, hgs); } buf.writeByte(')'); @@ -1093,17 +1121,17 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) // https://issues.dlang.org/show_bug.cgi?id=14690 // Unconditionally perform a full output dump // for `pragma(inline)` declarations. - bool savedFullDump = global.params.dihdr.fullOutput; + const saved = hgs.doFuncBodies; if (d.ident == Id.Pinline) - global.params.dihdr.fullOutput = true; + hgs.doFuncBodies = true; visitAttribDeclaration(d); - global.params.dihdr.fullOutput = savedFullDump; + hgs.doFuncBodies = saved; } void visitConditionalDeclaration(ConditionalDeclaration d) { - d.condition.conditionToBuffer(buf, &hgs); + d.condition.conditionToBuffer(buf, hgs); if (d.decl || d.elsedecl) { buf.writenl(); @@ -1149,12 +1177,12 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, p.storageClass)) buf.writeByte(' '); if (p.type) - typeToBuffer(p.type, p.ident, buf, &hgs); + typeToBuffer(p.type, p.ident, buf, hgs); else buf.writestring(p.ident.toString()); } buf.writestring("; "); - s.aggr.expressionToBuffer(buf, &hgs); + s.aggr.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1166,13 +1194,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(Token.toString(s.op)); buf.writestring(" ("); if (s.prm.type) - typeToBuffer(s.prm.type, s.prm.ident, buf, &hgs); + typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); else buf.writestring(s.prm.ident.toString()); buf.writestring("; "); - s.lwr.expressionToBuffer(buf, &hgs); + s.lwr.expressionToBuffer(buf, hgs); buf.writestring(" .. "); - s.upr.expressionToBuffer(buf, &hgs); + s.upr.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1200,7 +1228,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitMixinDeclaration(MixinDeclaration d) { buf.writestring("mixin("); - argsToBuffer(d.exps, buf, &hgs, null); + argsToBuffer(d.exps, buf, hgs, null); buf.writestring(");"); buf.writenl(); } @@ -1208,7 +1236,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitUserAttributeDeclaration(UserAttributeDeclaration d) { buf.writestring("@("); - argsToBuffer(d.atts, buf, &hgs); + argsToBuffer(d.atts, buf, hgs); buf.writeByte(')'); visitAttribDeclaration(d); } @@ -1218,7 +1246,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (!constraint) return; buf.writestring(" if ("); - constraint.expressionToBuffer(buf, &hgs); + constraint.expressionToBuffer(buf, hgs); buf.writeByte(')'); } @@ -1236,7 +1264,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1244,7 +1272,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) else { buf.writenl(); - frequire.statementToBuffer(buf, &hgs); + frequire.statementToBuffer(buf, hgs); requireDo = true; } } @@ -1264,7 +1292,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(fensure.id.toString()); } buf.writestring("; "); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1278,7 +1306,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte(')'); } buf.writenl(); - fensure.ensure.statementToBuffer(buf, &hgs); + fensure.ensure.statementToBuffer(buf, hgs); requireDo = true; } } @@ -1288,7 +1316,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void bodyToBuffer(FuncDeclaration f) { - if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) + if (!f.fbody || (hgs.hdrgen && hgs.doFuncBodies == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) { if (!f.fbody && (f.fensures || f.frequires)) { @@ -1326,7 +1354,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte('{'); buf.writenl(); buf.level++; - f.fbody.statementToBuffer(buf, &hgs); + f.fbody.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -1344,7 +1372,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (i) buf.writestring(", "); - typeToBuffer(b.type, null, buf, &hgs); + typeToBuffer(b.type, null, buf, hgs); } } @@ -1360,7 +1388,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) assert(fd.type); if (stcToBuffer(buf, fd.storage_class)) buf.writeByte(' '); - functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, &hgs, d); + functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); visitTemplateConstraint(d.constraint); hgs.tpltMember++; bodyToBuffer(fd); @@ -1402,7 +1430,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, vd.storage_class)) buf.writeByte(' '); if (vd.type) - typeToBuffer(vd.type, vd.ident, buf, &hgs); + typeToBuffer(vd.type, vd.ident, buf, hgs); else buf.writestring(vd.ident.toString()); buf.writeByte('('); @@ -1413,9 +1441,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(" = "); ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else - vd._init.initializerToBuffer(buf, &hgs); + vd._init.initializerToBuffer(buf, hgs); } buf.writeByte(';'); buf.writenl(); @@ -1463,21 +1491,21 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitTemplateInstance(TemplateInstance ti) { buf.writestring(ti.name.toChars()); - tiargsToBuffer(ti, buf, &hgs); + tiargsToBuffer(ti, buf, hgs); if (hgs.fullDump) { buf.writenl(); - dumpTemplateInstance(ti, buf, &hgs); + dumpTemplateInstance(ti, buf, hgs); } } void visitTemplateMixin(TemplateMixin tm) { buf.writestring("mixin "); - typeToBuffer(tm.tqual, null, buf, &hgs); - tiargsToBuffer(tm, buf, &hgs); - if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) + typeToBuffer(tm.tqual, null, buf, hgs); + tiargsToBuffer(tm, buf, hgs); + if (tm.ident && memcmp(tm.ident.toString().ptr, cast(const(char)*) "__mixin", 7) != 0) { buf.writeByte(' '); buf.writestring(tm.ident.toString()); @@ -1485,7 +1513,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte(';'); buf.writenl(); if (hgs.fullDump) - dumpTemplateInstance(tm, buf, &hgs); + dumpTemplateInstance(tm, buf, hgs); } void visitEnumDeclaration(EnumDeclaration d) @@ -1501,7 +1529,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.memtype) { buf.writestring(" : "); - typeToBuffer(d.memtype, null, buf, &hgs); + typeToBuffer(d.memtype, null, buf, hgs); } if (!d.members) { @@ -1525,7 +1553,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte('}'); buf.writenl(); - if (!hgs.importcHdr) + if (!hgs.importcHdr || !d.ident) return; /* C enums get their members inserted into the symbol table of the enum declaration. @@ -1649,7 +1677,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, d.ident, buf, &hgs); + typeToBuffer(d.type, d.ident, buf, hgs); } else if (d.ident) { @@ -1658,7 +1686,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(" = "); if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, null, buf, &hgs); + typeToBuffer(d.type, null, buf, hgs); hgs.declstring = false; } buf.writeByte(';'); @@ -1672,7 +1700,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.aliassym) toCBuffer(d.aliassym, buf, hgs); else // d.type - typeToBuffer(d.type, null, buf, &hgs); + typeToBuffer(d.type, null, buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1692,7 +1720,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, f.storage_class)) buf.writeByte(' '); auto tf = f.type.isTypeFunction(); - typeToBuffer(tf, f.ident, buf, &hgs); + typeToBuffer(tf, f.ident, buf, hgs); if (hgs.hdrgen) { @@ -1706,7 +1734,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) bodyToBuffer(f); hgs.autoMember--; } - else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false && !hgs.insideFuncBody) + else if (hgs.tpltMember == 0 && hgs.doFuncBodies == false && !hgs.insideFuncBody) { if (!f.fbody) { @@ -1740,8 +1768,8 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) TypeFunction tf = cast(TypeFunction)f.type; if (!f.inferRetType && tf.next) - typeToBuffer(tf.next, null, buf, &hgs); - parametersToBuffer(tf.parameterList, buf, &hgs); + typeToBuffer(tf.next, null, buf, hgs); + parametersToBuffer(tf.parameterList, buf, hgs); // https://issues.dlang.org/show_bug.cgi?id=20074 void printAttribute(string str) @@ -1764,7 +1792,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (rs && rs.exp) { buf.writestring(" => "); - rs.exp.expressionToBuffer(buf, &hgs); + rs.exp.expressionToBuffer(buf, hgs); } else { @@ -1833,7 +1861,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writestring(");"); buf.writenl(); } @@ -1858,9 +1886,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); Identifier id = d.isAnonymous() ? null : d.ident; - typeToBuffer(d.type, id, buf, &hgs); + typeToBuffer(d.type, id, buf, hgs); buf.writestring(" : "); - d.width.expressionToBuffer(buf, &hgs); + d.width.expressionToBuffer(buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1874,7 +1902,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitModule(Module m) { - moduleToBuffer2(m, buf, &hgs); + moduleToBuffer2(m, buf, hgs); } extern (C++) @@ -1931,6 +1959,47 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) s.accept(v); } +// Note: this function is not actually `const`, because iterating the +// function parameter list may run dsymbolsemantic on enum types +public +void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, ref HdrGenState hgs) +{ + buf.writestring(td.ident == Id.ctor ? "this" : td.ident.toString()); + buf.writeByte('('); + foreach (i, const tp; *td.parameters) + { + if (i) + buf.writestring(", "); + toCBuffer(tp, buf, hgs); + } + buf.writeByte(')'); + + if (td.onemember) + { + if (const fd = td.onemember.isFuncDeclaration()) + { + if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) + { + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } + } + } + } + + if (!hgs.skipConstraints && + td.constraint) + { + buf.writestring(" if ("); + toCBuffer(td.constraint, buf, hgs); + buf.writeByte(')'); + } +} + /***************************************** * Pretty-print a template parameter list to a buffer. @@ -1963,9 +2032,9 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, { auto ie = v._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else - v._init.initializerToBuffer(buf, &hgs); + v._init.initializerToBuffer(buf, hgs); } const commentIt = hgs.importcHdr && isSpecialCName(v.ident); @@ -1988,7 +2057,7 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, if (stcToBuffer(buf, stc)) buf.writeByte(' '); if (v.type) - typeToBuffer(v.type, v.ident, buf, &hgs); + typeToBuffer(v.type, v.ident, buf, hgs); else if (useTypeof) { buf.writestring("typeof("); @@ -2033,7 +2102,7 @@ private bool isSpecialCName(Identifier id) /********************************************* * Print expression to buffer. */ -private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { void visit(Expression e) { @@ -2042,7 +2111,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitInteger(IntegerExp e) { - const dinteger_t v = e.toInteger(); + const ulong v = e.toInteger(); if (e.type) { Type t = e.type; @@ -2059,7 +2128,8 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* { if ((cast(EnumMember)em).value.toInteger == v) { - buf.printf("%s.%s", sym.toChars(), em.ident.toChars()); + const id = em.ident.toString(); + buf.printf("%s.%.*s", sym.toChars(), cast(int)id.length, id.ptr); return ; } } @@ -2119,15 +2189,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* break; case Tpointer: buf.writestring("cast("); - buf.writestring(t.toChars()); - buf.writeByte(')'); - if (target.ptrsize == 8) - goto case Tuns64; - else if (target.ptrsize == 4 || - target.ptrsize == 2) - goto case Tuns32; - else - assert(0); + + HdrGenState hgs2; // should re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + toCBuffer(t, buf, null, hgs2); + + buf.writestring(")cast(size_t)"); + goto case Tuns64; case Tvoid: buf.writestring("cast(void)0"); @@ -2136,11 +2204,8 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* default: /* This can happen if errors, such as * the type is painted on like in fromConstInitializer(). + * Just ignore */ - if (!global.errors) - { - assert(0); - } break; } } @@ -2212,6 +2277,16 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitString(StringExp e) { + if (e.hexString || e.sz == 8) + { + buf.writeByte('x'); + buf.writeByte('"'); + buf.writeHexString(e.peekData, true); + buf.writeByte('"'); + if (e.postfix) + buf.writeByte(e.postfix); + return; + } buf.writeByte('"'); const o = buf.length; foreach (i; 0 .. e.len) @@ -2225,6 +2300,37 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* buf.writeByte(e.postfix); } + void visitInterpolation(InterpExp e) + { + buf.writeByte('i'); + buf.writeByte('"'); + const o = buf.length; + + foreach (idx, str; e.interpolatedSet.parts) + { + if (idx % 2 == 0) + { + foreach(ch; str) + writeCharLiteral(buf, ch); + } + else + { + buf.writeByte('$'); + buf.writeByte('('); + foreach(ch; str) + buf.writeByte(ch); + buf.writeByte(')'); + } + } + + if (hgs.ddoc) + escapeDdocString(buf, o); + buf.writeByte('"'); + if (e.postfix) + buf.writeByte(e.postfix); + + } + void visitArrayLiteral(ArrayLiteralExp e) { buf.writeByte('['); @@ -2286,7 +2392,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* { e.sds.dsymbolToBuffer(buf, hgs); } - else if (hgs !is null && hgs.ddoc) + else if (hgs.ddoc) { // fixes bug 6491 if (auto m = e.sds.isModule()) @@ -2403,7 +2509,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* // which isn't correct as regular D code. buf.writeByte('('); - visitVarDecl(var, false, buf, *hgs); + visitVarDecl(var, false, buf, hgs); buf.writeByte(';'); buf.writeByte(')'); @@ -2446,7 +2552,10 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* typeToBuffer(e.targ, e.id, buf, hgs); if (e.tok2 != TOK.reserved) { - buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok2)); } else if (e.tspec) { @@ -2459,7 +2568,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* if (e.parameters && e.parameters.length) { buf.writestring(", "); - visitTemplateParameters(e.parameters, buf, *hgs); + visitTemplateParameters(e.parameters, buf, hgs); } buf.writeByte(')'); } @@ -2472,7 +2581,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitLoweredAssignExp(LoweredAssignExp e) { - if (global.params.vcg_ast) + if (hgs.vcg_ast) { expressionToBuffer(e.lowering, buf, hgs); return; @@ -2802,6 +2911,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* case EXP.super_: return visitSuper(e.isSuperExp()); case EXP.null_: return visitNull(e.isNullExp()); case EXP.string_: return visitString(e.isStringExp()); + case EXP.interpolated: return visitInterpolation(e.isInterpExp()); case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); @@ -2937,12 +3047,12 @@ public: if (tp.specType) { buf.writestring(" : "); - typeToBuffer(tp.specType, null, *buf, hgs); + typeToBuffer(tp.specType, null, *buf, *hgs); } if (tp.defaultType) { buf.writestring(" = "); - typeToBuffer(tp.defaultType, null, *buf, hgs); + typeToBuffer(tp.defaultType, null, *buf, *hgs); } } @@ -2956,33 +3066,33 @@ public: { buf.writestring("alias "); if (tp.specType) - typeToBuffer(tp.specType, tp.ident, *buf, hgs); + typeToBuffer(tp.specType, tp.ident, *buf, *hgs); else buf.writestring(tp.ident.toString()); if (tp.specAlias) { buf.writestring(" : "); - objectToBuffer(tp.specAlias, *buf, hgs); + objectToBuffer(tp.specAlias, *buf, *hgs); } if (tp.defaultAlias) { buf.writestring(" = "); - objectToBuffer(tp.defaultAlias, *buf, hgs); + objectToBuffer(tp.defaultAlias, *buf, *hgs); } } override void visit(TemplateValueParameter tp) { - typeToBuffer(tp.valType, tp.ident, *buf, hgs); + typeToBuffer(tp.valType, tp.ident, *buf, *hgs); if (tp.specValue) { buf.writestring(" : "); - tp.specValue.expressionToBuffer(*buf, hgs); + tp.specValue.expressionToBuffer(*buf, *hgs); } if (tp.defaultValue) { buf.writestring(" = "); - tp.defaultValue.expressionToBuffer(*buf, hgs); + tp.defaultValue.expressionToBuffer(*buf, *hgs); } } @@ -2993,9 +3103,9 @@ public: } } -private void conditionToBuffer(Condition c, ref OutBuffer buf, HdrGenState* hgs) +private void conditionToBuffer(Condition c, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new ConditionPrettyPrintVisitor(&buf, hgs); + scope v = new ConditionPrettyPrintVisitor(&buf, &hgs); c.accept(v); } @@ -3035,19 +3145,19 @@ public: override void visit(StaticIfCondition c) { buf.writestring("static if ("); - c.exp.expressionToBuffer(*buf, hgs); + c.exp.expressionToBuffer(*buf, *hgs); buf.writeByte(')'); } } void toCBuffer(const Statement s, ref OutBuffer buf, ref HdrGenState hgs) { - (cast()s).statementToBuffer(buf, &hgs); + (cast()s).statementToBuffer(buf, hgs); } void toCBuffer(const Type t, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs) { - typeToBuffer(cast() t, ident, buf, &hgs); + typeToBuffer(cast() t, ident, buf, hgs); } // used from TemplateInstance::toChars() and TemplateMixin::toChars() @@ -3057,12 +3167,12 @@ void toCBufferInstance(const TemplateInstance ti, ref OutBuffer buf, bool qualif hgs.fullQual = qualifyTypes; buf.writestring(ti.name.toChars()); - tiargsToBuffer(cast() ti, buf, &hgs); + tiargsToBuffer(cast() ti, buf, hgs); } void toCBuffer(const Initializer iz, ref OutBuffer buf, ref HdrGenState hgs) { - initializerToBuffer(cast() iz, buf, &hgs); + initializerToBuffer(cast() iz, buf, hgs); } bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe @@ -3255,7 +3365,7 @@ extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure @safe } // Print the full function signature with correct ident, attributes and template args -void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) +void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs, TemplateDeclaration td) { //printf("TypeFunction::toCBuffer() this = %p\n", this); visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); @@ -3265,12 +3375,12 @@ void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier i void functionToBufferWithIdent(TypeFunction tf, ref OutBuffer buf, const(char)* ident, bool isStatic) { HdrGenState hgs; - visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic); + visitFuncIdentWithPostfix(tf, ident.toDString(), buf, hgs, isStatic); } void toCBuffer(const Expression e, ref OutBuffer buf, ref HdrGenState hgs) { - expressionPrettyPrint(cast()e, buf, &hgs); + expressionPrettyPrint(cast()e, buf, hgs); } /************************************************** @@ -3285,7 +3395,7 @@ void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) { if (i) buf.writestring(", "); - typeToBuffer(arg.type, null, buf, &hgs); + typeToBuffer(arg.type, null, buf, hgs); } } @@ -3298,7 +3408,7 @@ void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) { if (i) buf.writestring(", "); - objectToBuffer(o, buf, &hgs); + objectToBuffer(o, buf, hgs); } } @@ -3312,7 +3422,7 @@ extern (C++) const(char)* parametersTypeToChars(ParameterList pl) { OutBuffer buf; HdrGenState hgs; - parametersToBuffer(pl, buf, &hgs); + parametersToBuffer(pl, buf, hgs); return buf.extractChars(); } @@ -3330,7 +3440,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua HdrGenState hgs; hgs.fullQual = fullQual; - parameterToBuffer(parameter, buf, &hgs); + parameterToBuffer(parameter, buf, hgs); if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.length - 1]) { @@ -3348,7 +3458,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua * hgs = context */ -private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState* hgs) +private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('('); foreach (i; 0 .. pl.length) @@ -3386,7 +3496,7 @@ private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState * buf = buffer to write it to * hgs = context */ -private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) +private void parameterToBuffer(Parameter p, ref OutBuffer buf, ref HdrGenState hgs) { if (p.userAttribDecl) { @@ -3409,7 +3519,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) if (p.storageClass & STC.in_) { buf.writestring("in "); - if (global.params.previewIn && p.storageClass & STC.ref_) + if ((p.storageClass & (STC.constscoperef | STC.ref_)) == (STC.constscoperef | STC.ref_)) stc &= ~STC.ref_; } else if (p.storageClass & STC.lazy_) @@ -3424,14 +3534,15 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope))) buf.writeByte(' '); + const(char)[] s; if (p.storageClass & STC.alias_) { if (p.ident) buf.writestring(p.ident.toString()); } - else if (p.type.ty == Tident && - (cast(TypeIdentifier)p.type).ident.toString().length > 3 && - strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) + else if (p.type.isTypeIdentifier() && + (s = p.type.isTypeIdentifier().ident.toString()).length > 3 && + s[0..3] == "__T") { // print parameter name, instead of undetermined type parameter buf.writestring(p.ident.toString()); @@ -3458,7 +3569,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) * basis = replace `null`s in argument list with this expression (for sparse array literals) * names = if non-null, use these as the names for the arguments */ -private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null) +private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, ref HdrGenState hgs, Expression basis = null, Identifiers* names = null) { if (!expressions || !expressions.length) return; @@ -3509,26 +3620,23 @@ private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenSta } } -private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void sizeToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { if (e.type == Type.tsize_t) { Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e); ex = ex.optimize(WANTvalue); - const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1; - if (cast(sinteger_t)uval >= 0) - { - dinteger_t sizemax = void; - if (target.ptrsize == 8) - sizemax = 0xFFFFFFFFFFFFFFFFUL; - else if (target.ptrsize == 4) - sizemax = 0xFFFFFFFFU; - else if (target.ptrsize == 2) - sizemax = 0xFFFFU; - else - assert(0); - if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) + const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; + if (cast(long)uval >= 0) + { + if (uval <= 0xFFFFU) + { + buf.print(uval); + return; + } + if (uval <= 0x7FFF_FFFF_FFFF_FFFFUL) { + buf.writestring("cast(size_t)"); buf.print(uval); return; } @@ -3537,7 +3645,7 @@ private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) expToBuffer(e, PREC.assign, buf, hgs); } -private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void expressionToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { expressionPrettyPrint(e, buf, hgs); } @@ -3546,7 +3654,7 @@ private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hg * Write expression out to buf, but wrap it * in ( ) if its precedence is less than pr. */ -private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* hgs) +private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, ref HdrGenState hgs) { debug { @@ -3580,7 +3688,7 @@ private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* /************************************************** * An entry point to pretty-print type. */ -private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, HdrGenState* hgs, +private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, ref HdrGenState hgs, ubyte modMask = 0) { if (auto tf = t.isTypeFunction()) @@ -3596,7 +3704,7 @@ private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, Hdr } } -private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState* hgs) +private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, ref HdrGenState hgs) { // Tuples and functions don't use the type constructor syntax if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) @@ -3632,7 +3740,7 @@ private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState } -private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) +private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('{'); buf.writenl(); @@ -3655,7 +3763,7 @@ private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGen } -private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) +private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('!'); if (ti.nest) @@ -3675,7 +3783,9 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* { if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.length == 0)) { - buf.writestring(t.toChars()); + HdrGenState hgs2; // re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + toCBuffer(t, buf, null, hgs2); return; } } @@ -3683,7 +3793,7 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* { 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()); + toCBuffer(e, buf, hgs); return; } } @@ -3704,7 +3814,7 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* * This makes a 'pretty' version of the template arguments. * It's analogous to genIdent() which makes a mangled version. */ -private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs) +private void objectToBuffer(RootObject oarg, ref OutBuffer buf, ref HdrGenState hgs) { //printf("objectToBuffer()\n"); /* The logic of this should match what genIdent() does. The _dynamic_cast() @@ -3725,8 +3835,10 @@ private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs } else if (Dsymbol s = isDsymbol(oarg)) { - const p = s.ident ? s.ident.toChars() : s.toChars(); - buf.writestring(p); + if (s.ident) + buf.writestring(s.ident.toString()); + else + buf.writestring(s.toChars()); } else if (auto v = isTuple(oarg)) { @@ -3757,7 +3869,7 @@ private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs } -private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, HdrGenState* hgs, bool isStatic) +private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, ref HdrGenState hgs, bool isStatic) { if (t.inuse) { @@ -3802,7 +3914,7 @@ private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref O } private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, - ref OutBuffer buf, HdrGenState* hgs) + ref OutBuffer buf, ref HdrGenState hgs) { if (t.inuse) { @@ -3858,7 +3970,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te { if (i) buf.writestring(", "); - toCBuffer(p, buf, *hgs); + toCBuffer(p, buf, hgs); } buf.writeByte(')'); } @@ -3871,7 +3983,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te } -private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState* hgs) +private void initializerToBuffer(Initializer inx, ref OutBuffer buf, ref HdrGenState hgs) { void visitError(ErrorInitializer iz) { @@ -3944,7 +4056,7 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState if (d.exp) { buf.writeByte('['); - toCBuffer(d.exp, buf, *hgs); + toCBuffer(d.exp, buf, hgs); buf.writeByte(']'); } else @@ -3965,7 +4077,7 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState } -private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) +private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs) { void visitType(Type t) { @@ -4155,13 +4267,13 @@ private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) buf.writestring("const "); if (hgs.importcHdr && t.id) { - buf.writestring(t.id.toChars()); + buf.writestring(t.id.toString()); return; } - buf.writestring(Token.toChars(t.tok)); + buf.writestring(Token.toString(t.tok)); buf.writeByte(' '); if (t.id) - buf.writestring(t.id.toChars()); + buf.writestring(t.id.toString()); if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) { buf.writestring(" : "); diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h index e43a355..e38ca56 100644 --- a/gcc/d/dmd/hdrgen.h +++ b/gcc/d/dmd/hdrgen.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Dave Fladebo * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -15,7 +15,7 @@ class Module; -void genhdrfile(Module *m, OutBuffer &buf); +void genhdrfile(Module *m, bool doFuncBodies, OutBuffer &buf); void genCppHdrFiles(Modules &ms); -void moduleToBuffer(OutBuffer& buf, Module *m); +void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module *m); const char *parametersTypeToChars(ParameterList pl); diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d index c58224f..24a4513 100644 --- a/gcc/d/dmd/iasm.d +++ b/gcc/d/dmd/iasm.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/iasm.html, Inline Assembler) * - * Copyright (C) 2018-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d, _iasm.d) diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 92837b4..db51e73 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -1,7 +1,7 @@ /** * Inline assembler for the GCC D compiler. * - * Copyright (C) 2018-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved * Authors: Iain Buclaw * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d, _iasmgcc.d) diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 32221d9..5ad324d 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -1,7 +1,7 @@ /** * Contains the `Id` struct with a list of predefined symbols the compiler knows about. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d) @@ -335,6 +335,12 @@ immutable Msgtable[] msgtable = { "_d_arrayassign_l" }, { "_d_arrayassign_r" }, + { "imported" }, + { "InterpolationHeader" }, + { "InterpolationFooter" }, + { "InterpolatedLiteral" }, + { "InterpolatedExpression" }, + // For pragma's { "Pinline", "inline" }, { "lib" }, @@ -521,6 +527,7 @@ immutable Msgtable[] msgtable = { "udaSelector", "selector" }, { "udaOptional", "optional"}, { "udaMustUse", "mustuse" }, + { "udaStandalone", "standalone" }, // C names, for undefined identifier error messages { "NULL" }, diff --git a/gcc/d/dmd/id.h b/gcc/d/dmd/id.h index f6cf6e5..ddc8da2 100644 --- a/gcc/d/dmd/id.h +++ b/gcc/d/dmd/id.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2017-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2017-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index c2b2fba..8ace310 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -1,7 +1,7 @@ /** * Defines an identifier, which is the name of a `Dsymbol`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d) diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h index e7b3ba6..afd3664 100644 --- a/gcc/d/dmd/identifier.h +++ b/gcc/d/dmd/identifier.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d index b45880a..b899f81 100644 --- a/gcc/d/dmd/impcnvtab.d +++ b/gcc/d/dmd/impcnvtab.d @@ -6,7 +6,7 @@ * Specification: $(LINK2 https://dlang.org/spec/type.html#integer-promotions, Integer Promotions), * $(LINK2 https://dlang.org/spec/type.html#usual-arithmetic-conversions, Usual Arithmetic Conversions). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d, _impcnvtab.d) diff --git a/gcc/d/dmd/imphint.d b/gcc/d/dmd/imphint.d index 9e9466a..ea2f13d 100644 --- a/gcc/d/dmd/imphint.d +++ b/gcc/d/dmd/imphint.d @@ -3,7 +3,7 @@ * * For example, prompt to `import std.stdio` when using `writeln`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d, _imphint.d) diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index 624cd74..bfbb551 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -41,7 +41,6 @@ public: const char *kind() const override; Visibility visible() override; Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees - void importAll(Scope *sc) override; Dsymbol *toAlias() override; bool overloadInsert(Dsymbol *s) override; diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 2c7699b..69a85ce 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -3,7 +3,7 @@ * * Specification: C11 * - * Copyright: Copyright (C) 2021-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2021-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d) diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index e484100..62bd41e 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -1,7 +1,7 @@ /** * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d) @@ -12,21 +12,15 @@ module dmd.init; import core.stdc.stdio; -import core.checkedint; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.dsymbol; import dmd.expression; -import dmd.globals; -import dmd.hdrgen; import dmd.identifier; import dmd.location; import dmd.mtype; -import dmd.common.outbuffer; import dmd.rootobject; -import dmd.tokens; import dmd.visitor; enum NeedInterpret : int diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 21bd07f..b4e15e3 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 6d31f95..79d7902 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -1,7 +1,7 @@ /** * Semantic analysis of initializers. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d) @@ -30,6 +30,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -59,36 +60,33 @@ Expression toAssocArrayLiteral(ArrayInitializer ai) { //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars()); //static int i; if (++i == 2) assert(0); - const dim = ai.value.length; - if (!dim) - { - error(ai.loc, "invalid associative array initializer `%s`, use `null` instead", - toChars(ai)); - return ErrorExp.get(); - } + auto no(const char* format, Initializer i) { error(i.loc, format, toChars(i)); return ErrorExp.get(); } - Expression e; - auto keys = new Expressions(dim); + + const dim = ai.value.length; + if (!dim) + return no("invalid associative array initializer `%s`, use `null` instead", ai); + + auto keys = new Expressions(dim); auto values = new Expressions(dim); - for (size_t i = 0; i < dim; i++) + foreach (i, iz; ai.value[]) { - Initializer iz = ai.value[i]; assert(iz); - e = iz.initializerToExpression(); - if (!e) + auto ev = iz.initializerToExpression(); + if (!ev) return no("invalid value `%s` in initializer", iz); - (*values)[i] = e; - e = ai.index[i]; - if (!e) + (*values)[i] = ev; + + auto ei = ai.index[i]; + if (!ei) return no("missing key for value `%s` in initializer", iz); - (*keys)[i] = e; + (*keys)[i] = ei; } - e = new AssocArrayLiteralExp(ai.loc, keys, values); - return e; + return new AssocArrayLiteralExp(ai.loc, keys, values); } /****************************************** @@ -138,8 +136,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ /* This works by replacing the StructInitializer with an ExpInitializer. */ t = t.toBasetype(); - if (t.ty == Tsarray && t.nextOf().toBasetype().ty == Tstruct) - t = t.nextOf().toBasetype(); + if (auto tsa = t.isTypeSArray()) + { + auto ts = tsa.nextOf().toBasetype().isTypeStruct(); + if (ts) + t = ts; + } if (auto ts = t.isTypeStruct()) { StructDeclaration sd = ts.sym; @@ -154,16 +156,17 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (sd.sizeok != Sizeok.done) return err(); - Expression getExp(size_t j, Type fieldType) - { - // Convert initializer to Expression `ex` - auto tm = fieldType.addMod(t.mod); - auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); - auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); - if (ex.op != EXP.error) - i.value[j] = iz; - return ex; - } + Expression getExp(size_t j, Type fieldType) + { + // Convert initializer to Expression `ex` + auto tm = fieldType.addMod(t.mod); + auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); + auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); + if (ex.op != EXP.error) + i.value[j] = iz; + return ex; + } + auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field[], &getExp, (size_t j) => i.value[j].loc); if (!elements) return err(); @@ -232,17 +235,19 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ auto ei = new ExpInitializer(e.loc, e); return ei.initializerSemantic(sc, t, needInterpret); } + case Tpointer: - if (t.nextOf().ty != Tfunction) - break; - goto default; + if (t.nextOf().isTypeFunction()) + goto default; + break; + default: error(i.loc, "cannot use array to initialize `%s`", t.toChars()); return err(); } i.type = t; length = 0; - for (size_t j = 0; j < i.index.length; j++) + for (size_t j = 0; j < i.index.length; j++) // don't replace with foreach; j is modified { Expression idx = i.index[j]; if (idx) @@ -277,9 +282,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ TupleExp te = ei.exp.isTupleExp(); i.index.remove(j); i.value.remove(j); - for (size_t k = 0; k < te.exps.length; ++k) + foreach (k, e; (*te.exps)[]) { - Expression e = (*te.exps)[k]; i.index.insert(j + k, cast(Expression)null); i.value.insert(j + k, new ExpInitializer(e.loc, e)); } @@ -290,7 +294,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { i.value[j] = val; } - length++; + ++length; if (length == 0) { error(i.loc, "array dimension overflow"); @@ -311,7 +315,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { - uinteger_t edim = tsa.dim.toInteger(); + ulong edim = tsa.dim.toInteger(); if (i.dim > edim) { error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); @@ -347,7 +351,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ sc = sc.endCTFE(); if (i.exp.op == EXP.error) return err(); - uint olderrors = global.errors; + const olderrors = global.errors; /* ImportC: convert arrays to pointers, functions to pointers to functions */ @@ -606,7 +610,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { import dmd.common.outbuffer; OutBuffer buf; - HdrGenStage hgs; + HdrGenState hgs; toCBuffer(ts.sym, buf, hgs); printf("%s\n", buf.peekChars()); } @@ -803,9 +807,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Loop1: for (size_t index = 0; index < ci.initializerList.length; ) { - CInitializer cprev; - size_t indexprev; - L1: DesigInit di = ci.initializerList[index]; Designators* dlist = di.designatorList; if (dlist) @@ -833,15 +834,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ continue Loop1; } } - if (cprev) - { - /* The peeling didn't work, so unpeel it - */ - ci = cprev; - index = indexprev; - di = ci.initializerList[index]; - goto L2; - } error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars()); return err(); } @@ -849,18 +841,55 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { if (fieldi == nfields) break; - if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer()) + + auto ix = di.initializer; + + /* If a C initializer is wrapped in a C initializer, with no designators, + * peel off the outer one + */ + if (ix.isCInitializer()) { - /* Try peeling off this set of { } and see if it works + CInitializer cix = ix.isCInitializer(); + if (cix.initializerList.length == 1) + { + DesigInit dix = cix.initializerList[0]; + if (!dix.designatorList) + { + Initializer inix = dix.initializer; + if (inix.isCInitializer()) + ix = inix; + } + } + } + + if (auto cix = ix.isCInitializer()) + { + /* ImportC loses the structure from anonymous structs, but this is retained + * by the initializer syntax. if a CInitializer has a Designator, it is probably + * a nested anonymous struct */ - cprev = ci; - ci = di.initializer.isCInitializer(); - indexprev = index; - index = 0; - goto L1; + if (cix.initializerList.length) + { + DesigInit dix = cix.initializerList[0]; + Designators* dlistx = dix.designatorList; + if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident) + { + auto id = (*dlistx)[0].ident; + foreach (k, f; sd.fields[]) // linear search for now + { + if (f.ident == id) + { + fieldi = k; + si.addInit(id, dix.initializer); + ++fieldi; + ++index; + continue Loop1; + } + } + } + } } - L2: VarDeclaration field; while (1) // skip field if it overlaps with previously seen fields { @@ -871,10 +900,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (fieldi == nfields) break; } + auto tn = field.type.toBasetype(); auto tnsa = tn.isTypeSArray(); auto tns = tn.isTypeStruct(); - auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) { ExpInitializer ei = ix.isExpInitializer(); @@ -1013,7 +1043,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { - error(ci.loc, "unrecognized C initializer `%s`", toChars(ci)); + error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars()); return err(); } } @@ -1144,7 +1174,7 @@ Initializer inferType(Initializer init, Scope* sc) bool hasOverloads; if (auto f = isFuncAddress(init.exp, &hasOverloads)) { - if (f.checkForwardRef(init.loc)) + if (checkForwardRef(f, init.loc)) { return new ErrorInitializer(); } @@ -1548,6 +1578,11 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr); return null; } + if (fieldi >= nfields) + { + error(argLoc, "trying to initialize past the last field `%s` of `%s`", sd.fields[nfields - 1].toChars(), sd.toChars()); + return null; + } VarDeclaration vd = sd.fields[fieldi]; if (elems[fieldi]) diff --git a/gcc/d/dmd/inline.d b/gcc/d/dmd/inline.d index afab831..3e163ae 100644 --- a/gcc/d/dmd/inline.d +++ b/gcc/d/dmd/inline.d @@ -4,7 +4,7 @@ * The AST is traversed, and every function call is considered for inlining using `inlinecost.d`. * The function call is then inlined if this cost is below a threshold. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inline.d, _inline.d) diff --git a/gcc/d/dmd/intrange.d b/gcc/d/dmd/intrange.d index 442668f..29c8b50 100644 --- a/gcc/d/dmd/intrange.d +++ b/gcc/d/dmd/intrange.d @@ -1,7 +1,7 @@ /** * Implement $(LINK2 https://digitalmars.com/articles/b62.html, Value Range Propagation). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d) diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 11ab816..7c65067 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -1,7 +1,7 @@ /** * Code for generating .json descriptions of the module when passing the `-X` flag to dmd. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d) @@ -873,12 +873,9 @@ public: propertyStart("predefinedVersions"); arrayStart(); - if (global.versionids) + foreach (const versionid; global.versionids) { - foreach (const versionid; *global.versionids) - { - item(versionid.toString()); - } + item(versionid.toString()); } arrayEnd(); @@ -905,12 +902,9 @@ public: propertyStart("importPaths"); arrayStart(); - if (global.params.imppath) + foreach (importPath; global.params.imppath[]) { - foreach (importPath; *global.params.imppath) - { - item(importPath.toDString); - } + item(importPath.toDString); } arrayEnd(); diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h index 09fdecd..8a94911 100644 --- a/gcc/d/dmd/json.h +++ b/gcc/d/dmd/json.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index d19d435..a1db8d5 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -5,7 +5,7 @@ * The serialization is a string which contains the type of the parameters and the string * represantation of the lambda expression. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d) @@ -244,7 +244,7 @@ public: { // we must check what the identifier expression is. Dsymbol scopesym; - Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); + Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) { auto v = s.isVarDeclaration(); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index b8faec7..937597c 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/lex.html, Lexical) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d) @@ -506,6 +506,29 @@ class Lexer } else goto case_ident; + case 'i': + if (Ccompile) + goto case_ident; + if (p[1] == '"') + { + p++; // skip the i + escapeStringConstant(t, true); + return; + } + else if (p[1] == '`') + { + p++; // skip the i + wysiwygStringConstant(t, true); + return; + } + else if (p[1] == 'q' && p[2] == '{') + { + p += 2; // skip the i and q + tokenStringConstant(t, true); + return; + } + else + goto case_ident; case '"': escapeStringConstant(t); return; @@ -517,7 +540,7 @@ class Lexer case 'f': case 'g': case 'h': - case 'i': + /*case 'i':*/ case 'j': case 'k': case 'l': @@ -1429,9 +1452,18 @@ class Lexer Params: result = pointer to the token that accepts the result */ - private void wysiwygStringConstant(Token* result) + private void wysiwygStringConstant(Token* result, bool supportInterpolation = false) { - result.value = TOK.string_; + if (supportInterpolation) + { + result.value = TOK.interpolated; + result.interpolatedSet = null; + } + else + { + result.value = TOK.string_; + } + Loc start = loc(); auto terminator = p[0]; p++; @@ -1451,6 +1483,14 @@ class Lexer c = '\n'; // treat EndOfLine as \n character endOfLine(); break; + case '$': + if (!supportInterpolation) + goto default; + + if (!handleInterpolatedSegment(result, start)) + goto default; + + continue; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); @@ -1461,7 +1501,11 @@ class Lexer default: if (c == terminator) { - result.setString(stringbuffer); + if (supportInterpolation) + result.appendInterpolatedPart(stringbuffer); + else + result.setString(stringbuffer); + stringPostfix(result); return; } @@ -1736,13 +1780,21 @@ class Lexer Params: result = pointer to the token that accepts the result */ - private void tokenStringConstant(Token* result) + private void tokenStringConstant(Token* result, bool supportInterpolation = false) { - result.value = TOK.string_; + if (supportInterpolation) + { + result.value = TOK.interpolated; + result.interpolatedSet = null; + } + else + { + result.value = TOK.string_; + } uint nest = 1; const start = loc(); - const pstart = ++p; + auto pstart = ++p; inTokenStringConstant++; scope(exit) inTokenStringConstant--; while (1) @@ -1757,11 +1809,29 @@ class Lexer case TOK.rightCurly: if (--nest == 0) { - result.setString(pstart, p - 1 - pstart); + if (supportInterpolation) + result.appendInterpolatedPart(pstart, p - 1 - pstart); + else + result.setString(pstart, p - 1 - pstart); + stringPostfix(result); return; } continue; + case TOK.dollar: + if (!supportInterpolation) + goto default; + + stringbuffer.setsize(0); + stringbuffer.write(pstart, p - 1 - pstart); + if (!handleInterpolatedSegment(result, start)) + goto default; + + stringbuffer.setsize(0); + + pstart = p; + + continue; case TOK.endOfFile: error("unterminated token string constant starting at %s", start.toChars()); result.setString(); @@ -1772,6 +1842,52 @@ class Lexer } } + // returns true if it got special treatment as an interpolated segment + // otherwise returns false, indicating to treat it as just part of a normal string + private bool handleInterpolatedSegment(Token* token, Loc start) + { + switch(*p) + { + case '(': + // expression, at this level we need to scan until the closing ')' + + // always put the string part in first + token.appendInterpolatedPart(stringbuffer); + stringbuffer.setsize(0); + + int openParenCount = 1; + p++; // skip the first open paren + auto pstart = p; + while (openParenCount > 0) + { + // need to scan with the lexer to support embedded strings and other complex cases + Token tok; + scan(&tok); + if (tok.value == TOK.leftParenthesis) + openParenCount++; + if (tok.value == TOK.rightParenthesis) + openParenCount--; + if (tok.value == TOK.endOfFile) + { + // FIXME: make this error better, it spams a lot + error("unterminated interpolated string constant starting at %s", start.toChars()); + return false; + } + } + + // then put the interpolated string segment + token.appendInterpolatedPart(pstart[0 .. p - 1 - pstart]); + + stringbuffer.setsize(0); // make sure this is reset from the last token scan + // otherwise something like i"$(func("thing")) stuff" can still include it + + return true; + default: + // nothing special + return false; + } + } + /** Scan a quoted string while building the processed string value by handling escape sequences. The result is returned in the given `t` token. @@ -1783,9 +1899,17 @@ class Lexer * D https://dlang.org/spec/lex.html#double_quoted_strings * ImportC C11 6.4.5 */ - private void escapeStringConstant(Token* t) + private void escapeStringConstant(Token* t, bool supportInterpolation = false) { - t.value = TOK.string_; + if (supportInterpolation) + { + t.value = TOK.interpolated; + t.interpolatedSet = null; + } + else + { + t.value = TOK.string_; + } const start = loc(); const tc = *p++; // opening quote @@ -1813,11 +1937,28 @@ class Lexer c = escapeSequence(c2); stringbuffer.writeUTF8(c); continue; + case '$': + if (supportInterpolation) + { + p++; // skip escaped $ + stringbuffer.writeByte('$'); + continue; + } + else + goto default; default: c = escapeSequence(c2); break; } break; + case '$': + if (!supportInterpolation) + goto default; + + if (!handleInterpolatedSegment(t, start)) + goto default; + + continue; case '\n': endOfLine(); if (Ccompile) @@ -1835,7 +1976,10 @@ class Lexer case '"': if (c != tc) goto default; - t.setString(stringbuffer); + if (supportInterpolation) + t.appendInterpolatedPart(stringbuffer); + else + t.setString(stringbuffer); if (!Ccompile) stringPostfix(t); return; @@ -2008,23 +2152,17 @@ class Lexer case 'u': dchar d1; size_t idx; - auto msg = utf_decodeChar(str, idx, d1); - dchar d2 = 0; - if (idx < n && !msg) - msg = utf_decodeChar(str, idx, d2); - if (msg) - error(loc, "%.*s", cast(int)msg.length, msg.ptr); - else if (idx < n) - error(loc, "max number of chars in 16 bit character literal is 2, had %d", - cast(int)((n + 1) >> 1)); - else if (d1 > 0x1_0000) - error(loc, "%d does not fit in 16 bits", d1); - else if (d2 > 0x1_0000) - error(loc, "%d does not fit in 16 bits", d2); - u = d1; - if (d2) - u = (d1 << 16) | d2; - break; + while (idx < n) + { + string msg = utf_decodeChar(str, idx, d1); + if (msg) + error(loc, "%.*s", cast(int)msg.length, msg.ptr); + } + if (d1 >= 0x1_0000) + error(loc, "x%x does not fit in 16 bits", d1); + t.unsvalue = d1; + t.value = TOK.wcharLiteral; // C11 6.4.4.4-9 + return; case 'U': dchar d; @@ -2035,8 +2173,9 @@ class Lexer else if (idx < n) error(loc, "max number of chars in 32 bit character literal is 1, had %d", cast(int)((n + 3) >> 2)); - u = d; - break; + t.unsvalue = d; + t.value = TOK.dcharLiteral; // C11 6.4.4.4-9 + return; default: assert(0); @@ -3270,7 +3409,7 @@ class Lexer while (1) { printf("%s ", (*tk).toChars()); - if (tk.value == TOK.endOfFile) + if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine) break; tk = peek(tk); } diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d index 9fe48b8..d71ea58 100644 --- a/gcc/d/dmd/location.d +++ b/gcc/d/dmd/location.d @@ -1,7 +1,7 @@ /** * Encapsulates file/line/column locations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/location.d, _location.d) diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h index aa24698..68064a9 100644 --- a/gcc/d/dmd/mangle.h +++ b/gcc/d/dmd/mangle.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index cab0b0a..d09e873 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -88,7 +88,7 @@ public: Identifier *searchCacheIdent; Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags + SearchOptFlags searchCacheFlags; // cached flags d_bool insearch; // module from command line we're imported from, @@ -121,9 +121,8 @@ public: const char *kind() const override; bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise. Module *parse(); // syntactic parse - void importAll(Scope *sc) override; int needModuleInfo(); - bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override; + bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override; Dsymbol *symtabInsert(Dsymbol *s) override; static void runDeferredSemantic(); static void runDeferredSemantic2(); diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 8860f14..c46f560 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -1,7 +1,7 @@ /** * Defines a D type. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d) @@ -19,31 +19,24 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; -import dmd.attrib; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; import dmd.dclass; -import dmd.dcast; import dmd.declaration; import dmd.denum; -import dmd.dmangle; -import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; -import dmd.dsymbolsem; import dmd.dtemplate; +import dmd.enumsem; import dmd.errors; import dmd.expression; -import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; import dmd.identifier; -import dmd.init; import dmd.location; -import dmd.opover; import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.rmem; @@ -59,6 +52,12 @@ enum LOGDEFAULTINIT = 0; // log ::defaultInit() enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions +static if (__VERSION__ < 2095) +{ + // Fix linker errors when building with older compilers. + // See: https://issues.dlang.org/show_bug.cgi?id=21299 + private alias StringValueType = StringValue!Type; +} /*************************** * Return !=0 if modfrom can be implicitly converted to modto @@ -258,57 +257,6 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe return ty == Tchar || ty == Twchar || ty == Tdchar; } -/************************************ - * Determine mutability of indirections in (ref) t. - * - * Returns: When the type has any mutable indirections, returns 0. - * When all indirections are immutable, returns 2. - * Otherwise, when the type has const/inout indirections, returns 1. - * - * Params: - * isref = if true, check `ref t`; otherwise, check just `t` - * t = the type that is being checked - */ -int mutabilityOfType(bool isref, Type t) -{ - if (isref) - { - if (t.mod & MODFlags.immutable_) - return 2; - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - return 0; - } - - t = t.baseElemOf(); - - if (!t.hasPointers() || t.mod & MODFlags.immutable_) - return 2; - - /* Accept immutable(T)[] and immutable(T)* as being strongly pure - */ - if (t.ty == Tarray || t.ty == Tpointer) - { - Type tn = t.nextOf().toBasetype(); - if (tn.mod & MODFlags.immutable_) - return 2; - if (tn.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - } - - /* The rest of this is too strict; fix later. - * For example, the only pointer members of a struct may be immutable, - * which would maintain strong purity. - * (Just like for dynamic arrays and pointers above.) - */ - if (t.mod & (MODFlags.const_ | MODFlags.wild)) - return 1; - - /* Should catch delegates and function pointers, and fold in their purity - */ - return 0; -} - /**************** * dotExp() bit flags */ @@ -357,7 +305,7 @@ extern (C++) abstract class Type : ASTNode Type swto; // MODFlags.shared_ | MODFlags.wild Type swcto; // MODFlags.shared_ | MODFlags.wildconst } - private Mcache* mcache; + Mcache* mcache; Type pto; // merged pointer to this type Type rto; // reference to this type @@ -365,7 +313,7 @@ extern (C++) abstract class Type : ASTNode TypeInfoDeclaration vtinfo; // TypeInfo object for this Type - type* ctype; // for back end + void* ctype; // for back end extern (C++) __gshared Type tvoid; extern (C++) __gshared Type tint8; @@ -498,7 +446,7 @@ extern (C++) abstract class Type : ASTNode final bool equivalent(Type t) { - return immutableOf().equals(t.immutableOf()); + return immutableOf(this).equals(t.immutableOf()); } // kludge for template.isType() @@ -522,274 +470,12 @@ extern (C++) abstract class Type : ASTNode return mcache; } - /******************************* - * Covariant means that 'this' can substitute for 't', - * i.e. a pure function is a match for an impure type. - * Params: - * t = type 'this' is covariant with - * pstc = if not null, store STCxxxx which would make it covariant - * cppCovariant = true if extern(C++) function types should follow C++ covariant rules - * Returns: - * An enum value of either `Covariant.yes` or a reason it's not covariant. - */ - final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false) - { - version (none) - { - printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars()); - printf("deco = %p, %p\n", deco, t.deco); - // printf("ty = %d\n", next.ty); - printf("mod = %x, %x\n", mod, t.mod); - } - if (pstc) - *pstc = 0; - StorageClass stc = 0; - - bool notcovariant = false; - - if (equals(t)) - return Covariant.yes; - - TypeFunction t1 = this.isTypeFunction(); - TypeFunction t2 = t.isTypeFunction(); - - if (!t1 || !t2) - goto Ldistinct; - - if (t1.parameterList.varargs != t2.parameterList.varargs) - goto Ldistinct; - - if (t1.parameterList.parameters && t2.parameterList.parameters) - { - if (t1.parameterList.length != t2.parameterList.length) - goto Ldistinct; - - foreach (i, fparam1; t1.parameterList) - { - Parameter fparam2 = t2.parameterList[i]; - Type tp1 = fparam1.type; - Type tp2 = fparam2.type; - - if (!tp1.equals(tp2)) - { - if (tp1.ty == tp2.ty) - { - if (auto tc1 = tp1.isTypeClass()) - { - if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) - goto Lcov; - } - else if (auto ts1 = tp1.isTypeStruct()) - { - if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) - goto Lcov; - } - else if (tp1.ty == Tpointer) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - else if (tp1.ty == Tarray) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - else if (tp1.ty == Tdelegate) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - } - goto Ldistinct; - } - Lcov: - notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); - - /* https://issues.dlang.org/show_bug.cgi?id=23135 - * extern(C++) mutable parameters are not covariant with const. - */ - if (t1.linkage == LINK.cpp && cppCovariant) - { - notcovariant |= tp1.isNaked() != tp2.isNaked(); - if (auto tpn1 = tp1.nextOf()) - notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); - } - } - } - else if (t1.parameterList.parameters != t2.parameterList.parameters) - { - if (t1.parameterList.length || t2.parameterList.length) - goto Ldistinct; - } - - // The argument lists match - if (notcovariant) - goto Lnotcovariant; - if (t1.linkage != t2.linkage) - goto Lnotcovariant; - - { - // Return types - Type t1n = t1.next; - Type t2n = t2.next; - - if (!t1n || !t2n) // happens with return type inference - goto Lnotcovariant; - - if (t1n.equals(t2n)) - goto Lcovariant; - if (t1n.ty == Tclass && t2n.ty == Tclass) - { - /* If same class type, but t2n is const, then it's - * covariant. Do this test first because it can work on - * forward references. - */ - if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) - goto Lcovariant; - - // If t1n is forward referenced: - ClassDeclaration cd = (cast(TypeClass)t1n).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (!cd.isBaseInfoComplete()) - { - return Covariant.fwdref; - } - } - if (t1n.ty == Tstruct && t2n.ty == Tstruct) - { - if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) - goto Lcovariant; - } - else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) - { - if (t1.isref && t2.isref) - { - // Treat like pointers to t1n and t2n - if (t1n.constConv(t2n) < MATCH.constant) - goto Lnotcovariant; - } - goto Lcovariant; - } - else if (t1n.ty == Tnull) - { - // NULL is covariant with any pointer type, but not with any - // dynamic arrays, associative arrays or delegates. - // https://issues.dlang.org/show_bug.cgi?id=8589 - // https://issues.dlang.org/show_bug.cgi?id=19618 - Type t2bn = t2n.toBasetype(); - if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) - goto Lcovariant; - } - // bottom type is covariant to any type - else if (t1n.ty == Tnoreturn) - goto Lcovariant; - } - goto Lnotcovariant; - - Lcovariant: - if (t1.isref != t2.isref) - goto Lnotcovariant; - - if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) - { - StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; - StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; - if (t1.isreturn) - { - stc1 |= STC.return_; - if (!t1.isScopeQual) - stc1 |= STC.ref_; - } - if (t2.isreturn) - { - stc2 |= STC.return_; - if (!t2.isScopeQual) - stc2 |= STC.ref_; - } - if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) - goto Lnotcovariant; - } - - // We can subtract 'return ref' from 'this', but cannot add it - else if (t1.isreturn && !t2.isreturn) - goto Lnotcovariant; - - /* https://issues.dlang.org/show_bug.cgi?id=23135 - * extern(C++) mutable member functions are not covariant with const. - */ - if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) - goto Lnotcovariant; - - /* Can convert mutable to const - */ - if (!MODimplicitConv(t2.mod, t1.mod)) - { - version (none) - { - //stop attribute inference with const - // If adding 'const' will make it covariant - if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) - stc |= STC.const_; - else - goto Lnotcovariant; - } - else - { - goto Ldistinct; - } - } - - /* Can convert pure to impure, nothrow to throw, and nogc to gc - */ - if (!t1.purity && t2.purity) - stc |= STC.pure_; - - if (!t1.isnothrow && t2.isnothrow) - stc |= STC.nothrow_; - - if (!t1.isnogc && t2.isnogc) - stc |= STC.nogc; - - /* Can convert safe/trusted to system - */ - if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) - { - // Should we infer trusted or safe? Go with safe. - stc |= STC.safe; - } - - if (stc) - { - if (pstc) - *pstc = stc; - goto Lnotcovariant; - } - - //printf("\tcovaraint: 1\n"); - return Covariant.yes; - - Ldistinct: - //printf("\tcovaraint: 0\n"); - return Covariant.distinct; - - Lnotcovariant: - //printf("\tcovaraint: 2\n"); - return Covariant.no; - } - /******************************** * For pretty-printing a type. */ final override const(char)* toChars() const { - OutBuffer buf; - buf.reserve(16); - HdrGenState hgs; - hgs.fullQual = (ty == Tclass && !mod); - - toCBuffer(this, buf, null, hgs); - return buf.extractChars(); + return dmd.hdrgen.toChars(this); } /// ditto @@ -838,16 +524,39 @@ extern (C++) abstract class Type : ASTNode Terror ]; + static Type merge(Type t) + { + import dmd.basicmangle : tyToDecoBuffer; + + OutBuffer buf; + buf.reserve(3); + + if (t.ty == Tnoreturn) + buf.writestring("Nn"); + else + tyToDecoBuffer(buf, t.ty); + + auto sv = t.stringtable.update(buf[]); + if (sv.value) + return sv.value; + else + { + t.deco = cast(char*)sv.toDchars(); + sv.value = t; + return t; + } + } + for (size_t i = 0; basetab[i] != Terror; i++) { Type t = new TypeBasic(basetab[i]); - t = t.merge(); + t = merge(t); basic[basetab[i]] = t; } basic[Terror] = new TypeError(); tnoreturn = new TypeNoreturn(); - tnoreturn.deco = tnoreturn.merge().deco; + tnoreturn.deco = merge(tnoreturn).deco; basic[Tnoreturn] = tnoreturn; tvoid = basic[Tvoid]; @@ -882,7 +591,7 @@ extern (C++) abstract class Type : ASTNode terror = basic[Terror]; tnoreturn = basic[Tnoreturn]; tnull = new TypeNull(); - tnull.deco = tnull.merge().deco; + tnull.deco = merge(tnull).deco; tvoidptr = tvoid.pointerTo(); tstring = tchar.immutableOf().arrayOf(); @@ -923,54 +632,6 @@ extern (C++) abstract class Type : ASTNode return cast(uint)size(Loc.initial); } - final Type trySemantic(const ref Loc loc, Scope* sc) - { - //printf("+trySemantic(%s) %d\n", toChars(), global.errors); - - // Needed to display any deprecations that were gagged - auto tcopy = this.syntaxCopy(); - - const errors = global.startGagging(); - Type t = typeSemantic(this, loc, sc); - if (global.endGagging(errors) || t.ty == Terror) // if any errors happened - { - t = null; - } - else - { - // If `typeSemantic` succeeded, there may have been deprecations that - // were gagged due the `startGagging` above. Run again to display - // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 - if (global.gaggedWarnings > 0) - typeSemantic(tcopy, loc, sc); - } - //printf("-trySemantic(%s) %d\n", toChars(), global.errors); - return t; - } - - /************************************* - * This version does a merge even if the deco is already computed. - * Necessary for types that have a deco, but are not merged. - */ - final Type merge2() - { - //printf("merge2(%s)\n", toChars()); - Type t = this; - assert(t); - if (!t.deco) - return t.merge(); - - auto sv = stringtable.lookup(t.deco, strlen(t.deco)); - if (sv && sv.value) - { - t = sv.value; - assert(t.deco); - } - else - assert(0); - return t; - } - /********************************* * Store this type's modifier name into buf. */ @@ -1061,17 +722,6 @@ extern (C++) abstract class Type : ASTNode return isscalar(); } - /********************************* - * Check type to see if it is based on a deprecated symbol. - */ - void checkDeprecated(const ref Loc loc, Scope* sc) - { - if (Dsymbol s = toDsymbol(sc)) - { - s.checkDeprecated(loc, sc); - } - } - final bool isConst() const nothrow pure @nogc @safe { return (mod & MODFlags.const_) != 0; @@ -1141,255 +791,6 @@ extern (C++) abstract class Type : ASTNode return t; } - /******************************** - * Convert to 'const'. - */ - final Type constOf() - { - //printf("Type::constOf() %p %s\n", this, toChars()); - if (mod == MODFlags.const_) - return this; - if (mcache && mcache.cto) - { - assert(mcache.cto.mod == MODFlags.const_); - return mcache.cto; - } - Type t = makeConst(); - t = t.merge(); - t.fixTo(this); - //printf("-Type::constOf() %p %s\n", t, t.toChars()); - return t; - } - - /******************************** - * Convert to 'immutable'. - */ - final Type immutableOf() - { - //printf("Type::immutableOf() %p %s\n", this, toChars()); - if (isImmutable()) - return this; - if (mcache && mcache.ito) - { - assert(mcache.ito.isImmutable()); - return mcache.ito; - } - Type t = makeImmutable(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p\n", t); - return t; - } - - /******************************** - * Make type mutable. - */ - final Type mutableOf() - { - //printf("Type::mutableOf() %p, %s\n", this, toChars()); - Type t = this; - if (isImmutable()) - { - getMcache(); - t = mcache.ito; // immutable => naked - assert(!t || (t.isMutable() && !t.isShared())); - } - else if (isConst()) - { - getMcache(); - if (isShared()) - { - if (isWild()) - t = mcache.swcto; // shared wild const -> shared - else - t = mcache.sto; // shared const => shared - } - else - { - if (isWild()) - t = mcache.wcto; // wild const -> naked - else - t = mcache.cto; // const => naked - } - assert(!t || t.isMutable()); - } - else if (isWild()) - { - getMcache(); - if (isShared()) - t = mcache.sto; // shared wild => shared - else - t = mcache.wto; // wild => naked - assert(!t || t.isMutable()); - } - if (!t) - { - t = makeMutable(); - t = t.merge(); - t.fixTo(this); - } - else - t = t.merge(); - assert(t.isMutable()); - return t; - } - - final Type sharedOf() - { - //printf("Type::sharedOf() %p, %s\n", this, toChars()); - if (mod == MODFlags.shared_) - return this; - if (mcache && mcache.sto) - { - assert(mcache.sto.mod == MODFlags.shared_); - return mcache.sto; - } - Type t = makeShared(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p\n", t); - return t; - } - - final Type sharedConstOf() - { - //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); - if (mod == (MODFlags.shared_ | MODFlags.const_)) - return this; - if (mcache && mcache.scto) - { - assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); - return mcache.scto; - } - Type t = makeSharedConst(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p\n", t); - return t; - } - - /******************************** - * Make type unshared. - * 0 => 0 - * const => const - * immutable => immutable - * shared => 0 - * shared const => const - * wild => wild - * wild const => wild const - * shared wild => wild - * shared wild const => wild const - */ - final Type unSharedOf() - { - //printf("Type::unSharedOf() %p, %s\n", this, toChars()); - Type t = this; - - if (isShared()) - { - getMcache(); - if (isWild()) - { - if (isConst()) - t = mcache.wcto; // shared wild const => wild const - else - t = mcache.wto; // shared wild => wild - } - else - { - if (isConst()) - t = mcache.cto; // shared const => const - else - t = mcache.sto; // shared => naked - } - assert(!t || !t.isShared()); - } - - if (!t) - { - t = this.nullAttributes(); - t.mod = mod & ~MODFlags.shared_; - t.ctype = ctype; - t = t.merge(); - t.fixTo(this); - } - else - t = t.merge(); - assert(!t.isShared()); - return t; - } - - /******************************** - * Convert to 'wild'. - */ - final Type wildOf() - { - //printf("Type::wildOf() %p %s\n", this, toChars()); - if (mod == MODFlags.wild) - return this; - if (mcache && mcache.wto) - { - assert(mcache.wto.mod == MODFlags.wild); - return mcache.wto; - } - Type t = makeWild(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - - final Type wildConstOf() - { - //printf("Type::wildConstOf() %p %s\n", this, toChars()); - if (mod == MODFlags.wildconst) - return this; - if (mcache && mcache.wcto) - { - assert(mcache.wcto.mod == MODFlags.wildconst); - return mcache.wcto; - } - Type t = makeWildConst(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - - final Type sharedWildOf() - { - //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); - if (mod == (MODFlags.shared_ | MODFlags.wild)) - return this; - if (mcache && mcache.swto) - { - assert(mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild)); - return mcache.swto; - } - Type t = makeSharedWild(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - - final Type sharedWildConstOf() - { - //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars()); - if (mod == (MODFlags.shared_ | MODFlags.wildconst)) - return this; - if (mcache && mcache.swcto) - { - assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); - return mcache.swcto; - } - Type t = makeSharedWildConst(); - t = t.merge(); - t.fixTo(this); - //printf("\t%p %s\n", t, t.toChars()); - return t; - } - /********************************** * For our new type 'this', which is type-constructed from t, * fill in the cto, ito, sto, scto, wto shortcuts. @@ -1791,56 +1192,6 @@ extern (C++) abstract class Type : ASTNode } /************************************ - * Apply MODxxxx bits to existing type. - */ - final Type castMod(MOD mod) - { - Type t; - switch (mod) - { - case 0: - t = unSharedOf().mutableOf(); - break; - - case MODFlags.const_: - t = unSharedOf().constOf(); - break; - - case MODFlags.wild: - t = unSharedOf().wildOf(); - break; - - case MODFlags.wildconst: - t = unSharedOf().wildConstOf(); - break; - - case MODFlags.shared_: - t = mutableOf().sharedOf(); - break; - - case MODFlags.shared_ | MODFlags.const_: - t = sharedConstOf(); - break; - - case MODFlags.shared_ | MODFlags.wild: - t = sharedWildOf(); - break; - - case MODFlags.shared_ | MODFlags.wildconst: - t = sharedWildConstOf(); - break; - - case MODFlags.immutable_: - t = immutableOf(); - break; - - default: - assert(0); - } - return t; - } - - /************************************ * Add MODxxxx bits to existing type. * We're adding, not replacing, so adding const to * a shared type => "shared const" @@ -1862,16 +1213,16 @@ extern (C++) abstract class Type : ASTNode if (isShared()) { if (isWild()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedConstOf(); + t = this.sharedConstOf(); } else { - if (isWild()) - t = wildConstOf(); + if (this.isWild()) + t = this.wildConstOf(); else - t = constOf(); + t = t.constOf(); } break; @@ -1879,63 +1230,63 @@ extern (C++) abstract class Type : ASTNode if (isShared()) { if (isConst()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedWildOf(); + t = this.sharedWildOf(); } else { if (isConst()) - t = wildConstOf(); + t = this.wildConstOf(); else - t = wildOf(); + t = this.wildOf(); } break; case MODFlags.wildconst: if (isShared()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = wildConstOf(); + t = this.wildConstOf(); break; case MODFlags.shared_: if (isWild()) { if (isConst()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedWildOf(); + t = this.sharedWildOf(); } else { if (isConst()) - t = sharedConstOf(); + t = this.sharedConstOf(); else - t = sharedOf(); + t = this.sharedOf(); } break; case MODFlags.shared_ | MODFlags.const_: if (isWild()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedConstOf(); + t = this.sharedConstOf(); break; case MODFlags.shared_ | MODFlags.wild: if (isConst()) - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); else - t = sharedWildOf(); + t = this.sharedWildOf(); break; case MODFlags.shared_ | MODFlags.wildconst: - t = sharedWildConstOf(); + t = this.sharedWildConstOf(); break; case MODFlags.immutable_: - t = immutableOf(); + t = this.immutableOf(); break; default: @@ -2051,7 +1402,7 @@ extern (C++) abstract class Type : ASTNode if (callable) { auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet); - if (!fd || fd.errors || !fd.functionSemantic()) + if (!fd || fd.errors || !functionSemantic(fd)) return Type.terror; auto t = fd.type.nextOf(); @@ -2182,11 +1533,6 @@ extern (C++) abstract class Type : ASTNode return t; } - Dsymbol toDsymbol(Scope* sc) - { - return null; - } - /******************************* * If this is a shell around another type, * get that other type. @@ -2200,11 +1546,6 @@ extern (C++) abstract class Type : ASTNode return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; } - bool isBaseOf(Type t, int* poffset) - { - return 0; // assume not - } - /******************************** * Determine if 'this' can be implicitly converted * to type 'to'. @@ -2356,7 +1697,7 @@ extern (C++) abstract class Type : ASTNode final Type unqualify(uint m) { - Type t = mutableOf().unSharedOf(); + Type t = this.mutableOf().unSharedOf(); Type tn = ty == Tenum ? null : nextOf(); if (tn && tn.ty != Tfunction) @@ -2430,32 +1771,6 @@ extern (C++) abstract class Type : ASTNode return false; // assume not } - final Identifier getTypeInfoIdent() - { - // _init_10TypeInfo_%s - OutBuffer buf; - buf.reserve(32); - mangleToBuffer(this, buf); - - const slice = buf[]; - - // Allocate buffer on stack, fail over to using malloc() - char[128] namebuf; - const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; - auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); - - const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", - cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); - //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); - assert(0 < length && length < namelen); // don't overflow the buffer - - auto id = Identifier.idPool(name[0 .. length]); - - if (name != namebuf.ptr) - free(name); - return id; - } - /*************************************** * Return !=0 if the type or any of its subtypes is wild. */ @@ -2464,16 +1779,6 @@ extern (C++) abstract class Type : ASTNode return mod & MODFlags.wild; } - /*************************************** - * Return !=0 if type has pointers that need to - * be scanned by the GC during a collection cycle. - */ - bool hasPointers() - { - //printf("Type::hasPointers() %s, %d\n", toChars(), ty); - return false; - } - /************************************* * Detect if type has pointer fields that are initialized to void. * Local stack variables with such void fields can remain uninitialized, @@ -2615,76 +1920,6 @@ extern (C++) abstract class Type : ASTNode return false; } - /************************************* - * https://issues.dlang.org/show_bug.cgi?id=14488 - * Check if the inner most base type is complex or imaginary. - * Should only give alerts when set to emit transitional messages. - * Params: - * loc = The source location. - * sc = scope of the type - */ - extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc) - { - if (sc.isDeprecated()) - return false; - // Don't complain if we're inside a template constraint - // https://issues.dlang.org/show_bug.cgi?id=21831 - if (sc.flags & SCOPE.constraint) - return false; - - Type t = baseElemOf(); - while (t.ty == Tpointer || t.ty == Tarray) - t = t.nextOf().baseElemOf(); - - // Basetype is an opaque enum, nothing to check. - if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) - return false; - - if (t.isimaginary() || t.iscomplex()) - { - if (sc.flags & SCOPE.Cfile) - return true; // complex/imaginary not deprecated in C code - Type rt; - switch (t.ty) - { - case Tcomplex32: - case Timaginary32: - rt = Type.tfloat32; - break; - - case Tcomplex64: - case Timaginary64: - rt = Type.tfloat64; - break; - - case Tcomplex80: - case Timaginary80: - rt = Type.tfloat80; - break; - - default: - assert(0); - } - // @@@DEPRECATED_2.117@@@ - // Deprecated in 2.097 - Can be made an error from 2.117. - // The deprecation period is longer than usual as `cfloat`, - // `cdouble`, and `creal` were quite widely used. - if (t.iscomplex()) - { - deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", - toChars(), rt.toChars()); - return true; - } - else - { - deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", - toChars(), rt.toChars()); - return true; - } - } - return false; - } - // For eliminating dynamic_cast TypeBasic isTypeBasic() { @@ -2825,13 +2060,6 @@ extern (C++) abstract class TypeNext : Type this.next = next; } - override final void checkDeprecated(const ref Loc loc, Scope* sc) - { - Type.checkDeprecated(loc, sc); - if (next) // next can be NULL if TypeFunction and auto return type - next.checkDeprecated(loc, sc); - } - override final int hasWild() const { if (ty == Tfunction) @@ -3813,24 +3041,6 @@ extern (C++) final class TypeSArray : TypeArray return ae; } - override bool hasPointers() - { - /* Don't want to do this, because: - * struct S { T* array[0]; } - * may be a variable length struct. - */ - //if (dim.toInteger() == 0) - // return false; - - if (next.ty == Tvoid) - { - // Arrays of void contain arbitrary data, which may include pointers - return true; - } - else - return next.hasPointers(); - } - override bool hasSystemFields() { return next.hasSystemFields(); @@ -3955,11 +3165,6 @@ extern (C++) final class TypeDArray : TypeArray return Type.implicitConvTo(to); } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4016,11 +3221,6 @@ extern (C++) final class TypeAArray : TypeArray return true; } - override bool hasPointers() - { - return true; - } - override MATCH implicitConvTo(Type to) { //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); @@ -4159,11 +3359,6 @@ extern (C++) final class TypePointer : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4341,39 +3536,6 @@ extern (C++) final class TypeFunction : TypeNext } /******************************************** - * Set 'purity' field of 'this'. - * Do this lazily, as the parameter types might be forward referenced. - */ - void purityLevel() - { - TypeFunction tf = this; - if (tf.purity != PURE.fwdref) - return; - - purity = PURE.const_; // assume strong until something weakens it - - /* Evaluate what kind of purity based on the modifiers for the parameters - */ - foreach (i, fparam; tf.parameterList) - { - Type t = fparam.type; - if (!t) - continue; - - if (fparam.storageClass & (STC.lazy_ | STC.out_)) - { - purity = PURE.weak; - break; - } - const pref = (fparam.storageClass & STC.ref_) != 0; - if (mutabilityOfType(pref, t) == 0) - purity = PURE.weak; - } - - tf.purity = purity; - } - - /******************************************** * Return true if there are lazy parameters. */ bool hasLazyParameters() @@ -4397,122 +3559,6 @@ extern (C++) final class TypeFunction : TypeNext return linkage == LINK.d && parameterList.varargs == VarArg.variadic; } - /************************************ - * Take the specified storage class for p, - * and use the function signature to infer whether - * STC.scope_ and STC.return_ should be OR'd in. - * (This will not affect the name mangling.) - * Params: - * tthis = type of `this` parameter, null if none - * p = parameter to this function - * outerVars = context variables p could escape into, if any - * indirect = is this for an indirect or virtual function call? - * Returns: - * storage class with STC.scope_ or STC.return_ OR'd in - */ - StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null, - bool indirect = false) - { - //printf("parameterStorageClass(p: %s)\n", p.toChars()); - auto stc = p.storageClass; - - // When the preview switch is enable, `in` parameters are `scope` - if (stc & STC.in_ && global.params.previewIn) - return stc | STC.scope_; - - if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) - return stc; - - /* If haven't inferred the return type yet, can't infer storage classes - */ - if (!nextOf() || !isnothrow()) - return stc; - - purityLevel(); - - static bool mayHavePointers(Type t) - { - if (auto ts = t.isTypeStruct()) - { - auto sym = ts.sym; - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - // struct is forward referenced, so "may have" pointers - return true; - } - return t.hasPointers(); - } - - // See if p can escape via any of the other parameters - if (purity == PURE.weak) - { - /* - * Indirect calls may escape p through a nested context - * See: - * https://issues.dlang.org/show_bug.cgi?id=24212 - * https://issues.dlang.org/show_bug.cgi?id=24213 - */ - if (indirect) - return stc; - - // Check escaping through parameters - foreach (i, fparam; parameterList) - { - Type t = fparam.type; - if (!t) - continue; - t = t.baseElemOf(); // punch thru static arrays - if (t.isMutable() && t.hasPointers()) - { - if (fparam.isReference() && fparam != p) - return stc; - - if (t.ty == Tdelegate) - return stc; // could escape thru delegate - - if (t.ty == Tclass) - return stc; - - /* if t is a pointer to mutable pointer - */ - if (auto tn = t.nextOf()) - { - if (tn.isMutable() && mayHavePointers(tn)) - return stc; // escape through pointers - } - } - } - - // Check escaping through `this` - if (tthis && tthis.isMutable()) - { - foreach (VarDeclaration v; isAggregate(tthis).fields) - { - if (v.hasPointers()) - return stc; - } - } - - // Check escaping through nested context - if (outerVars && this.isMutable()) - { - foreach (VarDeclaration v; *outerVars) - { - if (v.hasPointers()) - return stc; - } - } - } - - // Check escaping through return value - Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) - { - return stc | STC.scope_ | STC.return_ | STC.returnScope; - } - else - return stc | STC.scope_; - } - override Type addStorageClass(StorageClass stc) { //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0); @@ -4612,27 +3658,7 @@ extern (C++) final class TypeFunction : TypeNext return t.merge(); } - // arguments get specially formatted - private const(char)* getParamError(Expression arg, Parameter par) - { - if (global.gag && !global.params.v.showGaggedErrors) - return null; - // show qualification when toChars() is the same but types are different - // https://issues.dlang.org/show_bug.cgi?id=19948 - // when comparing the type with strcmp, we need to drop the qualifier - bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && - strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; - auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); - OutBuffer buf; - // only mention rvalue if it's relevant - const rv = !arg.isLvalue() && par.isReference(); - buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", - rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, - parameterToChars(par, this, qual)); - return buf.extractChars(); - } - - private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args) + extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args) { if (global.gag && !global.params.v.showGaggedErrors) return null; @@ -4642,185 +3668,6 @@ extern (C++) final class TypeFunction : TypeNext } /******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Params: - * tthis = type of `this` pointer, null if not member function - * argumentList = arguments to function call - * flag = 1: performing a partial ordering match - * pMessage = address to store error message, or null - * sc = context - * Returns: - * MATCHxxxx - */ - extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) - { - //printf("TypeFunction::callMatch() %s\n", toChars()); - MATCH match = MATCH.exact; // assume exact match - ubyte wildmatch = 0; - - if (tthis) - { - Type t = tthis; - if (t.toBasetype().ty == Tpointer) - t = t.toBasetype().nextOf(); // change struct* to struct - if (t.mod != mod) - { - if (MODimplicitConv(t.mod, mod)) - match = MATCH.constant; - else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_)) - { - match = MATCH.constant; - } - else - return MATCH.nomatch; - } - if (isWild()) - { - if (t.isWild()) - wildmatch |= MODFlags.wild; - else if (t.isConst()) - wildmatch |= MODFlags.const_; - else if (t.isImmutable()) - wildmatch |= MODFlags.immutable_; - else - wildmatch |= MODFlags.mutable; - } - } - - const nparams = parameterList.length; - if (argumentList.length > nparams) - { - if (parameterList.varargs == VarArg.none) - { - // suppress early exit if an error message is wanted, - // so we can check any matching args are valid - if (!pMessage) - return MATCH.nomatch; - } - // too many args; no match - match = MATCH.convert; // match ... with a "conversion" match level - } - - // https://issues.dlang.org/show_bug.cgi?id=22997 - if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) - { - OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); - if (pMessage) - *pMessage = buf.extractChars(); - return MATCH.nomatch; - } - auto resolvedArgs = resolveNamedArgs(argumentList, pMessage); - Expression[] args; - if (!resolvedArgs) - { - if (!pMessage || *pMessage) - return MATCH.nomatch; - - // if no message was provided, it was because of overflow which will be diagnosed below - match = MATCH.nomatch; - args = argumentList.arguments ? (*argumentList.arguments)[] : null; - } - else - { - args = (*resolvedArgs)[]; - } - - foreach (u, p; parameterList) - { - if (u >= args.length) - break; - - Expression arg = args[u]; - if (!arg) - continue; // default argument - - Type tprm = p.type; - Type targ = arg.type; - - if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) - { - const isRef = p.isReference(); - wildmatch |= targ.deduceWild(tprm, isRef); - } - } - if (wildmatch) - { - /* Calculate wild matching modifier - */ - if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) - wildmatch = MODFlags.const_; - else if (wildmatch & MODFlags.immutable_) - wildmatch = MODFlags.immutable_; - else if (wildmatch & MODFlags.wild) - wildmatch = MODFlags.wild; - else - { - assert(wildmatch & MODFlags.mutable); - wildmatch = MODFlags.mutable; - } - } - - foreach (u, p; parameterList) - { - MATCH m; - - assert(p); - - // One or more arguments remain - if (u < args.length) - { - Expression arg = args[u]; - if (!arg) - continue; // default argument - m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); - } - else if (p.defaultArg) - continue; - - /* prefer matching the element type rather than the array - * type when more arguments are present with T[]... - */ - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) - goto L1; - - //printf("\tm = %d\n", m); - if (m == MATCH.nomatch) // if no match - { - L1: - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param - { - auto trailingArgs = args[u .. $]; - if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage)) - return vmatch < match ? vmatch : match; - // Error message was already generated in `matchTypeSafeVarArgs` - return MATCH.nomatch; - } - if (pMessage && u >= args.length) - *pMessage = getMatchError("missing argument for parameter #%d: `%s`", - u + 1, parameterToChars(p, this, false)); - // If an error happened previously, `pMessage` was already filled - else if (pMessage && !*pMessage) - *pMessage = getParamError(args[u], p); - - return MATCH.nomatch; - } - if (m < match) - match = m; // pick worst match - } - - if (pMessage && !parameterList.varargs && args.length > nparams) - { - // all parameters had a match, but there are surplus args - *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length); - return MATCH.nomatch; - } - //printf("match = %d\n", match); - return match; - } - - /******************************** * Convert an `argumentList`, which may contain named arguments, into * a list of arguments in the order of the parameter list. * @@ -5112,11 +3959,6 @@ extern (C++) final class TypeDelegate : TypeNext return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -5157,20 +3999,6 @@ extern (C++) final class TypeTraits : Type return tt; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Terror) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5210,20 +4038,6 @@ extern (C++) final class TypeMixin : Type return new TypeMixin(loc, Expression.arraySyntaxCopy(exps)); } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t) - s = t.toDsymbol(sc); - else if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5348,28 +4162,6 @@ extern (C++) final class TypeIdentifier : TypeQualified return t; } - /***************************************** - * See if type resolves to a symbol, if so, - * return that symbol. - */ - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); - if (!sc) - return null; - - Type t; - Expression e; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tident) - s = t.toDsymbol(sc); - if (e) - s = getDsymbol(e); - - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5403,18 +4195,6 @@ extern (C++) final class TypeInstance : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Type t; - Expression e; - Dsymbol s; - //printf("TypeInstance::semantic(%s)\n", toChars()); - resolve(this, loc, sc, e, t, s); - if (t && t.ty != Tinstance) - s = t.toDsymbol(sc); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5448,16 +4228,6 @@ extern (C++) final class TypeTypeof : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override uinteger_t size(const ref Loc loc) { if (exp.type) @@ -5494,15 +4264,6 @@ extern (C++) final class TypeReturn : TypeQualified return t; } - override Dsymbol toDsymbol(Scope* sc) - { - Expression e; - Type t; - Dsymbol s; - resolve(this, loc, sc, e, t, s); - return s; - } - override void accept(Visitor v) { v.visit(this); @@ -5549,11 +4310,6 @@ extern (C++) final class TypeStruct : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override structalign_t alignment() { if (sym.alignment.isUnknown()) @@ -5695,15 +4451,6 @@ extern (C++) final class TypeStruct : Type return false; } - override bool hasPointers() - { - if (sym.members && !sym.determineFields() && sym.type != Type.terror) - error(sym.loc, "no size because of forward references"); - - sym.determineTypeProperties(); - return sym.hasPointerField; - } - override bool hasVoidInitPointers() { sym.size(Loc.initial); // give error for forward references @@ -5874,9 +4621,9 @@ extern (C++) final class TypeEnum : Type return sym.getMemtype(loc).size(loc); } - Type memType(const ref Loc loc = Loc.initial) + Type memType() { - return sym.getMemtype(loc); + return sym.getMemtype(Loc.initial); } override uint alignsize() @@ -5887,11 +4634,6 @@ extern (C++) final class TypeEnum : Type return t.alignsize(); } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override bool isintegral() { return memType().isintegral(); @@ -5992,11 +4734,6 @@ extern (C++) final class TypeEnum : Type return sym.getDefaultValue(loc).toBool().hasValue(false); } - override bool hasPointers() - { - return memType().hasPointers(); - } - override bool hasVoidInitPointers() { return memType().hasVoidInitPointers(); @@ -6052,44 +4789,14 @@ extern (C++) final class TypeClass : Type return this; } - override Dsymbol toDsymbol(Scope* sc) - { - return sym; - } - override inout(ClassDeclaration) isClassHandle() inout { return sym; } - override bool isBaseOf(Type t, int* poffset) - { - if (t && t.ty == Tclass) - { - ClassDeclaration cd = (cast(TypeClass)t).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - - if (sym.isBaseOf(cd, poffset)) - return true; - } - return false; - } - extern (D) MATCH implicitConvToWithoutAliasThis(Type to) { - // Run semantic before checking whether class is convertible ClassDeclaration cdto = to.isClassHandle(); - if (cdto) - { - //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete()); - if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete()) - cdto.dsymbolSemantic(null); - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); - } MATCH m = constConv(to); if (m > MATCH.nomatch) return m; @@ -6187,11 +4894,6 @@ extern (C++) final class TypeClass : Type return true; } - override bool hasPointers() - { - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -6433,14 +5135,6 @@ extern (C++) final class TypeNull : Type return MATCH.nomatch; } - override bool hasPointers() - { - /* Although null isn't dereferencable, treat it as a pointer type for - * attribute inference, generic code, etc. - */ - return true; - } - override bool isBoolean() { return true; @@ -6908,34 +5602,28 @@ extern (C++) final class Parameter : ASTNode * Params: * returnByRef = true if the function returns by ref * p = Parameter to compare with - * previewIn = Whether `-preview=in` is being used, and thus if - * `in` means `scope [ref]`. - * * Returns: * true = `this` can be used in place of `p` * false = nope */ - bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn) + bool isCovariant(bool returnByRef, const Parameter p) const pure nothrow @nogc @safe { ulong thisSTC = this.storageClass; ulong otherSTC = p.storageClass; - if (previewIn) - { - if (thisSTC & STC.in_) - thisSTC |= STC.scope_; - if (otherSTC & STC.in_) - otherSTC |= STC.scope_; - } + if (thisSTC & STC.constscoperef) + thisSTC |= STC.scope_; + if (otherSTC & STC.constscoperef) + otherSTC |= STC.scope_; - const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0); + const mask = STC.ref_ | STC.out_ | STC.lazy_ | (((thisSTC | otherSTC) & STC.constscoperef) ? STC.in_ : 0); if ((thisSTC & mask) != (otherSTC & mask)) return false; return isCovariantScope(returnByRef, thisSTC, otherSTC); } - extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe + extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe { // Workaround for failing covariance when finding a common type of delegates, // some of which have parameters with inferred scope @@ -7120,39 +5808,6 @@ bool isIndexableNonAggregate(Type t) t.ty == Ttuple || t.ty == Tvector); } -/*************************************************** - * Determine if type t is copyable. - * Params: - * t = type to check - * Returns: - * true if we can copy it - */ -bool isCopyable(Type t) -{ - //printf("isCopyable() %s\n", t.toChars()); - if (auto ts = t.isTypeStruct()) - { - if (ts.sym.postblit && - ts.sym.postblit.storage_class & STC.disable) - return false; - if (ts.sym.hasCopyCtor) - { - // check if there is a matching overload of the copy constructor and whether it is disabled or not - // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 - Dsymbol ctor = search_function(ts.sym, Id.ctor); - assert(ctor); - scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue - el.type = cast() ts; - Expressions* args = new Expressions(); - args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); - if (!f || f.storage_class & STC.disable) - return false; - } - } - return true; -} - /*************************************** * Computes how a parameter may be returned. * Shrinking the representation is necessary because StorageClass is so wide @@ -7214,7 +5869,7 @@ enum ScopeRef * Returns: * corresponding string */ -const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe +const(char)* ScopeRefToChars(ScopeRef sr) pure nothrow @nogc @safe { with (ScopeRef) { @@ -7235,328 +5890,6 @@ const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe } /** - * Used by `callMatch` to check if the copy constructor may be called to - * copy the argument - * - * This is done by seeing if a call to the copy constructor can be made: - * ``` - * typeof(tprm) __copytmp; - * copytmp.__copyCtor(arg); - * ``` - */ -private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, - Expression arg, Type tprm, Scope* sc, const(char)** pMessage) -{ - auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); - tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; - tmp.dsymbolSemantic(sc); - Expression ve = new VarExp(arg.loc, tmp); - Expression e = new DotIdExp(arg.loc, ve, Id.ctor); - e = new CallExp(arg.loc, e, arg); - //printf("e = %s\n", e.toChars()); - if (.trySemantic(e, sc)) - return true; - - if (pMessage) - { - /* https://issues.dlang.org/show_bug.cgi?id=22202 - * - * If a function was deduced by semantic on the CallExp, - * it means that resolveFuncCall completed succesfully. - * Therefore, there exists a callable copy constructor, - * however, it cannot be called because scope constraints - * such as purity, safety or nogc. - */ - OutBuffer buf; - auto callExp = e.isCallExp(); - if (auto f = callExp.f) - { - char[] s; - if (!f.isPure && sc.func.setImpure()) - s ~= "pure "; - if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) - s ~= "@safe "; - if (!f.isNogc && sc.func.setGC(arg.loc, null)) - s ~= "nogc "; - if (s) - { - s[$-1] = '\0'; - buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); - } - else if (f.isGenerated() && f.isDisabled()) - { - /* https://issues.dlang.org/show_bug.cgi?id=23097 - * Compiler generated copy constructor failed. - */ - buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", - argStruct.toChars()); - } - else - { - /* Although a copy constructor may exist, no suitable match was found. - * i.e: `inout` constructor creates `const` object, not mutable. - * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. - */ - goto Lnocpctor; - } - } - else - { - Lnocpctor: - buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", - argStruct.toChars(), arg.type.toChars(), tprm.toChars()); - } - - *pMessage = buf.extractChars(); - } - return false; -} - -/** - * Match a single parameter to an argument. - * - * This function is called by `TypeFunction.callMatch` while iterating over - * the list of parameter. Here we check if `arg` is a match for `p`, - * which is mostly about checking if `arg.type` converts to `p`'s type - * and some check about value reference. - * - * Params: - * tf = The `TypeFunction`, only used for error reporting - * p = The parameter of `tf` being matched - * arg = Argument being passed (bound) to `p` - * wildmatch = Wild (`inout`) matching level, derived from the full argument list - * flag = A non-zero value means we're doing a partial ordering check - * (no value semantic check) - * sc = Scope we are in - * pMessage = A buffer to write the error in, or `null` - * - * Returns: Whether `trailingArgs` match `p`. - */ -private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, - Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) -{ - //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); - MATCH m; - Type targ = arg.type; - Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; - - if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) - m = MATCH.convert; - else if (flag) - { - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ.implicitConvTo(tprm); - } - else - { - const isRef = p.isReference(); - StructDeclaration argStruct, prmStruct; - - // first look for a copy constructor - if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) - { - // if the argument and the parameter are of the same unqualified struct type - argStruct = (cast(TypeStruct)targ).sym; - prmStruct = (cast(TypeStruct)tprm).sym; - } - - // check if the copy constructor may be called to copy the argument - if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) - { - if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) - return MATCH.nomatch; - m = MATCH.exact; - } - else - { - import dmd.dcast : cimplicitConvTo; - m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); - } - } - - // Non-lvalues do not match ref or out parameters - if (p.isReference()) - { - // https://issues.dlang.org/show_bug.cgi?id=13783 - // Don't use toBasetype() to handle enum types. - Type ta = targ; - Type tp = tprm; - //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); - - if (m && !arg.isLvalue()) - { - if (p.storageClass & STC.out_) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - - if (arg.op == EXP.string_ && tp.ty == Tsarray) - { - if (ta.ty != Tsarray) - { - Type tn = tp.nextOf().castMod(ta.nextOf().mod); - dinteger_t dim = (cast(StringExp)arg).len; - ta = tn.sarrayOf(dim); - } - } - else if (arg.op == EXP.slice && tp.ty == Tsarray) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - if (ta.ty != Tsarray) - { - Type tn = ta.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - } - else if ((p.storageClass & STC.in_) && global.params.previewIn) - { - // Allow converting a literal to an `in` which is `ref` - if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) - { - Type tn = tp.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - - // Need to make this a rvalue through a temporary - m = MATCH.convert; - } - else if (global.params.rvalueRefParam != FeatureState.enabled || - p.storageClass & STC.out_ || - !arg.type.isCopyable()) // can't copy to temp for ref parameter - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - else - { - /* in functionParameters() we'll convert this - * rvalue into a temporary - */ - m = MATCH.convert; - } - } - - /* If the match is not already perfect or if the arg - is not a lvalue then try the `alias this` chain - see https://issues.dlang.org/show_bug.cgi?id=15674 - and https://issues.dlang.org/show_bug.cgi?id=21905 - */ - if (ta != tp || !arg.isLvalue()) - { - Type firsttab = ta.toBasetype(); - while (1) - { - Type tab = ta.toBasetype(); - Type tat = tab.aliasthisOf(); - if (!tat || !tat.implicitConvTo(tprm)) - break; - if (tat == tab || tat == firsttab) - break; - ta = tat; - } - } - - /* A ref variable should work like a head-const reference. - * e.g. disallows: - * ref T <- an lvalue of const(T) argument - * ref T[dim] <- an lvalue of const(T[dim]) argument - */ - if (!ta.constConv(tp)) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - } - return m; -} - -/** - * Match the remaining arguments `trailingArgs` with parameter `p`. - * - * Assume we already checked that `p` is the last parameter of `tf`, - * and we want to know whether the arguments would match `p`. - * - * Params: - * tf = The `TypeFunction`, only used for error reporting - * p = The last parameter of `tf` which is variadic - * trailingArgs = The remaining arguments that should match `p` - * pMessage = A buffer to write the error in, or `null` - * - * Returns: Whether `trailingArgs` match `p`. - */ -private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, - Expression[] trailingArgs, const(char)** pMessage) -{ - Type tb = p.type.toBasetype(); - - switch (tb.ty) - { - case Tsarray: - TypeSArray tsa = cast(TypeSArray)tb; - dinteger_t sz = tsa.dim.toInteger(); - if (sz != trailingArgs.length) - { - if (pMessage) - *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", - sz, trailingArgs.length); - return MATCH.nomatch; - } - goto case Tarray; - case Tarray: - { - MATCH match = MATCH.exact; - TypeArray ta = cast(TypeArray)tb; - foreach (arg; trailingArgs) - { - MATCH m; - assert(arg); - - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type tret = p.isLazyArray(); - if (tret) - { - if (ta.next.equals(arg.type)) - m = MATCH.exact; - else if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - m = arg.implicitConvTo(ta.next); - } - } - else - m = arg.implicitConvTo(ta.next); - - if (m == MATCH.nomatch) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - if (m < match) - match = m; - } - return match; - } - case Tclass: - // We leave it up to the actual constructor call to do the matching. - return MATCH.exact; - - default: - // We can have things as `foo(int[int] wat...)` but they only match - // with an associative array proper. - if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); - return MATCH.nomatch; - } -} - -/** * Creates an appropriate vector type for `tv` that will hold one boolean * result for each element of the vector type. The result of vector comparisons * is a single or doubleword mask of all 1s (comparison true) or all 0s @@ -7738,3 +6071,36 @@ TypeIdentifier getException() tid.addIdent(Id.Exception); return tid; } + +/************************************** + * Check and set 'att' if 't' is a recursive 'alias this' type + * + * The goal is to prevent endless loops when there is a cycle in the alias this chain. + * Since there is no multiple `alias this`, the chain either ends in a leaf, + * or it loops back on itself as some point. + * + * Example: S0 -> (S1 -> S2 -> S3 -> S1) + * + * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. + * `S1` is a recursive alias this type, but since `att` is initialized to `null`, + * this still returns `false`, but `att1` is set to `S1`. + * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, + * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. + * + * Params: + * att = type reference used to detect recursion. Should be initialized to `null`. + * t = type of 'alias this' rewrite to attempt + * + * Returns: + * `false` if the rewrite is safe, `true` if it would loop back around + */ +bool isRecursiveAliasThis(ref Type att, Type t) +{ + //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); + auto tb = t.toBasetype(); + if (att && tb.equivalent(att)) + return true; + else if (!att && tb.checkAliasThisRec()) + att = tb; + return false; +} diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 675e944..a7a41c6 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -39,6 +39,7 @@ typedef union tree_node type; typedef struct TYPE type; #endif +extern const char* toChars(const Type* const t); Type *typeSemantic(Type *t, const Loc &loc, Scope *sc); Type *merge(Type *type); @@ -141,11 +142,7 @@ public: TY ty; MOD mod; // modifiers MODxxxx char *deco; - -private: void* mcache; - -public: Type *pto; // merged pointer to this type Type *rto; // reference to this type Type *arrayof; // array of this type @@ -225,7 +222,6 @@ public: // kludge for template.isType() DYNCAST dyncast() const override final { return DYNCAST_TYPE; } size_t getUniqueID() const; - Covariant covariant(Type *, StorageClass * = NULL, bool = false); const char *toChars() const override; char *toPrettyChars(bool QualifyTypes = false); static void _init(); @@ -233,8 +229,6 @@ public: uinteger_t size(); virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); - Type *trySemantic(const Loc &loc, Scope *sc); - Type *merge2(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -249,7 +243,6 @@ public: virtual bool isString(); virtual bool isAssignable(); virtual bool isBoolean(); - virtual void checkDeprecated(const Loc &loc, Scope *sc); bool isConst() const { return (mod & MODconst) != 0; } bool isImmutable() const { return (mod & MODimmutable) != 0; } bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; } @@ -260,17 +253,6 @@ public: bool isSharedWild() const { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); } bool isNaked() const { return mod == 0; } Type *nullAttributes() const; - Type *constOf(); - Type *immutableOf(); - Type *mutableOf(); - Type *sharedOf(); - Type *sharedConstOf(); - Type *unSharedOf(); - Type *wildOf(); - Type *wildConstOf(); - Type *sharedWildOf(); - Type *sharedWildConstOf(); - Type *castMod(MOD mod); Type *addMod(MOD mod); virtual Type *addStorageClass(StorageClass stc); Type *pointerTo(); @@ -288,9 +270,7 @@ public: virtual Type *makeSharedWild(); virtual Type *makeSharedWildConst(); virtual Type *makeMutable(); - virtual Dsymbol *toDsymbol(Scope *sc); Type *toBasetype(); - virtual bool isBaseOf(Type *t, int *poffset); virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); @@ -303,9 +283,7 @@ public: virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 - Identifier *getTypeInfoIdent(); virtual int hasWild() const; - virtual bool hasPointers(); virtual bool hasVoidInitPointers(); virtual bool hasSystemFields(); virtual bool hasInvariant(); @@ -364,7 +342,6 @@ class TypeNext : public Type public: Type *next; - void checkDeprecated(const Loc &loc, Scope *sc) override final; int hasWild() const override final; Type *nextOf() override final; Type *makeConst() override final; @@ -453,7 +430,6 @@ public: MATCH constConv(Type *to) override; MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; - bool hasPointers() override; bool hasSystemFields() override; bool hasVoidInitPointers() override; bool hasInvariant() override; @@ -476,7 +452,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isBoolean() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -493,7 +468,6 @@ public: uinteger_t size(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; @@ -511,7 +485,6 @@ public: MATCH constConv(Type *to) override; bool isscalar() override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -607,10 +580,8 @@ public: static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0); const char *kind() override; TypeFunction *syntaxCopy() override; - void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; - StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false); Type *addStorageClass(StorageClass stc) override; Type *substWildTo(unsigned mod) override; @@ -661,7 +632,6 @@ public: MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -677,7 +647,6 @@ class TypeTraits final : public Type const char *kind() override; TypeTraits *syntaxCopy() override; uinteger_t size(const Loc &loc) override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -689,7 +658,6 @@ class TypeMixin final : public Type const char *kind() override; TypeMixin *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -715,7 +683,6 @@ public: static TypeIdentifier *create(const Loc &loc, Identifier *ident); const char *kind() override; TypeIdentifier *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -728,7 +695,6 @@ public: const char *kind() override; TypeInstance *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -740,7 +706,6 @@ public: const char *kind() override; TypeTypeof *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -750,7 +715,6 @@ class TypeReturn final : public TypeQualified public: const char *kind() override; TypeReturn *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -778,7 +742,6 @@ public: uinteger_t size(const Loc &loc) override; unsigned alignsize() override; TypeStruct *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; structalign_t alignment() override; Expression *defaultInitLiteral(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; @@ -787,7 +750,6 @@ public: bool needsDestruction() override; bool needsCopyOrPostblit() override; bool needsNested() override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -808,8 +770,7 @@ public: TypeEnum *syntaxCopy() override; uinteger_t size(const Loc &loc) override; unsigned alignsize() override; - Type *memType(const Loc &loc = Loc()); - Dsymbol *toDsymbol(Scope *sc) override; + Type *memType(const Loc &loc); bool isintegral() override; bool isfloating() override; bool isreal() override; @@ -826,7 +787,6 @@ public: MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; bool isZeroInit(const Loc &loc) override; - bool hasPointers() override; bool hasVoidInitPointers() override; bool hasSystemFields() override; bool hasInvariant() override; @@ -845,9 +805,7 @@ public: const char *kind() override; uinteger_t size(const Loc &loc) override; TypeClass *syntaxCopy() override; - Dsymbol *toDsymbol(Scope *sc) override; ClassDeclaration *isClassHandle() override; - bool isBaseOf(Type *t, int *poffset) override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; @@ -855,7 +813,6 @@ public: bool isZeroInit(const Loc &loc) override; bool isscope() override; bool isBoolean() override; - bool hasPointers() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -896,7 +853,6 @@ public: TypeNull *syntaxCopy() override; MATCH implicitConvTo(Type *to) override; - bool hasPointers() override; bool isBoolean() override; uinteger_t size(const Loc &loc) override; @@ -927,5 +883,25 @@ public: /**************************************************************/ + // If the type is a class or struct, returns the symbol for it, else null. AggregateDeclaration *isAggregate(Type *t); +bool hasPointers(Type *t); +// return the symbol to which type t resolves +Dsymbol *toDsymbol(Type *t, Scope *sc); +Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); +bool isBaseOf(Type *tthis, Type *t, int *poffset); +Type *trySemantic(Type *type, const Loc &loc, Scope *sc); +void purityLevel(TypeFunction *type); +Type *merge2(Type *type); +Type *constOf(Type *type); +Type *immutableOf(Type *type); +Type *mutableOf(Type *type); +Type *sharedOf(Type *type); +Type *sharedConstOf(Type *type); +Type *unSharedOf(Type *type); +Type *wildOf(Type *type); +Type *wildConstOf(Type *type); +Type *sharedWildOf(Type *type); +Type *sharedWildConstOf(Type *type); +Type *castMod(Type *type, MOD mod); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index 6934649..c2fa5fb 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -1,7 +1,7 @@ /** * Compile-time checks associated with the @mustuse attribute. * - * Copyright: Copyright (C) 2022-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2022-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d) * Documentation: https://dlang.org/phobos/dmd_mustuse.html @@ -31,6 +31,7 @@ import dmd.location; bool checkMustUse(Expression e, Scope* sc) { import dmd.id : Id; + import dmd.typesem : toDsymbol; assert(e.type); if (auto sym = e.type.toDsymbol(sc)) @@ -222,20 +223,7 @@ private bool hasMustUseAttribute(Dsymbol sym, Scope* sc) */ private bool isMustUseAttribute(Expression e) { - import dmd.attrib : isCoreUda; + import dmd.attrib : isEnumAttribute; import dmd.id : Id; - - // Logic based on dmd.objc.Supported.declaredAsOptionalCount - auto typeExp = e.isTypeExp; - if (!typeExp) - return false; - - auto typeEnum = typeExp.type.isTypeEnum(); - if (!typeEnum) - return false; - - if (isCoreUda(typeEnum.sym, Id.udaMustUse)) - return true; - - return false; + return isEnumAttribute(e, Id.udaMustUse); } diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index e59b010..9e45e45 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#nogc-functions, No-GC Functions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d, _nogc.d) diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d index 22c6e63..52c2b79 100644 --- a/gcc/d/dmd/nspace.d +++ b/gcc/d/dmd/nspace.d @@ -36,7 +36,7 @@ * are valid D identifier. * * See_Also: https://github.com/dlang/dmd/pull/10031 - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d) @@ -46,22 +46,14 @@ module dmd.nspace; -import dmd.aggregate; import dmd.arraytypes; -import dmd.astenums; -import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem; -import dmd.errors; import dmd.expression; -import dmd.globals; import dmd.identifier; import dmd.location; import dmd.visitor; import core.stdc.stdio; -private enum LOG = false; - /// Ditto extern (C++) final class Nspace : ScopeDsymbol { @@ -91,14 +83,6 @@ extern (C++) final class Nspace : ScopeDsymbol return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("Nspace::setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, null); // try to resolve it - members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); - } - override const(char)* kind() const { return "namespace"; diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index 701cc93..cbee2fb 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -22,7 +22,6 @@ class Nspace final : public ScopeDsymbol Expression *identExp; Nspace *syntaxCopy(Dsymbol *s) override; bool hasPointers() override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; Nspace *isNspace() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index dc94aec..0a59815 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -1,7 +1,7 @@ /** * Flow analysis for Ownership/Borrowing * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d) @@ -197,7 +197,7 @@ enum PtrState : ubyte /************ */ -const(char)* toChars(PtrState state) +const(char)* PtrStateToChars(PtrState state) { return toString(state).ptr; } @@ -2490,7 +2490,7 @@ void checkObErrors(ref ObState obstate) if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner)) { auto v = obstate.vars[i]; - .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, s1.toChars(), s2.toChars()); + .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2)); } pvs1.combine(*pvs2, i, ob.gen); } @@ -2566,6 +2566,7 @@ void checkObErrors(ref ObState obstate) //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); if (pvs.state == PtrState.Owner) { + import dmd.typesem : hasPointers; auto v = obstate.vars[i]; if (v.type.hasPointers()) .error(v.loc, "%s `%s` is not disposed of before return", v.kind, v.toPrettyChars); diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index 359474c..2f36d5d 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/objc_interface.html, Interfacing to Objective-C) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d) diff --git a/gcc/d/dmd/objc.h b/gcc/d/dmd/objc.h index 40f634e..0390115 100644 --- a/gcc/d/dmd/objc.h +++ b/gcc/d/dmd/objc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2015-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2015-2024 by The D Language Foundation, All Rights Reserved * written by Michel Fortin * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index b7bc925..70eeaff 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/operatoroverloading.html, Operator Overloading) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/opover.d, _opover.d) @@ -37,6 +37,7 @@ import dmd.location; import dmd.mtype; import dmd.optimize; import dmd.statement; +import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index a979168..5c0ef67 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -1,7 +1,7 @@ /** * Perform constant folding. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d) @@ -33,6 +33,7 @@ import dmd.printast; import dmd.root.ctfloat; import dmd.sideeffect; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /************************************* @@ -272,7 +273,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) * Returns: * Constant folded version of `e` */ -Expression optimize(Expression e, int result, bool keepLvalue = false) +extern (C++) Expression optimize(Expression e, int result, bool keepLvalue = false) { //printf("optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue); Expression ret = e; diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index b6f30b9..0dc54ff 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d) @@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = CondExpression { nextToken(); - tp_defaultvalue = parseDefaultInitExp(); + tp_defaultvalue = parseAssignExp(); } tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); } @@ -2015,6 +2015,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: @@ -2899,6 +2900,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (transitionIn) eSink.message(scanloc, "Usage of 'in' on parameter"); stc = STC.in_; + if (compileEnv.previewIn) + stc |= STC.constscoperef; goto L2; case TOK.out_: @@ -2936,9 +2939,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: { - stc = storageClass & (STC.IOR | STC.lazy_); - // if stc is not a power of 2 - if (stc & (stc - 1) && !(stc == (STC.in_ | STC.ref_))) + const stcx = storageClass & (STC.in_ | STC.ref_ | STC.out_ | STC.lazy_); + // if stcx is not a power of 2 + if (stcx & (stcx - 1) && !(stcx == (STC.in_ | STC.ref_))) error("incompatible parameter storage classes"); //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_))) //error("scope cannot be ref or out"); @@ -2967,7 +2970,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) // = defaultArg { nextToken(); - ae = parseDefaultInitExp(); + ae = parseAssignExp(); } auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null); if (udas) @@ -5818,6 +5821,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.true_: case TOK.false_: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.leftParenthesis: case TOK.cast_: @@ -6947,33 +6951,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } - /***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__. - */ - private AST.Expression parseDefaultInitExp() - { - AST.Expression e = null; - const tv = peekNext(); - if (tv == TOK.comma || tv == TOK.rightParenthesis) - { - switch (token.value) - { - case TOK.file: e = new AST.FileInitExp(token.loc, 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; - case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break; - default: goto LExp; - } - nextToken(); - return e; - } - LExp: - return parseAssignExp(); - } - /******************** * Parse inline assembler block. * Enters with token on the `asm`. @@ -7338,6 +7315,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: @@ -8150,33 +8128,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; case TOK.file: - { - const(char)* s = loc.filename ? loc.filename : mod.ident.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.file); + nextToken(); + break; case TOK.fileFullPath: - { - assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location"); - const s = FileName.toAbsolute(loc.filename); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.FileInitExp(loc, EXP.fileFullPath); + nextToken(); + break; case TOK.line: - e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32); + e = new AST.LineInitExp(loc); nextToken(); break; case TOK.moduleString: - { - const(char)* s = md ? md.toChars() : mod.toChars(); - e = new AST.StringExp(loc, s.toDString()); - nextToken(); - break; - } + e = new AST.ModuleInitExp(loc); + nextToken(); + break; case TOK.functionString: e = new AST.FuncInitExp(loc); nextToken(); @@ -8212,6 +8180,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); break; + case TOK.interpolated: + e = new AST.InterpExp(loc, token.interpolatedSet, token.postfix); + nextToken(); + break; + case TOK.string_: case TOK.hexadecimalString: const bool hexString = token.value == TOK.hexadecimalString; @@ -8845,6 +8818,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.function_: case TOK.delegate_: case TOK.typeof_: diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index 3d0a585..422c1c8 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -183,6 +183,7 @@ public: void visit(AST.TypeidExp e) { visit(cast(AST.Expression)e); } void visit(AST.TraitsExp e) { visit(cast(AST.Expression)e); } void visit(AST.StringExp e) { visit(cast(AST.Expression)e); } + void visit(AST.InterpExp e) { visit(cast(AST.Expression)e); } void visit(AST.NewExp e) { visit(cast(AST.Expression)e); } void visit(AST.AssocArrayLiteralExp e) { visit(cast(AST.Expression)e); } void visit(AST.ArrayLiteralExp e) { visit(cast(AST.Expression)e); } diff --git a/gcc/d/dmd/postordervisitor.d b/gcc/d/dmd/postordervisitor.d index 70bd130..fe189d4 100644 --- a/gcc/d/dmd/postordervisitor.d +++ b/gcc/d/dmd/postordervisitor.d @@ -1,7 +1,7 @@ /** * A depth-first visitor for expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d) diff --git a/gcc/d/dmd/pragmasem.d b/gcc/d/dmd/pragmasem.d new file mode 100644 index 0000000..b52b551 --- /dev/null +++ b/gcc/d/dmd/pragmasem.d @@ -0,0 +1,650 @@ +/** + * Does semantic analysis for pragmas. + * + * Specification: $(LINK2 https://dlang.org/spec/pragma.html, Pragmas) + * + * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/pragmasem.d, _pragmasem.d) + * Documentation: https://dlang.org/phobos/dmd_pragmasem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/pragmasem.d + */ + +module dmd.pragmasem; + +import core.stdc.stdio; + +import dmd.astenums; +import dmd.arraytypes; +import dmd.attrib; +import dmd.dinterpret; +import dmd.dscope; +import dmd.dsymbol; +import dmd.errors; +import dmd.expression; +import dmd.expressionsem; +import dmd.globals; +import dmd.location; +import dmd.id; +import dmd.statement; + +/** + * Run semantic on `pragma` declaration. + * + * Params: + * pd = pragma declaration or statement to evaluate + * sc = enclosing scope + */ +void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc) +{ + import dmd.aggregate; + import dmd.common.outbuffer; + import dmd.dmangle; + import dmd.dmodule; + import dmd.dsymbolsem; + import dmd.identifier; + import dmd.root.rmem; + import dmd.root.utf; + import dmd.target; + import dmd.utils; + + StringExp verifyMangleString(ref Expression e) + { + auto se = semanticString(sc, e, "mangled name"); + if (!se) + return null; + e = se; + if (!se.len) + { + .error(pd.loc, "%s `%s` - zero-length string not allowed for mangled name", pd.kind, pd.toPrettyChars); + return null; + } + if (se.sz != 1) + { + .error(pd.loc, "%s `%s` - mangled name characters can only be of type `char`", pd.kind, pd.toPrettyChars); + return null; + } + version (all) + { + /* Note: D language specification should not have any assumption about backend + * implementation. Ideally pragma(mangle) can accept a string of any content. + * + * Therefore, this validation is compiler implementation specific. + */ + auto slice = se.peekString(); + for (size_t i = 0; i < se.len;) + { + dchar c = slice[i]; + if (c < 0x80) + { + if (c.isValidMangling) + { + ++i; + continue; + } + else + { + .error(pd.loc, "%s `%s` char 0x%02x not allowed in mangled name", pd.kind, pd.toPrettyChars, c); + break; + } + } + if (const msg = utf_decodeChar(slice, i, c)) + { + .error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr); + break; + } + if (!isUniAlpha(c)) + { + .error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c); + break; + } + } + } + return se; + } + void declarations() + { + if (!pd.decl) + return; + + Scope* sc2 = pd.newScope(sc); + scope(exit) + if (sc2 != sc) + sc2.pop(); + + foreach (s; (*pd.decl)[]) + { + if (pd.ident == Id.printf || pd.ident == Id.scanf) + { + s.setPragmaPrintf(pd.ident == Id.printf); + s.dsymbolSemantic(sc2); + continue; + } + + s.dsymbolSemantic(sc2); + if (pd.ident != Id.mangle) + continue; + assert(pd.args); + if (auto ad = s.isAggregateDeclaration()) + { + Expression e = (*pd.args)[0]; + sc2 = sc2.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc2, e); + sc2 = sc2.endCTFE(); + AggregateDeclaration agg; + if (auto tc = e.type.isTypeClass()) + agg = tc.sym; + else if (auto ts = e.type.isTypeStruct()) + agg = ts.sym; + ad.pMangleOverride = new MangleOverride; + void setString(ref Expression e) + { + if (auto se = verifyMangleString(e)) + { + const name = (cast(const(char)[])se.peekData()).xarraydup; + ad.pMangleOverride.id = Identifier.idPool(name); + e = se; + } + else + error(e.loc, "must be a string"); + } + if (agg) + { + ad.pMangleOverride.agg = agg; + if (pd.args.length == 2) + { + setString((*pd.args)[1]); + } + else + ad.pMangleOverride.id = agg.ident; + } + else + setString((*pd.args)[0]); + } + else if (auto td = s.isTemplateDeclaration()) + { + .error(pd.loc, "%s `%s` cannot apply to a template declaration", pd.kind, pd.toPrettyChars); + errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`"); + } + else if (auto se = verifyMangleString((*pd.args)[0])) + { + const name = (cast(const(char)[])se.peekData()).xarraydup; + uint cnt = setMangleOverride(s, name); + if (cnt > 1) + .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); + } + } + } + + void noDeclarations() + { + if (pd.decl) + { + .error(pd.loc, "%s `%s` is missing a terminating `;`", pd.kind, pd.toPrettyChars); + declarations(); + // do them anyway, to avoid segfaults. + } + } + + // Should be merged with PragmaStatement + //printf("\tpragmaDeclSemantic '%s'\n", pd.toChars()); + if (target.supportsLinkerDirective()) + { + if (pd.ident == Id.linkerDirective) + { + if (!pd.args || pd.args.length != 1) + .error(pd.loc, "%s `%s` one string argument expected for pragma(linkerDirective)", pd.kind, pd.toPrettyChars); + else + { + auto se = semanticString(sc, (*pd.args)[0], "linker directive"); + if (!se) + return noDeclarations(); + (*pd.args)[0] = se; + if (global.params.v.verbose) + message("linkopt %.*s", cast(int)se.len, se.peekString().ptr); + } + return noDeclarations(); + } + } + if (pd.ident == Id.msg) + { + if (!pd.args) + return noDeclarations(); + + if (!pragmaMsgSemantic(pd.loc, sc, pd.args)) + return; + + return noDeclarations(); + } + else if (pd.ident == Id.lib) + { + if (!pd.args || pd.args.length != 1) + .error(pd.loc, "%s `%s` string expected for library name", pd.kind, pd.toPrettyChars); + else + { + auto se = semanticString(sc, (*pd.args)[0], "library name"); + if (!se) + return noDeclarations(); + (*pd.args)[0] = se; + + auto name = se.peekString().xarraydup; + if (global.params.v.verbose) + message("library %s", name.ptr); + if (global.params.moduleDeps.buffer && !global.params.moduleDeps.name) + { + OutBuffer* ob = global.params.moduleDeps.buffer; + Module imod = sc._module; + ob.writestring("depsLib "); + ob.writestring(imod.toPrettyChars()); + ob.writestring(" ("); + escapePath(ob, imod.srcfile.toChars()); + ob.writestring(") : "); + ob.writestring(name); + ob.writenl(); + } + mem.xfree(name.ptr); + } + return noDeclarations(); + } + else if (pd.ident == Id.startaddress) + { + pragmaStartAddressSemantic(pd.loc, sc, pd.args); + return noDeclarations(); + } + else if (pd.ident == Id.Pinline) + { + // this pragma now gets evaluated on demand in function semantic + + return declarations(); + } + else if (pd.ident == Id.mangle) + { + if (!pd.args) + pd.args = new Expressions(); + if (pd.args.length == 0 || pd.args.length > 2) + { + .error(pd.loc, pd.args.length == 0 ? "%s `%s` - string expected for mangled name" + : "%s `%s` expected 1 or 2 arguments", pd.kind, pd.toPrettyChars); + pd.args.setDim(1); + (*pd.args)[0] = ErrorExp.get(); // error recovery + } + return declarations(); + } + else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor) + { + if (pd.args && pd.args.length != 0) + .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); + else + { + immutable isCtor = pd.ident == Id.crt_constructor; + + static uint recurse(Dsymbol s, bool isCtor) + { + if (auto ad = s.isAttribDeclaration()) + { + uint nestedCount; + auto decls = ad.include(null); + if (decls) + { + for (size_t i = 0; i < decls.length; ++i) + nestedCount += recurse((*decls)[i], isCtor); + } + return nestedCount; + } + else if (auto f = s.isFuncDeclaration()) + { + if (isCtor) + f.isCrtCtor = true; + else + f.isCrtDtor = true; + + return 1; + } + else + return 0; + assert(0); + } + + if (recurse(pd, isCtor) > 1) + .error(pd.loc, "%s `%s` can only apply to a single declaration", pd.kind, pd.toPrettyChars); + } + return declarations(); + } + else if (pd.ident == Id.printf || pd.ident == Id.scanf) + { + if (pd.args && pd.args.length != 0) + .error(pd.loc, "%s `%s` takes no argument", pd.kind, pd.toPrettyChars); + return declarations(); + } + else if (!global.params.ignoreUnsupportedPragmas) + { + error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars()); + return declarations(); + } + + if (!global.params.v.verbose) + return declarations(); + + /* Print unrecognized pragmas + */ + OutBuffer buf; + buf.writestring(pd.ident.toString()); + if (pd.args) + { + const errors_save = global.startGagging(); + for (size_t i = 0; i < pd.args.length; i++) + { + Expression e = (*pd.args)[i]; + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + e = e.ctfeInterpret(); + if (i == 0) + buf.writestring(" ("); + else + buf.writeByte(','); + buf.writestring(e.toChars()); + } + if (pd.args.length) + buf.writeByte(')'); + global.endGagging(errors_save); + } + message("pragma %s", buf.peekChars()); + return declarations(); +} + +/** + * Run semantic on `pragma` statement. + * + * Params: + * ps = pragma statement to evaluate + * sc = enclosing scope + * + * Returns : true if `pragma` is valid, or false if an error was found + */ +bool pragmaStmtSemantic(PragmaStatement ps, Scope* sc) +{ + import dmd.statementsem; + + /* https://dlang.org/spec/statement.html#pragma-statement + */ + // Should be merged with PragmaDeclaration + + //printf("pragmaStmtSemantic() %s\n", ps.toChars()); + //printf("body = %p\n", ps._body); + if (ps.ident == Id.msg) + { + if (!pragmaMsgSemantic(ps.loc, sc, ps.args)) + return false; + } + else if (ps.ident == Id.lib) + { + version (all) + { + /* Should this be allowed? + */ + error(ps.loc, "`pragma(lib)` not allowed as statement"); + return false; + } + else + { + if (!ps.args || ps.args.length != 1) + { + error(ps.loc, "`string` expected for library name"); + return false; + } + else + { + auto se = semanticString(sc, (*ps.args)[0], "library name"); + if (!se) + return false; + + if (global.params.v.verbose) + { + message("library %.*s", cast(int)se.len, se.string); + } + } + } + } + else if (ps.ident == Id.linkerDirective) + { + /* Should this be allowed? + */ + error(ps.loc, "`pragma(linkerDirective)` not allowed as statement"); + return false; + } + else if (ps.ident == Id.startaddress) + { + if (!pragmaStartAddressSemantic(ps.loc, sc, ps.args)) + return false; + } + else if (ps.ident == Id.Pinline) + { + if (auto fd = sc.func) + { + fd.inlining = evalPragmaInline(ps.loc, sc, ps.args); + } + else + { + error(ps.loc, "`pragma(inline)` is not inside a function"); + return false; + } + } + else if (ps.ident == Id.mangle) + { + auto es = ps._body ? ps._body.isExpStatement() : null; + auto de = es ? es.exp.isDeclarationExp() : null; + if (!de) + { + error(ps.loc, "`pragma(mangle)` must be attached to a declaration"); + return false; + } + const se = ps.args && (*ps.args).length == 1 ? semanticString(sc, (*ps.args)[0], "pragma mangle argument") : null; + if (!se) + { + error(ps.loc, "`pragma(mangle)` takes a single argument that must be a string literal"); + return false; + } + const cnt = setMangleOverride(de.declaration, cast(const(char)[])se.peekData()); + if (cnt != 1) + assert(0); + } + else if (!global.params.ignoreUnsupportedPragmas) + { + error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars()); + return false; + } + + if (ps._body) + { + if (ps.ident == Id.msg || ps.ident == Id.startaddress) + { + error(ps.loc, "`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); + return false; + } + ps._body = ps._body.statementSemantic(sc); + } + return true; +} + +/*************************************** + * Interpret a `pragma(inline, x)` + * + * Params: + * loc = location for error messages + * sc = scope for evaluation of argument + * args = pragma arguments + * Returns: corresponding `PINLINE` state + */ +package PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) +{ + if (!args || args.length == 0) + return PINLINE.default_; + + if (args && args.length > 1) + { + .error(loc, "one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.length); + args.setDim(1); + (*args)[0] = ErrorExp.get(); + } + + Expression e = (*args)[0]; + if (!e.type) + { + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + e = e.ctfeInterpret(); + e = e.toBoolean(sc); + if (e.isErrorExp()) + .error(loc, "pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars()); + (*args)[0] = e; + } + + const opt = e.toBool(); + if (opt.isEmpty()) + return PINLINE.default_; + else if (opt.get()) + return PINLINE.always; + else + return PINLINE.never; +} + +/** + * Apply pragma mangle to FuncDeclarations and VarDeclarations + * under `s`, poking through attribute declarations such as + * `extern(C)` but not through aggregates or function bodies. + * + * Params: + * s = symbol to apply + * sym = overriding symbol name + */ +private uint setMangleOverride(Dsymbol s, const(char)[] sym) +{ + if (s.isFuncDeclaration() || s.isVarDeclaration()) + { + s.isDeclaration().mangleOverride = sym; + return 1; + } + + if (auto ad = s.isAttribDeclaration()) + { + uint nestedCount = 0; + + ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } ); + + return nestedCount; + } + return 0; +} + +/*********************************************************** + * Evaluate and print a `pragma(msg, args)` + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = expressions to print + * Returns: + * `true` on success + */ +private bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args) +{ + import dmd.tokens; + + if (!args) + return true; + foreach (arg; *args) + { + sc = sc.startCTFE(); + auto e = arg.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + // pragma(msg) is allowed to contain types as well as expressions + e = ctfeInterpretForPragmaMsg(e); + if (e.op == EXP.error) + { + errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); + return false; + } + if (auto se = e.toStringExp()) + { + const slice = se.toUTF8(sc).peekString(); + fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); + } + else + fprintf(stderr, "%s", e.toChars()); + } + fprintf(stderr, "\n"); + return true; +} + +/** + * Apply pragma printf/scanf to FuncDeclarations under `s`, + * poking through attribute declarations such as `extern(C)` + * but not through aggregates or function bodies. + * + * Params: + * s = symbol to apply + * printf = `true` for printf, `false` for scanf + */ +private void setPragmaPrintf(Dsymbol s, bool printf) +{ + if (auto fd = s.isFuncDeclaration()) + { + fd.printf = printf; + fd.scanf = !printf; + } + + if (auto ad = s.isAttribDeclaration()) + { + ad.include(null).foreachDsymbol( (s) { setPragmaPrintf(s, printf); } ); + } +} + +/*********************************************************** + * Evaluate `pragma(startAddress, func)` and store the resolved symbol in `args` + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = pragma arguments + * Returns: + * `true` on success + */ +private bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args) +{ + import dmd.dtemplate; + + if (!args || args.length != 1) + { + .error(loc, "function name expected for start address"); + return false; + } + else + { + /* https://issues.dlang.org/show_bug.cgi?id=11980 + * resolveProperties and ctfeInterpret call are not necessary. + */ + Expression e = (*args)[0]; + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + // e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + // e = e.ctfeInterpret(); + (*args)[0] = e; + Dsymbol sa = getDsymbol(e); + if (!sa || !sa.isFuncDeclaration()) + { + .error(loc, "function name expected for start address, not `%s`", e.toChars()); + return false; + } + } + return true; +} diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index e1deb2c..02dc653 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -1,7 +1,7 @@ /** * Provides an AST printer for debugging. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/printast.d, _printast.d) diff --git a/gcc/d/dmd/res/default_ddoc_theme.ddoc b/gcc/d/dmd/res/default_ddoc_theme.ddoc index 7ae0db8..20269e1 100644 --- a/gcc/d/dmd/res/default_ddoc_theme.ddoc +++ b/gcc/d/dmd/res/default_ddoc_theme.ddoc @@ -70,7 +70,7 @@ D_CODE = <div class="code_sample"> <div class="dlang"> <ol class="code_lines"> - <li><code class="code">$0</code></li> + <li><pre><code class="code">$0</code></pre></li> </ol> </div> </div> @@ -81,7 +81,7 @@ OTHER_CODE = <div class="code_sample"> <div class="dlang"> <ol class="code_lines"> - <li><code class="code language-$1">$+</code></li> + <li><pre><code class="code language-$1">$+</code></pre></li> </ol> </div> </div> @@ -517,6 +517,10 @@ DDOC = white-space: pre-wrap; } + .ddoc .code_lines pre { + display: contents; + } + .ddoc .code_lines li:only-of-type::before { color: rgba(255, 255, 255, 1); content: " "; diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d index 1d45050..8929679 100644 --- a/gcc/d/dmd/root/aav.d +++ b/gcc/d/dmd/root/aav.d @@ -1,7 +1,7 @@ /** * Associative array implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d) diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d index f36ddb4..8135577 100644 --- a/gcc/d/dmd/root/array.d +++ b/gcc/d/dmd/root/array.d @@ -2,7 +2,7 @@ /** * Dynamic array implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d, root/_array.d) diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h index ebe2c47..1033b22 100644 --- a/gcc/d/dmd/root/array.h +++ b/gcc/d/dmd/root/array.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/bitarray.d b/gcc/d/dmd/root/bitarray.d index 66adab6..c32d59e 100644 --- a/gcc/d/dmd/root/bitarray.d +++ b/gcc/d/dmd/root/bitarray.d @@ -1,7 +1,7 @@ /** * Implementation of a bit array. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d) diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h index 617cc9e..2cd7152 100644 --- a/gcc/d/dmd/root/bitarray.h +++ b/gcc/d/dmd/root/bitarray.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/complex.d b/gcc/d/dmd/root/complex.d index 57d1e34..de4c8d34 100644 --- a/gcc/d/dmd/root/complex.d +++ b/gcc/d/dmd/root/complex.d @@ -1,7 +1,7 @@ /** * Implements a complex number type. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/complex.d, _complex.d) diff --git a/gcc/d/dmd/root/complex_t.h b/gcc/d/dmd/root/complex_t.h index de2040b..8134f9e 100644 --- a/gcc/d/dmd/root/complex_t.h +++ b/gcc/d/dmd/root/complex_t.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/ctfloat.d b/gcc/d/dmd/root/ctfloat.d index aae56fa..70446066 100644 --- a/gcc/d/dmd/root/ctfloat.d +++ b/gcc/d/dmd/root/ctfloat.d @@ -1,7 +1,7 @@ /** * Collects functions for compile-time floating-point calculations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d) diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h index d2f795b..ba8b447 100644 --- a/gcc/d/dmd/root/ctfloat.h +++ b/gcc/d/dmd/root/ctfloat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h index 1a49688..db2b2c6 100644 --- a/gcc/d/dmd/root/dcompat.h +++ b/gcc/d/dmd/root/dcompat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index fdf13d4..a4362e1 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -1,7 +1,7 @@ /** * Read a file from disk and store it in memory. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d, root/_file.d) diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 8f31f21..41c2050 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -1,7 +1,7 @@ /** * Encapsulate path and file names. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d, root/_filename.d) @@ -78,7 +78,7 @@ nothrow: private const(char)[] str; /// - extern (D) this(const(char)[] str) pure + extern (D) this(const char[] str) pure { this.str = str.xarraydup; } @@ -96,7 +96,7 @@ nothrow: } /// Ditto - extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure @nogc + extern (D) static bool equals(const char[] name1, const char[] name2) pure @nogc { if (name1.length != name2.length) return false; @@ -125,7 +125,7 @@ nothrow: } /// Ditto - extern (D) static bool absolute(const(char)[] name) pure @nogc @safe + extern (D) static bool absolute(const char[] name) pure @nogc @safe { if (!name.length) return false; @@ -189,7 +189,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] ext(const(char)[] str) nothrow pure @safe @nogc + extern (D) static const(char)[] ext(const char[] str) nothrow pure @safe @nogc { foreach_reverse (idx, char e; str) { @@ -249,7 +249,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] removeExt(const(char)[] str) + extern (D) static const(char)[] removeExt(const char[] str) { auto e = ext(str); if (e.length) @@ -278,7 +278,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] name(const(char)[] str) pure @nogc @safe + extern (D) static const(char)[] name(const char[] str) pure @nogc @safe { foreach_reverse (idx, char e; str) { @@ -333,7 +333,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] path(const(char)[] str) + extern (D) static const(char)[] path(const char[] str) { const n = name(str); bool hasTrailingSlash; @@ -358,7 +358,7 @@ nothrow: /************************************** * Replace filename portion of path. */ - extern (D) static const(char)[] replaceName(const(char)[] path, const(char)[] name) + extern (D) static const(char)[] replaceName(const char[] path, const char[] name) { if (absolute(name)) return name; @@ -387,7 +387,7 @@ nothrow: } /// Ditto - extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name) + extern(D) static const(char)[] combine(const char[] path, const char[] name) { return !path.length ? name : buildPath(path, name); } @@ -401,7 +401,7 @@ nothrow: assert(combine("foo/"[], "bar"[]) == "foo/bar"); } - static const(char)[] buildPath(const(char)[][] fragments...) + static const(char)[] buildPath(const char[][] fragments...) { size_t size; foreach (f; fragments) @@ -563,7 +563,7 @@ nothrow: * Returns: * A newly allocated string (free with `FileName.free`) */ - extern(D) static char[] addExt(const(char)[] name, const(char)[] ext) pure + extern(D) static char[] addExt(const char[] name, const char[] ext) pure { const len = name.length + ext.length + 2; auto s = cast(char*)mem.xmalloc(len); @@ -584,7 +584,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] defaultExt(const(char)[] name, const(char)[] ext) + extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext) { auto e = FileName.ext(name); if (e.length) // it already has an extension @@ -608,7 +608,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] forceExt(const(char)[] name, const(char)[] ext) + extern (D) static const(char)[] forceExt(const char[] name, const char[] ext) { if (auto e = FileName.ext(name)) return addExt(name[0 .. $ - e.length - 1], ext); @@ -630,7 +630,7 @@ nothrow: } /// Ditto - extern (D) static bool equalsExt(const(char)[] name, const(char)[] ext) pure @nogc + extern (D) static bool equalsExt(const char[] name, const char[] ext) pure @nogc { auto e = FileName.ext(name); if (!e.length && !ext.length) @@ -665,12 +665,12 @@ nothrow: * Returns: * if found, filename combined with path, otherwise null */ - extern (C++) static const(char)* searchPath(Strings* path, const(char)* name, bool cwd) + extern (C++) static const(char)* searchPath(const ref Strings path, const char* name, bool cwd) { - return searchPath(path, name.toDString, cwd).ptr; + return searchPath(path[], name.toDString, cwd).ptr; } - extern (D) static const(char)[] searchPath(Strings* path, const(char)[] name, bool cwd) + extern (D) static const(char)[] searchPath(const char*[] path, const char[] name, bool cwd) { if (absolute(name)) { @@ -681,24 +681,21 @@ nothrow: if (exists(name)) return name; } - if (path) + foreach (p; path) { - foreach (p; *path) + auto n = combine(p.toDString, name); + if (exists(n)) + return n; + //combine might return name + if (n.ptr != name.ptr) { - auto n = combine(p.toDString, name); - if (exists(n)) - return n; - //combine might return name - if (n.ptr != name.ptr) - { - mem.xfree(cast(void*)n.ptr); - } + mem.xfree(cast(void*)n.ptr); } } return null; } - extern (D) static const(char)[] searchPath(const(char)* path, const(char)[] name, bool cwd) + extern (D) static const(char)[] searchPath(const char* path, const char[] name, bool cwd) { if (absolute(name)) { @@ -738,7 +735,7 @@ nothrow: * Returns: * index of the first reserved character in path if found, size_t.max otherwise */ - extern (D) static size_t findReservedChar(const(char)[] name) pure @nogc @safe + extern (D) static size_t findReservedChar(const char[] name) pure @nogc @safe { version (Windows) { @@ -787,7 +784,7 @@ nothrow: * Returns: * true if path contains '..' reference to parent directory */ - extern (D) static bool refersToParentDir(const(char)[] name) pure @nogc @safe + extern (D) static bool refersToParentDir(const char[] name) pure @nogc @safe { size_t s = 0; foreach (i; 0 .. name.length) @@ -845,7 +842,7 @@ nothrow: } /// Ditto - extern (D) static int exists(const(char)[] name) + extern (D) static int exists(const char[] name) { if (!name.length) return 0; @@ -892,7 +889,7 @@ nothrow: Returns: `true` if the directory exists or was successfully created */ - extern (D) static bool ensurePathExists(const(char)[] path) + extern (D) static bool ensurePathExists(const char[] path) { //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); if (!path.length) @@ -967,7 +964,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] canonicalName(const(char)[] name) + extern (D) static const(char)[] canonicalName(const char[] name) { version (Posix) { @@ -1127,7 +1124,7 @@ version(Windows) * References: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx */ - private int _mkdir(const(char)[] path) nothrow + private int _mkdir(const char[] path) nothrow { const createRet = path.extendedPathThen!( p => CreateDirectoryW(&p[0], null /*securityAttributes*/)); @@ -1175,7 +1172,7 @@ version(Windows) * Returns: * The result of calling F on the UTF16 version of str. */ - private auto toWStringzThen(alias F)(const(char)[] str) nothrow + private auto toWStringzThen(alias F)(const char[] str) nothrow { import dmd.common.smallbuffer : SmallBuffer, toWStringz; diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index 6214233..0e52b98 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -38,7 +38,7 @@ public: bool equalsExt(const char *ext); - static const char *searchPath(Strings *path, const char *name, bool cwd); + static const char *searchPath(Strings& path, const char *name, bool cwd); static int exists(const char *name); static bool ensurePathExists(const char *path); static const char *canonicalName(const char *name); diff --git a/gcc/d/dmd/root/hash.d b/gcc/d/dmd/root/hash.d index 2acee35..441620e 100644 --- a/gcc/d/dmd/root/hash.d +++ b/gcc/d/dmd/root/hash.d @@ -1,7 +1,7 @@ /** * Hash functions for arbitrary binary data. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Martin Nowak, Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d) diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h index 8e505f0..f56cb17 100644 --- a/gcc/d/dmd/root/object.h +++ b/gcc/d/dmd/root/object.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/optional.d b/gcc/d/dmd/root/optional.d index bc1016b..e7d0e1e 100644 --- a/gcc/d/dmd/root/optional.d +++ b/gcc/d/dmd/root/optional.d @@ -1,7 +1,7 @@ /** * Implementation of an 'Optional' type * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://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) diff --git a/gcc/d/dmd/root/optional.h b/gcc/d/dmd/root/optional.h index 353332c..a92dedd 100644 --- a/gcc/d/dmd/root/optional.h +++ b/gcc/d/dmd/root/optional.h @@ -3,7 +3,7 @@ /** * Optional implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://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) diff --git a/gcc/d/dmd/root/port.d b/gcc/d/dmd/root/port.d index 290280f..ee846bd 100644 --- a/gcc/d/dmd/root/port.d +++ b/gcc/d/dmd/root/port.d @@ -1,7 +1,7 @@ /** * Portable routines for functions that have different implementations on different platforms. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d) diff --git a/gcc/d/dmd/root/port.h b/gcc/d/dmd/root/port.h index 6fa3c00..6c7dddd 100644 --- a/gcc/d/dmd/root/port.h +++ b/gcc/d/dmd/root/port.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/region.d b/gcc/d/dmd/root/region.d index 9fc57f1..a9fab16 100644 --- a/gcc/d/dmd/root/region.d +++ b/gcc/d/dmd/root/region.d @@ -1,7 +1,7 @@ /** * Region storage allocator implementation. * - * Copyright: Copyright (C) 2019-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2019-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d, root/_region.d) diff --git a/gcc/d/dmd/root/rmem.d b/gcc/d/dmd/root/rmem.d index cff5c4c..1965207 100644 --- a/gcc/d/dmd/root/rmem.d +++ b/gcc/d/dmd/root/rmem.d @@ -1,7 +1,7 @@ /** * Allocate memory using `malloc` or the GC depending on the configuration. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d) diff --git a/gcc/d/dmd/root/rmem.h b/gcc/d/dmd/root/rmem.h index 36aa264..09c0fc0 100644 --- a/gcc/d/dmd/root/rmem.h +++ b/gcc/d/dmd/root/rmem.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/root/speller.d b/gcc/d/dmd/root/speller.d index 7ad08b7..ae09cba 100644 --- a/gcc/d/dmd/root/speller.d +++ b/gcc/d/dmd/root/speller.d @@ -3,7 +3,7 @@ * * Does not have any dependencies on the rest of DMD. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d, root/_speller.d) diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d index 5ee81a9..e82b0d2 100644 --- a/gcc/d/dmd/root/string.d +++ b/gcc/d/dmd/root/string.d @@ -1,7 +1,7 @@ /** * Contains various string related functions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d, root/_string.d) diff --git a/gcc/d/dmd/root/stringtable.d b/gcc/d/dmd/root/stringtable.d index de293eb..1fba919 100644 --- a/gcc/d/dmd/root/stringtable.d +++ b/gcc/d/dmd/root/stringtable.d @@ -1,7 +1,7 @@ /** * A specialized associative array with string keys stored in a variable length structure. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d) diff --git a/gcc/d/dmd/root/utf.d b/gcc/d/dmd/root/utf.d index d7ba17f..7d732f2 100644 --- a/gcc/d/dmd/root/utf.d +++ b/gcc/d/dmd/root/utf.d @@ -1,7 +1,7 @@ /** * Functions related to UTF encoding. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/utf.d, _utf.d) diff --git a/gcc/d/dmd/rootobject.d b/gcc/d/dmd/rootobject.d index 7867ad5..7c926fe 100644 --- a/gcc/d/dmd/rootobject.d +++ b/gcc/d/dmd/rootobject.d @@ -1,7 +1,7 @@ /** * Provide the root object that AST classes in dmd inherit from. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.d, _rootobject.d) diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index bd531c0..8b57f7f 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#function-safety, Function Safety) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/safe.d, _safe.d) @@ -26,6 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; +import dmd.typesem : hasPointers; import dmd.func : setUnsafe, setUnsafePreview; /************************************************************* diff --git a/gcc/d/dmd/sapply.d b/gcc/d/dmd/sapply.d index 13fe691..340fbad 100644 --- a/gcc/d/dmd/sapply.d +++ b/gcc/d/dmd/sapply.d @@ -1,7 +1,7 @@ /** * Provides a depth-first statement visitor. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sparse.d, _sparse.d) diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 2cac5f2..f36a14b 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -87,6 +87,7 @@ struct Scope Dsymbol *inunion; // !=null if processing members of a union d_bool nofree; // true if shouldn't free it d_bool inLoop; // true if inside a loop (where constructor calls aren't allowed) + d_bool inDefaultArg; // true if inside a default argument (where __FILE__, etc are evaluated at the call site) int intypeof; // in typeof(exp) VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init ErrorSink *eSink; // sink for error messages @@ -130,5 +131,5 @@ struct Scope AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it - Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone); + Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); }; diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 036560b..b4f91ac 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -1,7 +1,7 @@ /** * Performs the semantic2 stage, which deals with initializer expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d) @@ -93,6 +93,13 @@ private extern(C++) final class Semantic2Visitor : Visitor override void visit(StaticAssert sa) { //printf("StaticAssert::semantic2() %s\n", sa.toChars()); + if (const e = sa.exp.isStringExp()) + { + // deprecated in 2.107 + deprecation(e.loc, "static assert condition cannot be a string literal"); + deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour", + e.toChars()); + } auto sds = new ScopeDsymbol(); sc = sc.push(sds); sc.tinst = null; @@ -822,7 +829,8 @@ private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) } /** - * Try lower a variable's static Associative Array to a newaa struct. + * Try lower a variable's Associative Array initializer to a newaa struct + * so it can be put in static data. * Params: * vd = Variable to lower * sc = Scope @@ -832,11 +840,20 @@ void lowerStaticAAs(VarDeclaration vd, Scope* sc) if (vd.storage_class & STC.manifest) return; if (auto ei = vd._init.isExpInitializer()) - { - scope v = new StaticAAVisitor(sc); - v.vd = vd; - ei.exp.accept(v); - } + lowerStaticAAs(ei.exp, sc); +} + +/** + * Try lower all Associative Array literals in an expression to a newaa struct + * so it can be put in static data. + * Params: + * e = Expression to traverse + * sc = Scope + */ +void lowerStaticAAs(Expression e, Scope* sc) +{ + scope v = new StaticAAVisitor(sc); + e.accept(v); } /// Visit Associative Array literals and lower them to structs for static initialization @@ -844,7 +861,6 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor { alias visit = SemanticTimeTransitiveVisitor.visit; Scope* sc; - VarDeclaration vd; this(Scope* sc) scope @safe { diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index c255701..125a39d 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -1,7 +1,7 @@ /** * Performs the semantic3 stage, which deals with function bodies. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d) @@ -41,6 +41,7 @@ import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -231,8 +232,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32) return true; - return f.next.ty == Tvoid && - (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain()); + return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain()); } VarDeclaration _arguments = null; @@ -346,6 +346,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.tf = null; sc2.os = null; sc2.inLoop = false; + sc2.inDefaultArg = false; sc2.userAttribDecl = null; if (sc2.intypeof == 1) sc2.intypeof = 2; @@ -384,7 +385,7 @@ private extern(C++) final class Semantic3Visitor : Visitor } } - funcdecl.declareThis(sc2); + declareThis(funcdecl, sc2); // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710 // No compiler supports this, and there was never any spec for it. @@ -520,7 +521,8 @@ private extern(C++) final class Semantic3Visitor : Visitor { Parameter narg = Parameter.getNth(t.arguments, j); assert(narg.ident); - VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration(); + Dsymbol pscopesym; + VarDeclaration v = sc2.search(Loc.initial, narg.ident, pscopesym).isVarDeclaration(); assert(v); (*exps)[j] = new VarExp(v.loc, v); } @@ -569,7 +571,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv) { - funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel); + funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel, Loc.initial); } // scope of out contract (need for vresult.semantic) diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 80c9a46..1d4745a 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -1,7 +1,7 @@ /** * Find side-effects of expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d, _sideeffect.d) @@ -19,11 +19,13 @@ import dmd.expression; import dmd.expressionsem; import dmd.func; import dmd.globals; +import dmd.id; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.postordervisitor; import dmd.tokens; +import dmd.typesem; import dmd.visitor; /************************************************** @@ -269,6 +271,15 @@ bool discardValue(Expression e) break; } case EXP.call: + // https://issues.dlang.org/show_bug.cgi?id=24359 + auto ce = e.isCallExp(); + if (const f = ce.f) + { + if (f.ident == Id.__equals && ce.arguments && ce.arguments.length == 2) + { + return discardValue(new EqualExp(EXP.equal, e.loc, (*ce.arguments)[0], (*ce.arguments)[1])); + } + } return false; case EXP.andAnd: case EXP.orOr: diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index b5906c8..a79b78a 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d) @@ -20,19 +20,15 @@ import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; import dmd.errors; -import dmd.gluelayer; import dmd.cond; import dmd.declaration; import dmd.dsymbol; import dmd.expression; import dmd.func; -import dmd.globals; -import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.location; import dmd.mtype; -import dmd.common.outbuffer; import dmd.rootobject; import dmd.sapply; import dmd.staticassert; @@ -333,6 +329,8 @@ extern (C++) final class ErrorStatement : Statement extern (D) this() { super(Loc.initial, STMT.Error); + + import dmd.globals; assert(global.gaggedErrors || global.errors); } @@ -1773,7 +1771,7 @@ extern (C++) class AsmStatement : Statement */ extern (C++) final class InlineAsmStatement : AsmStatement { - code* asmcode; + void* asmcode; uint asmalign; // alignment of this statement uint regs; // mask of registers modified (must match regm_t in back end) bool refparam; // true if function parameter is referenced diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index ef8423f..ee03d49 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -716,7 +716,7 @@ public: class InlineAsmStatement final : public AsmStatement { public: - code *asmcode; + void *asmcode; unsigned asmalign; // alignment of this statement unsigned regs; // mask of registers modified (must match regm_t in back end) d_bool refparam; // true if function parameter is referenced diff --git a/gcc/d/dmd/statement_rewrite_walker.d b/gcc/d/dmd/statement_rewrite_walker.d index dcdd963..221c502 100644 --- a/gcc/d/dmd/statement_rewrite_walker.d +++ b/gcc/d/dmd/statement_rewrite_walker.d @@ -1,7 +1,7 @@ /** * Provides a visitor for statements that allows rewriting the currently visited node. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d, _statement_rewrite_walker.d) diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 3873adc..a431d5c 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d, _statementsem.d) @@ -16,12 +16,10 @@ module dmd.statementsem; import core.stdc.stdio; import dmd.aggregate; -import dmd.aliasthis; import dmd.arrayop; import dmd.arraytypes; import dmd.astcodegen; import dmd.astenums; -import dmd.attrib; import dmd.blockexit; import dmd.clone; import dmd.cond; @@ -36,13 +34,12 @@ import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; -import dmd.dtemplate; import dmd.errors; -import dmd.errorsink; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.gluelayer; import dmd.hdrgen; @@ -63,7 +60,6 @@ import dmd.root.string; import dmd.semantic2; import dmd.sideeffect; import dmd.statement; -import dmd.staticassert; import dmd.target; import dmd.tokens; import dmd.typesem; @@ -568,8 +564,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) ds._body = ds._body.semanticScope(sc, ds, ds, null); sc.inLoop = inLoopSave; - if (ds.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)ds.condition).noderef = true; + if (auto dotid = ds.condition.isDotIdExp()) + dotid.noderef = true; // check in syntax level ds.condition = checkAssignmentAsCondition(ds.condition, sc); @@ -641,8 +637,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fs.condition) { - if (fs.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)fs.condition).noderef = true; + if (auto dotid = fs.condition.isDotIdExp()) + dotid.noderef = true; // check in syntax level fs.condition = checkAssignmentAsCondition(fs.condition, sc); @@ -729,8 +725,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) 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 && + if (fs.aggr.type && fs.aggr.type.toBasetype().isTypeStruct() && + fs.aggr.type.toBasetype().isTypeStruct().sym.dtor && !fs.aggr.isTypeExp() && !fs.aggr.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=14653 @@ -804,9 +800,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Parameter fparam = fparameters[0]; if ((fparam.type.ty == Tpointer || fparam.type.ty == Tdelegate) && - fparam.type.nextOf().ty == Tfunction) + fparam.type.nextOf().isTypeFunction()) { - TypeFunction tf = cast(TypeFunction)fparam.type.nextOf(); + auto tf = fparam.type.nextOf().isTypeFunction(); foreachParamCount = tf.parameterList.length; foundMismatch = true; } @@ -1284,7 +1280,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Type tfront; if (auto fd = sfront.isFuncDeclaration()) { - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return rangeError(); tfront = fd.type; } @@ -1644,8 +1640,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else { - if (ifs.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)ifs.condition).noderef = true; + if (auto dotid = ifs.condition.isDotIdExp()) + dotid.noderef = true; ifs.condition = ifs.condition.expressionSemantic(scd); ifs.condition = resolveProperties(scd, ifs.condition); @@ -1750,102 +1746,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { /* https://dlang.org/spec/statement.html#pragma-statement */ - // Should be merged with PragmaDeclaration - - //printf("PragmaStatement::semantic() %s\n", ps.toChars()); - //printf("body = %p\n", ps._body); - if (ps.ident == Id.msg) - { - if (!pragmaMsgSemantic(ps.loc, sc, ps.args)) - return setError(); - } - else if (ps.ident == Id.lib) - { - version (all) - { - /* Should this be allowed? - */ - error(ps.loc, "`pragma(lib)` not allowed as statement"); - return setError(); - } - else - { - if (!ps.args || ps.args.length != 1) - { - error(ps.loc, "`string` expected for library name"); - return setError(); - } - else - { - auto se = semanticString(sc, (*ps.args)[0], "library name"); - if (!se) - return setError(); - - if (global.params.v.verbose) - { - message("library %.*s", cast(int)se.len, se.string); - } - } - } - } - else if (ps.ident == Id.linkerDirective) - { - /* Should this be allowed? - */ - error(ps.loc, "`pragma(linkerDirective)` not allowed as statement"); - return setError(); - } - else if (ps.ident == Id.startaddress) - { - if (!pragmaStartAddressSemantic(ps.loc, sc, ps.args)) - return setError(); - } - else if (ps.ident == Id.Pinline) - { - if (auto fd = sc.func) - { - fd.inlining = evalPragmaInline(ps.loc, sc, ps.args); - } - else - { - error(ps.loc, "`pragma(inline)` is not inside a function"); - return setError(); - } - } - else if (ps.ident == Id.mangle) - { - auto es = ps._body ? ps._body.isExpStatement() : null; - auto de = es ? es.exp.isDeclarationExp() : null; - if (!de) - { - error(ps.loc, "`pragma(mangle)` must be attached to a declaration"); - return setError(); - } - const se = ps.args && (*ps.args).length == 1 ? semanticString(sc, (*ps.args)[0], "pragma mangle argument") : null; - if (!se) - { - error(ps.loc, "`pragma(mangle)` takes a single argument that must be a string literal"); - return setError(); - } - const cnt = setMangleOverride(de.declaration, cast(const(char)[])se.peekData()); - if (cnt != 1) - assert(0); - } - else if (!global.params.ignoreUnsupportedPragmas) - { - error(ps.loc, "unrecognized `pragma(%s)`", ps.ident.toChars()); + import dmd.pragmasem : pragmaStmtSemantic; + if (!pragmaStmtSemantic(ps, sc)) return setError(); - } - if (ps._body) - { - if (ps.ident == Id.msg || ps.ident == Id.startaddress) - { - error(ps.loc, "`pragma(%s)` is missing a terminating `;`", ps.ident.toChars()); - return setError(); - } - ps._body = ps._body.statementSemantic(sc); - } result = ps._body; } @@ -1910,8 +1814,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) while (!ss.condition.isErrorExp()) { // preserve enum type for final switches - if (ss.condition.type.ty == Tenum) - te = cast(TypeEnum)ss.condition.type; + if (auto tenum = ss.condition.type.isTypeEnum()) + te = tenum; if (ss.condition.type.isString()) { // If it's not an array, cast it to one @@ -2222,14 +2126,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc) 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 == EXP.cast_) - e = (cast(CastExp)e).e1; + while (e.isCastExp()) + e = e.isCastExp().e1; /* This is where variables are allowed as case expressions. */ - if (e.op == EXP.variable) + if (auto ve = e.isVarExp()) { - VarExp ve = cast(VarExp)e; VarDeclaration v = ve.var.isVarDeclaration(); Type t = cs.exp.type.toBasetype(); if (v && (t.isintegral() || t.ty == Tclass)) @@ -2261,7 +2164,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) continue; assert(scx.sw == sw); - if (!scx.search(cs.exp.loc, v.ident, null)) + Dsymbol pscopesym; + if (!scx.search(cs.exp.loc, v.ident, pscopesym)) { error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body", v.toChars(), v.loc.toChars()); @@ -2525,10 +2429,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fd.fes) fd = fd.fes.func; // fd is now function enclosing foreach - TypeFunction tf = cast(TypeFunction)fd.type; - assert(tf.ty == Tfunction); + auto tf = fd.type.isTypeFunction(); - if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult) + if (rs.exp && rs.exp.isVarExp() && rs.exp.isVarExp().var == fd.vresult) { // return vresult; if (sc.fes) @@ -2616,7 +2519,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) rs.exp.checkSharedAccess(sc, returnSharedRef); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (rs.exp.op == EXP.type) + if (rs.exp.isTypeExp()) rs.exp = resolveAliasThis(sc, rs.exp); rs.exp = resolveProperties(sc, rs.exp); @@ -2632,14 +2535,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // Extract side-effect part rs.exp = Expression.extractLast(rs.exp, e0); - if (rs.exp.op == EXP.call) + if (rs.exp.isCallExp()) rs.exp = valueNoDtor(rs.exp); /* Void-return function can have void / noreturn typed expression * on return statement. */ auto texp = rs.exp.type; - const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn; + const convToVoid = texp.ty == Tvoid || texp.isTypeNoreturn(); if (tbret && tbret.ty == Tvoid || convToVoid) { @@ -2688,7 +2591,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { tf.next = rs.exp.type; } - else if (tret.ty != Terror && !rs.exp.type.equals(tret)) + else if (!tret.isTypeError() && !rs.exp.type.equals(tret)) { int m1 = rs.exp.type.implicitConvTo(tret); int m2 = tret.implicitConvTo(rs.exp.type); @@ -2789,7 +2692,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // Found an actual return value before else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn()) { - if (tf.next.ty != Terror) + if (!tf.next.isTypeError()) { error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars()); } @@ -2807,7 +2710,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return { - if (tbret.ty != Terror) + if (!tbret.isTypeError()) { if (e0) error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars()); @@ -2901,7 +2804,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } if (e0) { - if (e0.op == EXP.declaration || e0.op == EXP.comma) + if (e0.isDeclarationExp() || e0.isCommaExp()) { rs.exp = Expression.combine(e0, rs.exp); } @@ -3227,9 +3130,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } - else if (ws.exp.op == EXP.type) + else if (auto et = ws.exp.isTypeExp()) { - Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc); + Dsymbol s = et.type.toDsymbol(sc); if (!s || !s.isScopeDsymbol()) { error(ws.loc, "`with` type `%s` has no members", ws.exp.toChars()); @@ -3754,7 +3657,10 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) { if (!global.params.useExceptions) { - loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); + version (IN_GCC) + loc.error("cannot use `throw` statements with `-fno-exceptions`"); + else + loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr); return false; } @@ -3767,16 +3673,15 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) if (FuncDeclaration fd = sc.parent.isFuncDeclaration()) fd.hasReturnExp |= 2; - if (exp.op == EXP.new_) + if (auto ne = exp.isNewExp()) { - NewExp ne = cast(NewExp) exp; ne.thrownew = true; } exp = exp.expressionSemantic(sc); exp = resolveProperties(sc, exp); exp = checkGC(sc, exp); - if (exp.op == EXP.error) + if (exp.isErrorExp()) return false; if (!exp.type.isNaked()) { @@ -3805,12 +3710,12 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, { message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); } - (cast(FuncExp)flde).fd.tookAddressOf = 1; + flde.isFuncExp().fd.tookAddressOf = 1; } else { if (sc2.useDIP1000 == FeatureState.enabled) - ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' + ++flde.isFuncExp().fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' } assert(tab.ty == Tstruct || tab.ty == Tclass); assert(sapply); @@ -3821,7 +3726,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident); ec = new CallExp(fs.loc, ec, flde); ec = ec.expressionSemantic(sc2); - if (ec.op == EXP.error) + if (ec.isErrorExp()) return null; if (ec.type != Type.tint32) { @@ -3838,11 +3743,12 @@ private extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde, /* Call: * aggr(flde) */ - if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && - !(cast(DelegateExp)fs.aggr).func.needThis()) + if (auto de = fs.aggr.isDelegateExp()) + if (de.func.isNested() && + !de.func.needThis()) { // https://issues.dlang.org/show_bug.cgi?id=3560 - fs.aggr = (cast(DelegateExp)fs.aggr).e1; + fs.aggr = de.e1; } ec = new CallExp(fs.loc, fs.aggr, flde); ec = ec.expressionSemantic(sc2); @@ -4099,7 +4005,7 @@ private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFuncti fld.tookAddressOf = 0; if (flde.op == EXP.error) return null; - return cast(FuncExp)flde; + return flde.isFuncExp(); } @@ -4273,9 +4179,9 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St { if (auto es = statement.isExpStatement()) { - if (es.exp && es.exp.op == EXP.declaration) + if (es.exp && es.exp.isDeclarationExp()) { - auto de = cast(DeclarationExp)es.exp; + auto de = es.exp.isDeclarationExp(); auto v = de.declaration.isVarDeclaration(); if (v && !v.isDataseg()) { @@ -4401,7 +4307,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState } Type tab = fs.aggr.type.toBasetype(); - TypeTuple tuple = cast(TypeTuple)tab; + TypeTuple tuple = tab.isTypeTuple(); Statements* statements; Dsymbols* declarations; @@ -4413,12 +4319,12 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState //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 + if (auto ate = fs.aggr.isTupleExp()) // expression tuple { - te = cast(TupleExp)fs.aggr; + te = ate; n = te.exps.length; } - else if (fs.aggr.op == EXP.type) // type tuple + else if (fs.aggr.isTypeExp()) // type tuple { n = Parameter.dim(tuple.arguments); } @@ -5007,86 +4913,6 @@ private void debugThrowWalker(Statement s) s.accept(walker); } -/*********************************************************** - * Evaluate and print a `pragma(msg, args)` - * - * Params: - * loc = location for error messages - * sc = scope for argument interpretation - * args = expressions to print - * Returns: - * `true` on success - */ -bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args) -{ - if (!args) - return true; - foreach (arg; *args) - { - sc = sc.startCTFE(); - auto e = arg.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - - // pragma(msg) is allowed to contain types as well as expressions - e = ctfeInterpretForPragmaMsg(e); - if (e.op == EXP.error) - { - errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); - return false; - } - if (auto se = e.toStringExp()) - { - const slice = se.toUTF8(sc).peekString(); - fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); - } - else - fprintf(stderr, "%s", e.toChars()); - } - fprintf(stderr, "\n"); - return true; -} - -/*********************************************************** - * Evaluate `pragma(startAddress, func)` and store the resolved symbol in `args` - * - * Params: - * loc = location for error messages - * sc = scope for argument interpretation - * args = pragma arguments - * Returns: - * `true` on success - */ -bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args) -{ - if (!args || args.length != 1) - { - .error(loc, "function name expected for start address"); - return false; - } - else - { - /* https://issues.dlang.org/show_bug.cgi?id=11980 - * resolveProperties and ctfeInterpret call are not necessary. - */ - Expression e = (*args)[0]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - // e = resolveProperties(sc, e); - sc = sc.endCTFE(); - - // e = e.ctfeInterpret(); - (*args)[0] = e; - Dsymbol sa = getDsymbol(e); - if (!sa || !sa.isFuncDeclaration()) - { - .error(loc, "function name expected for start address, not `%s`", e.toChars()); - return false; - } - } - return true; -} - /************************************ * Check for skipped variable declarations. * Params: diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d index 7f22c4c..08780ca 100644 --- a/gcc/d/dmd/staticassert.d +++ b/gcc/d/dmd/staticassert.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/version.html#static-assert, Static Assert) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d, _staticassert.d) @@ -14,14 +14,11 @@ module dmd.staticassert; import dmd.arraytypes; -import dmd.dscope; import dmd.dsymbol; import dmd.expression; -import dmd.globals; import dmd.location; import dmd.id; import dmd.identifier; -import dmd.mtype; import dmd.visitor; /*********************************************************** @@ -52,10 +49,10 @@ extern (C++) final class StaticAssert : Dsymbol return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null); } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { //printf("StaticAssert::oneMember())\n"); - *ps = null; + ps = null; return true; } diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h index c0d5363..ed76de0 100644 --- a/gcc/d/dmd/staticassert.h +++ b/gcc/d/dmd/staticassert.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -21,7 +21,7 @@ public: Expressions *msg; StaticAssert *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; const char *kind() const override; StaticAssert *isStaticAssert() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d index 1d18de3..72afe02 100644 --- a/gcc/d/dmd/staticcond.d +++ b/gcc/d/dmd/staticcond.d @@ -1,7 +1,7 @@ /** * Lazily evaluate static conditions for `static if`, `static assert` and template constraints. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d, _staticcond.d) diff --git a/gcc/d/dmd/stmtstate.d b/gcc/d/dmd/stmtstate.d index 7b2ea97..e1ed165 100644 --- a/gcc/d/dmd/stmtstate.d +++ b/gcc/d/dmd/stmtstate.d @@ -1,7 +1,7 @@ /** * Used to help transform statement AST into flow graph. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d) diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index aba3319..e63bf17 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -15,7 +15,7 @@ * - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository) * - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d) diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index ca0e09c..1209505 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved * written by Iain Buclaw * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 44f95ec..153eb4e 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -290,7 +290,7 @@ public: TemplateInstance *syntaxCopy(Dsymbol *) override; Dsymbol *toAlias() override final; // resolve real symbol const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; const char *toChars() const override; const char* toPrettyCharsHelper() override final; Identifier *getIdent() override final; @@ -309,9 +309,8 @@ public: TemplateMixin *syntaxCopy(Dsymbol *s) override; const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *toChars() const override; TemplateMixin *isTemplateMixin() override { return this; } @@ -325,4 +324,4 @@ Tuple *isTuple(RootObject *o); Parameter *isParameter(RootObject *o); TemplateParameter *isTemplateParameter(RootObject *o); bool isError(const RootObject *const o); -void printTemplateStats(); +void printTemplateStats(bool listInstances, ErrorSink* eSink); diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index 7762363..89749d6 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -1,7 +1,7 @@ /** * Semantic analysis of template parameters. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d) diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d new file mode 100644 index 0000000..0a36838 --- /dev/null +++ b/gcc/d/dmd/templatesem.d @@ -0,0 +1,2404 @@ +/** + * Template semantics. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templatesem.d, _templatesem.d) + * Documentation: https://dlang.org/phobos/dmd_templatesem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templatesem.d + */ + +module dmd.templatesem; + +import core.stdc.stdio; +import core.stdc.string; +import dmd.aggregate; +import dmd.aliasthis; +import dmd.arraytypes; +import dmd.astenums; +import dmd.ast_node; +import dmd.attrib; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.dinterpret; +import dmd.dmangle; +import dmd.dmodule; +import dmd.dscope; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.errorsink; +import dmd.expression; +import dmd.expressionsem; +import dmd.func; +import dmd.funcsem; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.impcnvtab; +import dmd.init; +import dmd.initsem; +import dmd.location; +import dmd.mtype; +import dmd.opover; +import dmd.optimize; +import dmd.root.array; +import dmd.common.outbuffer; +import dmd.rootobject; +import dmd.semantic2; +import dmd.semantic3; +import dmd.templateparamsem; +import dmd.tokens; +import dmd.typesem; +import dmd.visitor; + +/************************************ + * Perform semantic analysis on template. + * Params: + * sc = context + * tempdecl = template declaration + */ +void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl) +{ + enum log = false; + static if (log) + { + printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars()); + printf("sc.stc = %llx\n", sc.stc); + printf("sc.module = %s\n", sc._module.toChars()); + } + if (tempdecl.semanticRun != PASS.initial) + return; // semantic() already run + + if (tempdecl._scope) + { + sc = tempdecl._scope; + tempdecl._scope = null; + } + if (!sc) + return; + + // Remember templates defined in module object that we need to know about + if (sc._module && sc._module.ident == Id.object) + { + if (tempdecl.ident == Id.RTInfo) + Type.rtinfo = tempdecl; + } + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + if (!tempdecl._scope) + { + tempdecl._scope = sc.copy(); + tempdecl._scope.setNoFree(); + } + + tempdecl.semanticRun = PASS.semantic; + + tempdecl.parent = sc.parent; + tempdecl.visibility = sc.visibility; + tempdecl.userAttribDecl = sc.userAttribDecl; + tempdecl.cppnamespace = sc.namespace; + tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_); + tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_); + + UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage); + + if (!tempdecl.isstatic) + { + if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration()) + ad.makeNested(); + } + + // Set up scope for parameters + auto paramsym = new ScopeDsymbol(); + paramsym.parent = tempdecl.parent; + Scope* paramscope = sc.push(paramsym); + paramscope.stc = 0; + + if (global.params.ddoc.doOutput) + { + tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.length); + for (size_t i = 0; i < tempdecl.parameters.length; i++) + { + TemplateParameter tp = (*tempdecl.parameters)[i]; + (*tempdecl.origParameters)[i] = tp.syntaxCopy(); + } + } + + for (size_t i = 0; i < tempdecl.parameters.length; i++) + { + TemplateParameter tp = (*tempdecl.parameters)[i]; + if (!tp.declareParameter(paramscope)) + { + error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars()); + tempdecl.errors = true; + } + if (!tp.tpsemantic(paramscope, tempdecl.parameters)) + { + tempdecl.errors = true; + } + if (i + 1 != tempdecl.parameters.length && tp.isTemplateTupleParameter()) + { + .error(tempdecl.loc, "%s `%s` template sequence parameter must be the last one", tempdecl.kind, tempdecl.toPrettyChars); + tempdecl.errors = true; + } + } + + /* Calculate TemplateParameter.dependent + */ + TemplateParameters tparams = TemplateParameters(1); + for (size_t i = 0; i < tempdecl.parameters.length; i++) + { + TemplateParameter tp = (*tempdecl.parameters)[i]; + tparams[0] = tp; + + for (size_t j = 0; j < tempdecl.parameters.length; j++) + { + // Skip cases like: X(T : T) + if (i == j) + continue; + + if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter()) + { + if (reliesOnTident(ttp.specType, &tparams)) + tp.dependent = true; + } + else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter()) + { + if (reliesOnTident(tap.specType, &tparams) || + reliesOnTident(isType(tap.specAlias), &tparams)) + { + tp.dependent = true; + } + } + } + } + + paramscope.pop(); + + // Compute again + tempdecl.onemember = null; + if (tempdecl.members) + { + Dsymbol s; + if (Dsymbol.oneMembers(tempdecl.members, s, tempdecl.ident) && s) + { + tempdecl.onemember = s; + s.parent = tempdecl; + } + } + + /* BUG: should check: + * 1. template functions must not introduce virtual functions, as they + * cannot be accomodated in the vtbl[] + * 2. templates cannot introduce non-static data members (i.e. fields) + * as they would change the instance size of the aggregate. + */ + + tempdecl.semanticRun = PASS.semanticdone; +} + + +/*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Params: + * sc = context + * td = template + * ti = instance of td + * dedtypes = fill in with deduced types + * argumentList = arguments to template instance + * flag = 1 - don't do semantic() because of dummy types + * 2 - don't change types in matchArg() + * Returns: match level. + */ +public +MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) +{ + enum LOGM = 0; + static if (LOGM) + { + printf("\n+TemplateDeclaration.matchWithInstance(td = %s, ti = %s, flag = %d)\n", td.toChars(), ti.toChars(), flag); + } + version (none) + { + printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length); + if (ti.tiargs.length) + printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]); + } + MATCH nomatch() + { + static if (LOGM) + { + printf(" no match\n"); + } + return MATCH.nomatch; + } + MATCH m; + size_t dedtypes_dim = dedtypes.length; + + dedtypes.zero(); + + if (td.errors) + return MATCH.nomatch; + + size_t parameters_dim = td.parameters.length; + int variadic = td.isVariadic() !is null; + + // If more arguments than parameters, no match + if (ti.tiargs.length > parameters_dim && !variadic) + { + static if (LOGM) + { + printf(" no match: more arguments than parameters\n"); + } + return MATCH.nomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti.tiargs.length || variadic); + + assert(td._scope); + + // Set up scope for template parameters + Scope* paramscope = createScopeForTemplateParameters(td, ti, sc); + + // Attempt type deduction + m = MATCH.exact; + for (size_t i = 0; i < dedtypes_dim; i++) + { + MATCH m2; + TemplateParameter tp = (*td.parameters)[i]; + Declaration sparam; + + //printf("\targument [%d]\n", i); + static if (LOGM) + { + //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); + TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + + m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, td.parameters, dedtypes, &sparam); + //printf("\tm2 = %d\n", m2); + if (m2 == MATCH.nomatch) + { + version (none) + { + printf("\tmatchArg() for parameter %i failed\n", i); + } + return nomatch(); + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam.dsymbolSemantic(paramscope); + if (!paramscope.insert(sparam)) // TODO: This check can make more early + { + // in TemplateDeclaration.semantic, and + // then we don't need to make sparam if flags == 0 + return nomatch(); + } + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + foreach (i, ref dedtype; dedtypes) + { + if (!dedtype) + { + assert(i < ti.tiargs.length); + dedtype = cast(Type)(*ti.tiargs)[i]; + } + } + } + + if (m > MATCH.nomatch && td.constraint && !flag) + { + if (ti.hasNestedArgs(ti.tiargs, td.isstatic)) // TODO: should gag error + ti.parent = ti.enclosing; + else + ti.parent = td.parent; + + // Similar to doHeaderInstantiation + FuncDeclaration fd = td.onemember ? td.onemember.isFuncDeclaration() : null; + if (fd) + { + TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); + if (argumentList.hasNames) + return nomatch(); + Expressions* fargs = argumentList.arguments; + // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); + // if (!fargs) + // return nomatch(); + + fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); + fd.parent = ti; + fd.inferRetType = true; + + // Shouldn't run semantic on default arguments and return type. + foreach (ref param; *tf.parameterList.parameters) + param.defaultArg = null; + + tf.next = null; + tf.incomplete = true; + + // Resolve parameter types and 'auto ref's. + tf.fargs = fargs; + uint olderrors = global.startGagging(); + fd.type = tf.typeSemantic(td.loc, paramscope); + global.endGagging(olderrors); + if (fd.type.ty != Tfunction) + return nomatch(); + fd.originalType = fd.type; // for mangling + } + + // TODO: dedtypes => ti.tiargs ? + if (!evaluateConstraint(td, ti, sc, paramscope, &dedtypes, fd)) + return nomatch(); + } + + static if (LOGM) + { + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti.toChars()); + if (m > MATCH.nomatch) + { + for (size_t i = 0; i < dedtypes_dim; i++) + { + TemplateParameter tp = (*parameters)[i]; + RootObject oarg; + printf(" [%d]", i); + if (i < ti.tiargs.length) + oarg = (*ti.tiargs)[i]; + else + oarg = null; + tp.print(oarg, (*dedtypes)[i]); + } + } + else + return nomatch(); + } + static if (LOGM) + { + printf(" match = %d\n", m); + } + + paramscope.pop(); + static if (LOGM) + { + printf("-TemplateDeclaration.matchWithInstance(td = %s, ti = %s) = %d\n", td.toChars(), ti.toChars(), m); + } + return m; +} + +/**************************** + * Check to see if constraint is satisfied. + */ +bool evaluateConstraint(TemplateDeclaration td, TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) +{ + /* Detect recursive attempts to instantiate this template declaration, + * https://issues.dlang.org/show_bug.cgi?id=4072 + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(foo(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (enclosing is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ + + for (TemplatePrevious* p = td.previous; p; p = p.prev) + { + if (!arrayObjectMatch(*p.dedargs, *dedargs)) + continue; + //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); + /* It must be a subscope of p.sc, other scope chains are not recursive + * instantiations. + * the chain of enclosing scopes is broken by paramscope (its enclosing + * scope is _scope, but paramscope.callsc is the instantiating scope). So + * it's good enough to check the chain of callsc + */ + for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc) + { + // The first scx might be identical for nested eponymeous templates, e.g. + // template foo() { void foo()() {...} } + if (scx == p.sc && scx !is paramscope.callsc) + return false; + } + /* BUG: should also check for ref param differences + */ + } + + TemplatePrevious pr; + pr.prev = td.previous; + pr.sc = paramscope.callsc; + pr.dedargs = dedargs; + td.previous = ≺ // add this to threaded list + + Scope* scx = paramscope.push(ti); + scx.parent = ti; + scx.tinst = null; + scx.minst = null; + // Set SCOPE.constraint before declaring function parameters for the static condition + // (previously, this was immediately before calling evalStaticCondition), so the + // semantic pass knows not to issue deprecation warnings for these throw-away decls. + // https://issues.dlang.org/show_bug.cgi?id=21831 + scx.flags |= SCOPE.constraint; + + assert(!ti.symtab); + if (fd) + { + /* Declare all the function parameters as variables and add them to the scope + * Making parameters is similar to FuncDeclaration.semantic3 + */ + auto tf = fd.type.isTypeFunction(); + + scx.parent = fd; + + Parameters* fparameters = tf.parameterList.parameters; + const nfparams = tf.parameterList.length; + foreach (i, fparam; tf.parameterList) + { + fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); + fparam.storageClass |= STC.parameter; + if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams) + { + fparam.storageClass |= STC.variadic; + /* Don't need to set STC.scope_ because this will only + * be evaluated at compile time + */ + } + } + foreach (fparam; *fparameters) + { + if (!fparam.ident) + continue; + // don't add it, if it has no name + auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); + fparam.storageClass |= STC.parameter; + v.storage_class = fparam.storageClass; + v.dsymbolSemantic(scx); + if (!ti.symtab) + ti.symtab = new DsymbolTable(); + if (!scx.insert(v)) + .error(td.loc, "%s `%s` parameter `%s.%s` is already defined", td.kind, td.toPrettyChars, td.toChars(), v.toChars()); + else + v.parent = fd; + } + if (td.isstatic) + fd.storage_class |= STC.static_; + declareThis(fd, scx); + } + + td.lastConstraint = td.constraint.syntaxCopy(); + td.lastConstraintTiargs = ti.tiargs; + td.lastConstraintNegs.setDim(0); + + import dmd.staticcond; + + assert(ti.inst is null); + ti.inst = ti; // temporary instantiation to enable genIdent() + bool errors; + const bool result = evalStaticCondition(scx, td.constraint, td.lastConstraint, errors, &td.lastConstraintNegs); + if (result || errors) + { + td.lastConstraint = null; + td.lastConstraintTiargs = null; + td.lastConstraintNegs.setDim(0); + } + ti.inst = null; + ti.symtab = null; + scx = scx.pop(); + td.previous = pr.prev; // unlink from threaded list + if (errors) + return false; + return result; +} + +/******************************************* + * Append to buf a textual representation of template parameters with their arguments. + * Params: + * parameters = the template parameters + * tiargs = the correspondeing template arguments + * variadic = if it's a variadic argument list + * buf = where the text output goes + */ +void formatParamsWithTiargs(ref TemplateParameters parameters, ref Objects tiargs, bool variadic, ref OutBuffer buf) +{ + buf.writestring(" with `"); + + // write usual arguments line-by-line + // skips trailing default ones - they are not present in `tiargs` + const end = parameters.length - (variadic ? 1 : 0); + size_t i; + for (; i < tiargs.length && i < end; i++) + { + if (i) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + write(buf, parameters[i]); + buf.writestring(" = "); + write(buf, tiargs[i]); + } + // write remaining variadic arguments on the last line + if (variadic) + { + if (i) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + write(buf, parameters[end]); + buf.writestring(" = "); + buf.writeByte('('); + if (end < tiargs.length) + { + write(buf, tiargs[end]); + foreach (j; parameters.length .. tiargs.length) + { + buf.writestring(", "); + write(buf, tiargs[j]); + } + } + buf.writeByte(')'); + } + buf.writeByte('`'); +} + +/****************************** + * Create a scope for the parameters of the TemplateInstance + * `ti` in the parent scope sc from the ScopeDsymbol paramsym. + * + * If paramsym is null a new ScopeDsymbol is used in place of + * paramsym. + * Params: + * td = template that ti is an instance of + * ti = the TemplateInstance whose parameters to generate the scope for. + * sc = the parent scope of ti + * Returns: + * new scope for the parameters of ti + */ +Scope* createScopeForTemplateParameters(TemplateDeclaration td, TemplateInstance ti, Scope* sc) +{ + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = td._scope.parent; + Scope* paramscope = td._scope.push(paramsym); + paramscope.tinst = ti; + paramscope.minst = sc.minst; + paramscope.callsc = sc; + paramscope.stc = 0; + return paramscope; +} + +/******************************************** + * Determine partial specialization order of `td` vs `td2`. + * Params: + * sc = context + * td = first template + * td2 = second template + * argumentList = arguments to template + * Returns: + * MATCH - td is at least as specialized as td2 + * MATCH.nomatch - td2 is more specialized than td + */ +MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration td2, ArgumentList argumentList) +{ + enum LOG_LEASTAS = 0; + static if (LOG_LEASTAS) + { + printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); + } + + /* This works by taking the template parameters to this template + * declaration and feeding them to td2 as if it were a template + * instance. + * If it works, then this template is at least as specialized + * as td2. + */ + + // Set type arguments to dummy template instance to be types + // generated from the parameters to this template declaration + auto tiargs = new Objects(); + tiargs.reserve(td.parameters.length); + foreach (tp; *td.parameters) + { + if (tp.dependent) + break; + RootObject p = tp.dummyArg(); + if (!p) //TemplateTupleParameter + break; + + tiargs.push(p); + } + scope TemplateInstance ti = new TemplateInstance(Loc.initial, td.ident, tiargs); // create dummy template instance + + // Temporary Array to hold deduced types + Objects dedtypes = Objects(td2.parameters.length); + + // Attempt a type deduction + MATCH m = matchWithInstance(sc, td2, ti, dedtypes, argumentList, 1); + if (m > MATCH.nomatch) + { + /* A non-variadic template is more specialized than a + * variadic one. + */ + TemplateTupleParameter tp = td.isVariadic(); + if (tp && !tp.dependent && !td2.isVariadic()) + goto L1; + + static if (LOG_LEASTAS) + { + printf(" matches %d, so is least as specialized\n", m); + } + return m; + } +L1: + static if (LOG_LEASTAS) + { + printf(" doesn't match, so is not as specialized\n"); + } + return MATCH.nomatch; +} + +/************************************************* + * Match function arguments against a specific template function. + * + * Params: + * td = template declaration for template instance + * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments + * sc = instantiation scope + * fd = Partially instantiated function declaration, which is set to an instantiated function declaration + * tthis = 'this' argument if !NULL + * argumentList = arguments to function + * + * Returns: + * match pair of initial and inferred template arguments + */ +extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) +{ + version (none) + { + printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", td.toChars()); + for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) + { + Expression e = (*fargs)[i]; + printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); + } + printf("fd = %s\n", fd.toChars()); + printf("fd.type = %s\n", fd.type.toChars()); + if (tthis) + printf("tthis = %s\n", tthis.toChars()); + } + + assert(td._scope); + + auto dedargs = new Objects(td.parameters.length); + dedargs.zero(); + + Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T + dedtypes.setDim(td.parameters.length); + dedtypes.zero(); + + if (td.errors || fd.errors) + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + + // Set up scope for parameters + Scope* paramscope = createScopeForTemplateParameters(td, ti,sc); + + MATCHpair nomatch() + { + paramscope.pop(); + //printf("\tnomatch\n"); + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + } + + MATCHpair matcherror() + { + // todo: for the future improvement + paramscope.pop(); + //printf("\terror\n"); + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + } + // Mark the parameter scope as deprecated if the templated + // function is deprecated (since paramscope.enclosing is the + // calling scope already) + paramscope.stc |= fd.storage_class & STC.deprecated_; + + TemplateTupleParameter tp = td.isVariadic(); + Tuple declaredTuple = null; + + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + printf("\tdedarg[%d] = ", i); + RootObject oarg = (*dedargs)[i]; + if (oarg) + printf("%s", oarg.toChars()); + printf("\n"); + } + } + + size_t ntargs = 0; // array size of tiargs + size_t inferStart = 0; // index of first parameter to infer + const Loc instLoc = ti.loc; + MATCH matchTiargs = MATCH.exact; + + if (auto tiargs = ti.tiargs) + { + // Set initial template arguments + ntargs = tiargs.length; + size_t n = td.parameters.length; + if (tp) + n--; + if (ntargs > n) + { + if (!tp) + return nomatch(); + + /* The extra initial template arguments + * now form the tuple argument. + */ + auto t = new Tuple(ntargs - n); + assert(td.parameters.length); + (*dedargs)[td.parameters.length - 1] = t; + + for (size_t i = 0; i < t.objects.length; i++) + { + t.objects[i] = (*tiargs)[n + i]; + } + td.declareParameter(paramscope, tp, t); + declaredTuple = t; + } + else + n = ntargs; + + memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); + + for (size_t i = 0; i < n; i++) + { + assert(i < td.parameters.length); + Declaration sparam = null; + MATCH m = (*td.parameters)[i].matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCH.nomatch) + return nomatch(); + if (m < matchTiargs) + matchTiargs = m; + + sparam.dsymbolSemantic(paramscope); + if (!paramscope.insert(sparam)) + return nomatch(); + } + if (n < td.parameters.length && !declaredTuple) + { + inferStart = n; + } + else + inferStart = td.parameters.length; + //printf("tiargs matchTiargs = %d\n", matchTiargs); + } + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + printf("\tdedarg[%d] = ", i); + RootObject oarg = (*dedargs)[i]; + if (oarg) + printf("%s", oarg.toChars()); + printf("\n"); + } + } + + ParameterList fparameters = fd.getParameterList(); // function parameter list + const nfparams = fparameters.length; // number of function parameters + if (argumentList.hasNames) + return matcherror(); // TODO: resolve named args + Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * void foo(T, A...)(T t, A a); + * void main() { foo(1,2,3); } + */ + size_t fptupindex = IDX_NOTFOUND; + if (tp) // if variadic + { + // TemplateTupleParameter always makes most lesser matching. + matchTiargs = MATCH.convert; + + if (nfparams == 0 && argumentList.length != 0) // if no function parameters + { + if (!declaredTuple) + { + auto t = new Tuple(); + //printf("t = %p\n", t); + (*dedargs)[td.parameters.length - 1] = t; + td.declareParameter(paramscope, tp, t); + declaredTuple = t; + } + } + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? + if (fparam.type.ty != Tident) + continue; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); + if (!tp.ident.equals(tid.ident) || tid.idents.length) + continue; + + if (fparameters.varargs != VarArg.none) // variadic function doesn't + return nomatch(); // go with variadic template + + goto L1; + } + fptupindex = IDX_NOTFOUND; + L1: + } + } + + MATCH match = MATCH.exact; + if (td.toParent().isModule()) + tthis = null; + if (tthis) + { + bool hasttp = false; + + // Match 'tthis' to any TemplateThisParameter's + foreach (param; *td.parameters) + { + if (auto ttp = param.isTemplateThisParameter()) + { + hasttp = true; + + Type t = new TypeIdentifier(Loc.initial, ttp.ident); + MATCH m = deduceType(tthis, paramscope, t, *td.parameters, *dedtypes); + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; // pick worst match + } + } + + // Match attributes of tthis against attributes of fd + if (fd.type && !fd.isCtorDeclaration() && !(td._scope.stc & STC.static_)) + { + StorageClass stc = td._scope.stc | fd.storage_class2; + // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 + Dsymbol p = td.parent; + while (p.isTemplateDeclaration() || p.isTemplateInstance()) + p = p.parent; + AggregateDeclaration ad = p.isAggregateDeclaration(); + if (ad) + stc |= ad.storage_class; + + ubyte mod = fd.type.mod; + if (stc & STC.immutable_) + mod = MODFlags.immutable_; + else + { + if (stc & (STC.shared_ | STC.synchronized_)) + mod |= MODFlags.shared_; + if (stc & STC.const_) + mod |= MODFlags.const_; + if (stc & STC.wild) + mod |= MODFlags.wild; + } + + ubyte thismod = tthis.mod; + if (hasttp) + mod = MODmerge(thismod, mod); + MATCH m = MODmethodConv(thismod, mod); + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + } + } + + // Loop through the function parameters + { + //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); + //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); + size_t argi = 0; + size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs + uint inoutMatch = 0; // for debugging only + for (size_t parami = 0; parami < nfparams; parami++) + { + Parameter fparam = fparameters[parami]; + + // Apply function parameter storage classes to parameter types + Type prmtype = fparam.type.addStorageClass(fparam.storageClass); + + Expression farg; + + /* See function parameters which wound up + * as part of a template tuple parameter. + */ + if (fptupindex != IDX_NOTFOUND && parami == fptupindex) + { + TypeIdentifier tid = prmtype.isTypeIdentifier(); + assert(tid); + if (!declaredTuple) + { + /* The types of the function arguments + * now form the tuple argument. + */ + declaredTuple = new Tuple(); + (*dedargs)[td.parameters.length - 1] = declaredTuple; + + /* Count function parameters with no defaults following a tuple parameter. + * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) + */ + size_t rem = 0; + foreach (j; parami + 1 .. nfparams) + { + Parameter p = fparameters[j]; + if (p.defaultArg) + { + break; + } + if (!reliesOnTemplateParameters(p.type, (*td.parameters)[inferStart .. td.parameters.length])) + { + Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); + if (auto ptt = pt.isTypeTuple()) + rem += ptt.arguments.length; + else + rem += 1; + } + else + { + ++rem; + } + } + + if (nfargs2 - argi < rem) + return nomatch(); + declaredTuple.objects.setDim(nfargs2 - argi - rem); + foreach (i; 0 .. declaredTuple.objects.length) + { + farg = fargs[argi + i]; + + // Check invalid arguments to detect errors early. + if (farg.op == EXP.error || farg.type.ty == Terror) + return nomatch(); + + if (!fparam.isLazy() && farg.type.ty == Tvoid) + return nomatch(); + + Type tt; + MATCH m; + if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) + { + inoutMatch |= wm; + m = MATCH.constant; + } + else + { + m = deduceTypeHelper(farg.type, tt, tid); + } + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + + /* Remove top const for dynamic array types and pointer types + */ + if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) + { + tt = tt.mutableOf(); + } + declaredTuple.objects[i] = tt; + } + td.declareParameter(paramscope, tp, declaredTuple); + } + else + { + // https://issues.dlang.org/show_bug.cgi?id=6810 + // If declared tuple is not a type tuple, + // it cannot be function parameter types. + for (size_t i = 0; i < declaredTuple.objects.length; i++) + { + if (!isType(declaredTuple.objects[i])) + return nomatch(); + } + } + assert(declaredTuple); + argi += declaredTuple.objects.length; + continue; + } + + // If parameter type doesn't depend on inferred template parameters, + // semantic it to get actual type. + if (!reliesOnTemplateParameters(prmtype, (*td.parameters)[inferStart .. td.parameters.length])) + { + // should copy prmtype to avoid affecting semantic result + prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); + + if (TypeTuple tt = prmtype.isTypeTuple()) + { + const tt_dim = tt.arguments.length; + for (size_t j = 0; j < tt_dim; j++, ++argi) + { + Parameter p = (*tt.arguments)[j]; + if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && + parami + 1 == nfparams && argi < fargs.length) + { + prmtype = p.type; + goto Lvarargs; + } + if (argi >= fargs.length) + { + if (p.defaultArg) + continue; + + // https://issues.dlang.org/show_bug.cgi?id=19888 + if (fparam.defaultArg) + break; + + return nomatch(); + } + farg = fargs[argi]; + if (!farg.implicitConvTo(p.type)) + return nomatch(); + } + continue; + } + } + + if (argi >= fargs.length) // if not enough arguments + { + if (!fparam.defaultArg) + goto Lvarargs; + + /* https://issues.dlang.org/show_bug.cgi?id=2803 + * Before the starting of type deduction from the function + * default arguments, set the already deduced parameters into paramscope. + * It's necessary to avoid breaking existing acceptable code. Cases: + * + * 1. Already deduced template parameters can appear in fparam.defaultArg: + * auto foo(A, B)(A a, B b = A.stringof); + * foo(1); + * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' + * + * 2. If prmtype depends on default-specified template parameter, the + * default type should be preferred. + * auto foo(N = size_t, R)(R r, N start = 0) + * foo([1,2,3]); + * // at fparam `N start = 0`, N should be 'size_t' before + * // the deduction result from fparam.defaultArg. + */ + if (argi == fargs.length) + { + foreach (ref dedtype; *dedtypes) + { + Type at = isType(dedtype); + if (at && at.ty == Tnone) + { + TypeDeduced xt = cast(TypeDeduced)at; + dedtype = xt.tded; // 'unbox' + } + } + for (size_t i = ntargs; i < dedargs.length; i++) + { + TemplateParameter tparam = (*td.parameters)[i]; + + RootObject oarg = (*dedargs)[i]; + RootObject oded = (*dedtypes)[i]; + if (oarg) + continue; + + if (oded) + { + if (tparam.specialization() || !tparam.isTemplateTypeParameter()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", + td.kind, td.toPrettyChars, td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + else + { + if (MATCH.convert < matchTiargs) + matchTiargs = MATCH.convert; + } + (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded); + } + else + { + oded = tparam.defaultArg(instLoc, paramscope); + if (oded) + (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded); + } + } + } + nfargs2 = argi + 1; + + /* If prmtype does not depend on any template parameters: + * + * auto foo(T)(T v, double x = 0); + * foo("str"); + * // at fparam == 'double x = 0' + * + * or, if all template parameters in the prmtype are already deduced: + * + * auto foo(R)(R range, ElementType!R sum = 0); + * foo([1,2,3]); + * // at fparam == 'ElementType!R sum = 0' + * + * Deducing prmtype from fparam.defaultArg is not necessary. + */ + if (prmtype.deco || prmtype.syntaxCopy().trySemantic(td.loc, paramscope)) + { + ++argi; + continue; + } + + // Deduce prmtype from the defaultArg. + farg = fparam.defaultArg.syntaxCopy(); + farg = farg.expressionSemantic(paramscope); + farg = resolveProperties(paramscope, farg); + } + else + { + farg = fargs[argi]; + } + { + // Check invalid arguments to detect errors early. + if (farg.op == EXP.error || farg.type.ty == Terror) + return nomatch(); + + Type att = null; + Lretry: + version (none) + { + printf("\tfarg.type = %s\n", farg.type.toChars()); + printf("\tfparam.type = %s\n", prmtype.toChars()); + } + Type argtype = farg.type; + + if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_) + return nomatch(); + + // https://issues.dlang.org/show_bug.cgi?id=12876 + // Optimize argument to allow CT-known length matching + farg = farg.optimize(WANTvalue, fparam.isReference()); + //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); + + RootObject oarg = farg; + if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) + { + /* Allow expressions that have CT-known boundaries and type [] to match with [dim] + */ + bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); + if (auto aaType = prmtype.isTypeAArray()) + { + if (auto indexType = aaType.index.isTypeIdentifier()) + { + inferIndexType = indexType.idents.length == 0; + } + } + if (inferIndexType) + { + if (StringExp se = farg.isStringExp()) + { + argtype = se.type.nextOf().sarrayOf(se.len); + } + else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) + { + argtype = ae.type.nextOf().sarrayOf(ae.elements.length); + } + else if (SliceExp se = farg.isSliceExp()) + { + if (Type tsa = toStaticArrayType(se)) + argtype = tsa; + } + } + + oarg = argtype; + } + else if ((fparam.storageClass & STC.out_) == 0 && + (argtype.ty == Tarray || argtype.ty == Tpointer) && + templateParameterLookup(prmtype, td.parameters) != IDX_NOTFOUND && + prmtype.isTypeIdentifier().idents.length == 0) + { + /* The farg passing to the prmtype always make a copy. Therefore, + * we can shrink the set of the deduced type arguments for prmtype + * by adjusting top-qualifier of the argtype. + * + * prmtype argtype ta + * T <- const(E)[] const(E)[] + * T <- const(E[]) const(E)[] + * qualifier(T) <- const(E)[] const(E[]) + * qualifier(T) <- const(E[]) const(E[]) + */ + Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); + if (ta != argtype) + { + Expression ea = farg.copy(); + ea.type = ta; + oarg = ea; + } + } + + if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) + goto Lvarargs; + + uint im = 0; + MATCH m = deduceType(oarg, paramscope, prmtype, *td.parameters, *dedtypes, &im, inferStart); + //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); + inoutMatch |= im; + + /* If no match, see if the argument can be matched by using + * implicit conversions. + */ + if (m == MATCH.nomatch && prmtype.deco) + m = farg.implicitConvTo(prmtype); + + if (m == MATCH.nomatch) + { + AggregateDeclaration ad = isAggregate(farg.type); + if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype)) + { + // https://issues.dlang.org/show_bug.cgi?id=12537 + // The isRecursiveAliasThis() call above + + /* If a semantic error occurs while doing alias this, + * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), + * just regard it as not a match. + * + * We also save/restore sc.func.flags to avoid messing up + * attribute inference in the evaluation. + */ + const oldflags = sc.func ? sc.func.flags : 0; + auto e = resolveAliasThis(sc, farg, true); + if (sc.func) + sc.func.flags = oldflags; + if (e) + { + farg = e; + goto Lretry; + } + } + } + + if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) + { + if (!farg.isLvalue()) + { + 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] + } + else if (global.params.rvalueRefParam == FeatureState.enabled) + { + // Allow implicit conversion to ref + } + else + return nomatch(); + } + } + if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) + { + if (!farg.isLvalue()) + return nomatch(); + if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 + return nomatch(); + } + if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid) + m = MATCH.convert; + if (m != MATCH.nomatch) + { + if (m < match) + match = m; // pick worst match + argi++; + continue; + } + } + + Lvarargs: + /* The following code for variadic arguments closely + * matches TypeFunction.callMatch() + */ + if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams)) + return nomatch(); + + /* Check for match with function parameter T... + */ + Type tb = prmtype.toBasetype(); + switch (tb.ty) + { + // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). + case Tsarray: + case Taarray: + { + // Perhaps we can do better with this, see TypeFunction.callMatch() + if (TypeSArray tsa = tb.isTypeSArray()) + { + dinteger_t sz = tsa.dim.toInteger(); + if (sz != fargs.length - argi) + return nomatch(); + } + else if (TypeAArray taa = tb.isTypeAArray()) + { + Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); + + size_t i = templateParameterLookup(taa.index, td.parameters); + if (i == IDX_NOTFOUND) + { + Expression e; + Type t; + Dsymbol s; + Scope *sco; + + uint errors = global.startGagging(); + /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 + * The parameter isn't part of the template + * ones, let's try to find it in the + * instantiation scope 'sc' and the one + * belonging to the template itself. */ + sco = sc; + taa.index.resolve(instLoc, sco, e, t, s); + if (!e) + { + sco = paramscope; + taa.index.resolve(instLoc, sco, e, t, s); + } + global.endGagging(errors); + + if (!e) + return nomatch(); + + e = e.ctfeInterpret(); + e = e.implicitCastTo(sco, Type.tsize_t); + e = e.optimize(WANTvalue); + if (!dim.equals(e)) + return nomatch(); + } + else + { + // This code matches code in TypeInstance.deduceType() + TemplateParameter tprm = (*td.parameters)[i]; + TemplateValueParameter tvp = tprm.isTemplateValueParameter(); + if (!tvp) + return nomatch(); + Expression e = cast(Expression)(*dedtypes)[i]; + if (e) + { + if (!dim.equals(e)) + return nomatch(); + } + else + { + Type vt = tvp.valType.typeSemantic(Loc.initial, sc); + MATCH m = dim.implicitConvTo(vt); + if (m == MATCH.nomatch) + return nomatch(); + (*dedtypes)[i] = dim; + } + } + } + goto case Tarray; + } + case Tarray: + { + TypeArray ta = cast(TypeArray)tb; + Type tret = fparam.isLazyArray(); + for (; argi < fargs.length; argi++) + { + Expression arg = fargs[argi]; + assert(arg); + + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + if (tret) + { + if (ta.next.equals(arg.type)) + { + m = MATCH.exact; + } + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + { + if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + } + } + } + else + { + uint wm = 0; + m = deduceType(arg, paramscope, ta.next, *td.parameters, *dedtypes, &wm, inferStart); + inoutMatch |= wm; + } + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + return nomatch(); + } + assert(0); + } + //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); + if (argi != nfargs2 && fparameters.varargs == VarArg.none) + return nomatch(); + } + +Lmatch: + foreach (ref dedtype; *dedtypes) + { + if (Type at = isType(dedtype)) + { + if (at.ty == Tnone) + { + TypeDeduced xt = cast(TypeDeduced)at; + at = xt.tded; // 'unbox' + } + dedtype = at.merge2(); + } + } + for (size_t i = ntargs; i < dedargs.length; i++) + { + TemplateParameter tparam = (*td.parameters)[i]; + //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); + + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + RootObject oarg = (*dedargs)[i]; + RootObject oded = (*dedtypes)[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg.toChars()); + //if (oded) printf("oded: %s\n", oded.toChars()); + if (oarg) + continue; + + if (oded) + { + if (tparam.specialization() || !tparam.isTemplateTypeParameter()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + else + { + // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 + if (MATCH.convert < matchTiargs) + matchTiargs = MATCH.convert; + } + } + else + { + oded = tparam.defaultArg(instLoc, paramscope); + if (!oded) + { + // if tuple parameter and + // tuple parameter was not in function parameter list and + // we're one or more arguments short (i.e. no tuple argument) + if (tparam == tp && + fptupindex == IDX_NOTFOUND && + ntargs <= dedargs.length - 1) + { + // make tuple argument an empty tuple + oded = new Tuple(); + } + else + return nomatch(); + } + if (isError(oded)) + return matcherror(); + ntargs++; + + /* At the template parameter T, the picked default template argument + * X!int should be matched to T in order to deduce dependent + * template parameter A. + * auto foo(T : X!A = X!int, A...)() { ... } + * foo(); // T <-- X!int, A <-- (int) + */ + if (tparam.specialization()) + { + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + } + oded = td.declareParameter(paramscope, tparam, oded); + (*dedargs)[i] = oded; + } + + /* https://issues.dlang.org/show_bug.cgi?id=7469 + * As same as the code for 7469 in findBestMatch, + * expand a Tuple in dedargs to normalize template arguments. + */ + if (auto d = dedargs.length) + { + if (auto va = isTuple((*dedargs)[d - 1])) + { + dedargs.setDim(d - 1); + dedargs.insert(d - 1, &va.objects); + } + } + ti.tiargs = dedargs; // update to the normalized template arguments. + + // Partially instantiate function for constraint and fd.leastAsSpecialized() + { + assert(paramscope.scopesym); + Scope* sc2 = td._scope; + sc2 = sc2.push(paramscope.scopesym); + sc2 = sc2.push(ti); + sc2.parent = ti; + sc2.tinst = ti; + sc2.minst = sc.minst; + sc2.stc |= fd.storage_class & STC.deprecated_; + + fd = doHeaderInstantiation(td, ti, sc2, fd, tthis, argumentList.arguments); + sc2 = sc2.pop(); + sc2 = sc2.pop(); + + if (!fd) + return nomatch(); + } + + if (td.constraint) + { + if (!evaluateConstraint(td, ti, sc, paramscope, dedargs, fd)) + return nomatch(); + } + + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + RootObject o = (*dedargs)[i]; + printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); + } + } + + paramscope.pop(); + //printf("\tmatch %d\n", match); + return MATCHpair(matchTiargs, match); +} + +/************************************************* + * Limited function template instantiation for using fd.leastAsSpecialized() + */ +private +FuncDeclaration doHeaderInstantiation(TemplateDeclaration td, TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs) +{ + assert(fd); + version (none) + { + printf("doHeaderInstantiation this = %s\n", toChars()); + } + + // function body and contracts are not need + if (fd.isCtorDeclaration()) + fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy()); + else + fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy()); + fd.parent = ti; + + assert(fd.type.ty == Tfunction); + auto tf = fd.type.isTypeFunction(); + tf.fargs = fargs; + + if (tthis) + { + // Match 'tthis' to any TemplateThisParameter's + bool hasttp = false; + foreach (tp; *td.parameters) + { + TemplateThisParameter ttp = tp.isTemplateThisParameter(); + if (ttp) + hasttp = true; + } + if (hasttp) + { + tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction(); + assert(!tf.deco); + } + } + + Scope* scx = sc2.push(); + + // Shouldn't run semantic on default arguments and return type. + foreach (ref params; *tf.parameterList.parameters) + params.defaultArg = null; + tf.incomplete = true; + + if (fd.isCtorDeclaration()) + { + // For constructors, emitting return type is necessary for + // isReturnIsolated() in functionResolve. + tf.isctor = true; + + Dsymbol parent = td.toParentDecl(); + Type tret; + AggregateDeclaration ad = parent.isAggregateDeclaration(); + if (!ad || parent.isUnionDeclaration()) + { + tret = Type.tvoid; + } + else + { + tret = ad.handleType(); + assert(tret); + tret = tret.addStorageClass(fd.storage_class | scx.stc); + tret = tret.addMod(tf.mod); + } + tf.next = tret; + if (ad && ad.isStructDeclaration()) + tf.isref = 1; + //printf("tf = %s\n", tf.toChars()); + } + else + tf.next = null; + fd.type = tf; + fd.type = fd.type.addSTC(scx.stc); + fd.type = fd.type.typeSemantic(fd.loc, scx); + scx = scx.pop(); + + if (fd.type.ty != Tfunction) + return null; + + fd.originalType = fd.type; // for mangling + //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod); + //printf("fd.needThis() = %d\n", fd.needThis()); + + return fd; +} + +/************************************************** + * Declare template parameter tp with value o, and install it in the scope sc. + */ +extern (D) RootObject declareParameter(TemplateDeclaration td, Scope* sc, TemplateParameter tp, RootObject o) +{ + //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); + Type ta = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + + Declaration d; + VarDeclaration v = null; + + if (ea) + { + if (ea.op == EXP.type) + ta = ea.type; + else if (auto se = ea.isScopeExp()) + sa = se.sds; + else if (auto te = ea.isThisExp()) + sa = te.var; + else if (auto se = ea.isSuperExp()) + sa = se.var; + else if (auto fe = ea.isFuncExp()) + { + if (fe.td) + sa = fe.td; + else + sa = fe.fd; + } + } + + if (ta) + { + //printf("type %s\n", ta.toChars()); + auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta); + ad.storage_class |= STC.templateparameter; + d = ad; + } + else if (sa) + { + //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); + auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa); + ad.storage_class |= STC.templateparameter; + d = ad; + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer _init = new ExpInitializer(td.loc, ea); + TemplateValueParameter tvp = tp.isTemplateValueParameter(); + Type t = tvp ? tvp.valType : null; + v = new VarDeclaration(td.loc, t, tp.ident, _init); + v.storage_class = STC.manifest | STC.templateparameter; + d = v; + } + else if (va) + { + //printf("\ttuple\n"); + d = new TupleDeclaration(td.loc, tp.ident, &va.objects); + } + else + { + assert(0); + } + d.storage_class |= STC.templateparameter; + + if (ta) + { + Type t = ta; + // consistent with Type.checkDeprecated() + while (t.ty != Tenum) + { + if (!t.nextOf()) + break; + t = (cast(TypeNext)t).next; + } + if (Dsymbol s = t.toDsymbol(sc)) + { + if (s.isDeprecated()) + d.storage_class |= STC.deprecated_; + } + } + else if (sa) + { + if (sa.isDeprecated()) + d.storage_class |= STC.deprecated_; + } + + if (!sc.insert(d)) + .error(td.loc, "%s `%s` declaration `%s` is already defined", td.kind, td.toPrettyChars, tp.ident.toChars()); + d.dsymbolSemantic(sc); + /* So the caller's o gets updated with the result of semantic() being run on o + */ + if (v) + o = v._init.initializerToExpression(); + return o; +} + +/************************************************* + * Given function arguments, figure out which template function + * to expand, and return matching result. + * Params: + * m = matching result + * dstart = the root of overloaded function templates + * loc = instantiation location + * sc = instantiation scope + * tiargs = initial list of template arguments + * tthis = if !NULL, the 'this' pointer argument + * argumentList= arguments to function + * errorHelper = delegate to send error message to if not null + */ +void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, + Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null) +{ + version (none) + { + printf("functionResolve() dstart = %s\n", dstart.toChars()); + printf(" tiargs:\n"); + if (tiargs) + { + for (size_t i = 0; i < tiargs.length; i++) + { + RootObject arg = (*tiargs)[i]; + printf("\t%s\n", arg.toChars()); + } + } + printf(" fargs:\n"); + for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) + { + Expression arg = (*fargs)[i]; + printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); + //printf("\tty = %d\n", arg.type.ty); + } + //printf("stc = %llx\n", dstart._scope.stc); + //printf("match:t/f = %d/%d\n", ta_last, m.last); + } + + // results + int property = 0; // 0: uninitialized + // 1: seen @property + // 2: not @property + size_t ov_index = 0; + TemplateDeclaration td_best; + TemplateInstance ti_best; + MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch; + Type tthis_best; + + int applyFunction(FuncDeclaration fd) + { + // skip duplicates + if (fd == m.lastf) + return 0; + // explicitly specified tiargs never match to non template function + if (tiargs && tiargs.length > 0) + return 0; + + // constructors need a valid scope in order to detect semantic errors + if (!fd.isCtorDeclaration && + fd.semanticRun < PASS.semanticdone) + { + fd.ungagSpeculative(); + fd.dsymbolSemantic(null); + } + if (fd.semanticRun < PASS.semanticdone) + { + .error(loc, "forward reference to template `%s`", fd.toChars()); + return 1; + } + //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); + auto tf = fd.type.isTypeFunction(); + + int prop = tf.isproperty ? 1 : 2; + if (property == 0) + property = prop; + else if (property != prop) + error(fd.loc, "cannot overload both property and non-property functions"); + + /* For constructors, qualifier check will be opposite direction. + * Qualified constructor always makes qualified object, then will be checked + * that it is implicitly convertible to tthis. + */ + Type tthis_fd = fd.needThis() ? tthis : null; + bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); + if (isCtorCall) + { + //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(), + // tf.mod, tthis_fd.mod, fd.isReturnIsolated()); + if (MODimplicitConv(tf.mod, tthis_fd.mod) || + tf.isWild() && tf.isShared() == tthis_fd.isShared() || + fd.isReturnIsolated()) + { + /* && tf.isShared() == tthis_fd.isShared()*/ + // Uniquely constructed object can ignore shared qualifier. + // TODO: Is this appropriate? + tthis_fd = null; + } + else + return 0; // MATCH.nomatch + } + /* Fix Issue 17970: + If a struct is declared as shared the dtor is automatically + considered to be shared, but when the struct is instantiated + the instance is no longer considered to be shared when the + function call matching is done. The fix makes it so that if a + struct declaration is shared, when the destructor is called, + the instantiated struct is also considered shared. + */ + if (auto dt = fd.isDtorDeclaration()) + { + auto dtmod = dt.type.toTypeFunction(); + auto shared_dtor = dtmod.mod & MODFlags.shared_; + auto shared_this = tthis_fd !is null ? + tthis_fd.mod & MODFlags.shared_ : 0; + if (shared_dtor && !shared_this) + tthis_fd = dtmod; + else if (shared_this && !shared_dtor && tthis_fd !is null) + tf.mod = tthis_fd.mod; + } + const(char)* failMessage; + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); + //printf("test1: mfa = %d\n", mfa); + if (failMessage) + errorHelper(failMessage); + if (mfa == MATCH.nomatch) + return 0; + + int firstIsBetter() + { + td_best = null; + ti_best = null; + ta_last = MATCH.exact; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m.count = 1; + return 0; + } + + if (mfa > m.last) return firstIsBetter(); + if (mfa < m.last) return 0; + + /* See if one of the matches overrides the other. + */ + assert(m.lastf); + if (m.lastf.overrides(fd)) return 0; + if (fd.overrides(m.lastf)) return firstIsBetter(); + + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) return firstIsBetter(); + if (c1 < c2) return 0; + } + + /* The 'overrides' check above does covariant checking only + * for virtual member functions. It should do it for all functions, + * but in order to not risk breaking code we put it after + * the 'leastAsSpecialized' check. + * In the future try moving it before. + * I.e. a not-the-same-but-covariant match is preferred, + * as it is more restrictive. + */ + if (!m.lastf.type.equals(fd.type)) + { + //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type)); + const lastCovariant = m.lastf.type.covariant(fd.type); + const firstCovariant = fd.type.covariant(m.lastf.type); + + if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no) + { + if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no) + { + return 0; + } + } + else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no) + { + return firstIsBetter(); + } + } + + /* If the two functions are the same function, like: + * int foo(int); + * int foo(int x) { ... } + * then pick the one with the body. + * + * If none has a body then don't care because the same + * real function would be linked to the decl (e.g from object file) + */ + if (tf.equals(m.lastf.type) && + fd.storage_class == m.lastf.storage_class && + fd.parent == m.lastf.parent && + fd.visibility == m.lastf.visibility && + fd._linkage == m.lastf._linkage) + { + if (fd.fbody && !m.lastf.fbody) + return firstIsBetter(); + if (!fd.fbody) + return 0; + } + + // https://issues.dlang.org/show_bug.cgi?id=14450 + // Prefer exact qualified constructor for the creating object type + if (isCtorCall && tf.mod != m.lastf.type.mod) + { + if (tthis.mod == tf.mod) return firstIsBetter(); + if (tthis.mod == m.lastf.type.mod) return 0; + } + + m.nextf = fd; + m.count++; + return 0; + } + + int applyTemplate(TemplateDeclaration td) + { + //printf("applyTemplate(): td = %s\n", td.toChars()); + if (td == td_best) // skip duplicates + return 0; + + if (!sc) + sc = td._scope; // workaround for Type.aliasthisOf + + if (td.semanticRun == PASS.initial && td._scope) + { + // Try to fix forward reference. Ungag errors while doing so. + td.ungagSpeculative(); + td.dsymbolSemantic(td._scope); + } + if (td.semanticRun == PASS.initial) + { + .error(loc, "forward reference to template `%s`", td.toChars()); + Lerror: + m.lastf = null; + m.count = 0; + m.last = MATCH.nomatch; + return 1; + } + //printf("td = %s\n", td.toChars()); + + if (argumentList.hasNames) + { + .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet"); + goto Lerror; + } + auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; + if (!f) + { + if (!tiargs) + tiargs = new Objects(); + auto ti = new TemplateInstance(loc, td, tiargs); + Objects dedtypes = Objects(td.parameters.length); + assert(td.semanticRun != PASS.initial); + MATCH mta = matchWithInstance(sc, td, ti, dedtypes, argumentList, 0); + //printf("matchWithInstance = %d\n", mta); + if (mta == MATCH.nomatch || mta < ta_last) // no match or less match + return 0; + + ti.templateInstanceSemantic(sc, argumentList); + if (!ti.inst) // if template failed to expand + return 0; + + Dsymbol s = ti.inst.toAlias(); + FuncDeclaration fd; + if (auto tdx = s.isTemplateDeclaration()) + { + Objects dedtypesX; // empty tiargs + + // https://issues.dlang.org/show_bug.cgi?id=11553 + // Check for recursive instantiation of tdx. + for (TemplatePrevious* p = tdx.previous; p; p = p.prev) + { + if (arrayObjectMatch(*p.dedargs, dedtypesX)) + { + //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); + /* It must be a subscope of p.sc, other scope chains are not recursive + * instantiations. + */ + for (Scope* scx = sc; scx; scx = scx.enclosing) + { + if (scx == p.sc) + { + error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars()); + goto Lerror; + } + } + } + /* BUG: should also check for ref param differences + */ + } + + TemplatePrevious pr; + pr.prev = tdx.previous; + pr.sc = sc; + pr.dedargs = &dedtypesX; + tdx.previous = ≺ // add this to threaded list + + fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); + + tdx.previous = pr.prev; // unlink from threaded list + } + else if (s.isFuncDeclaration()) + { + fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); + } + else + goto Lerror; + + if (!fd) + return 0; + + if (fd.type.ty != Tfunction) + { + m.lastf = fd; // to propagate "error match" + m.count = 1; + m.last = MATCH.nomatch; + return 1; + } + + Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; + + auto tf = fd.type.isTypeFunction(); + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); + if (mfa < m.last) + return 0; + + if (mta < ta_last) goto Ltd_best2; + if (mta > ta_last) goto Ltd2; + + if (mfa < m.last) goto Ltd_best2; + if (mfa > m.last) goto Ltd2; + + // td_best and td are ambiguous + //printf("Lambig2\n"); + m.nextf = fd; + m.count++; + return 0; + + Ltd_best2: + return 0; + + Ltd2: + // td is the new best match + assert(td._scope); + td_best = td; + ti_best = null; + property = 0; // (backward compatibility) + ta_last = mta; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = 0; + m.nextf = null; + m.count = 1; + return 0; + } + + //printf("td = %s\n", td.toChars()); + for (size_t ovi = 0; f; f = f.overnext0, ovi++) + { + if (f.type.ty != Tfunction || f.errors) + goto Lerror; + + /* This is a 'dummy' instance to evaluate constraint properly. + */ + auto ti = new TemplateInstance(loc, td, tiargs); + ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. + + auto fd = f; + MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList); + MATCH mta = x.mta; + MATCH mfa = x.mfa; + //printf("match:t/f = %d/%d\n", mta, mfa); + if (!fd || mfa == MATCH.nomatch) + continue; + + Type tthis_fd = fd.needThis() ? tthis : null; + + bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); + if (isCtorCall) + { + // Constructor call requires additional check. + auto tf = fd.type.isTypeFunction(); + assert(tf.next); + if (MODimplicitConv(tf.mod, tthis_fd.mod) || + tf.isWild() && tf.isShared() == tthis_fd.isShared() || + fd.isReturnIsolated()) + { + tthis_fd = null; + } + else + continue; // MATCH.nomatch + + // need to check here whether the constructor is the member of a struct + // declaration that defines a copy constructor. This is already checked + // in the semantic of CtorDeclaration, however, when matching functions, + // the template instance is not expanded. + // https://issues.dlang.org/show_bug.cgi?id=21613 + auto ad = fd.isThis(); + auto sd = ad.isStructDeclaration(); + if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti)) + continue; + } + + if (mta < ta_last) goto Ltd_best; + if (mta > ta_last) goto Ltd; + + if (mfa < m.last) goto Ltd_best; + if (mfa > m.last) goto Ltd; + + if (td_best) + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); + //printf("1: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + assert(fd && m.lastf); + { + // Disambiguate by tf.callMatch + auto tf1 = fd.type.isTypeFunction(); + auto tf2 = m.lastf.type.isTypeFunction(); + MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc); + MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc); + //printf("2: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + { + // Disambiguate by picking the most specialized FunctionDeclaration + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); + //printf("3: c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) goto Ltd; + if (c1 < c2) goto Ltd_best; + } + + // https://issues.dlang.org/show_bug.cgi?id=14450 + // Prefer exact qualified constructor for the creating object type + if (isCtorCall && fd.type.mod != m.lastf.type.mod) + { + if (tthis.mod == fd.type.mod) goto Ltd; + if (tthis.mod == m.lastf.type.mod) goto Ltd_best; + } + + m.nextf = fd; + m.count++; + continue; + + Ltd_best: // td_best is the best match so far + //printf("Ltd_best\n"); + continue; + + Ltd: // td is the new best match + //printf("Ltd\n"); + assert(td._scope); + td_best = td; + ti_best = ti; + property = 0; // (backward compatibility) + ta_last = mta; + m.last = mfa; + m.lastf = fd; + tthis_best = tthis_fd; + ov_index = ovi; + m.nextf = null; + m.count = 1; + continue; + } + return 0; + } + + auto td = dstart.isTemplateDeclaration(); + if (td && td.funcroot) + dstart = td.funcroot; + overloadApply(dstart, (Dsymbol s) + { + if (s.errors) + return 0; + if (auto fd = s.isFuncDeclaration()) + return applyFunction(fd); + if (auto td = s.isTemplateDeclaration()) + return applyTemplate(td); + return 0; + }, sc); + + //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf); + if (td_best && ti_best && m.count == 1) + { + // Matches to template function + assert(td_best.onemember && td_best.onemember.isFuncDeclaration()); + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert(td_best._scope); + if (!sc) + sc = td_best._scope; // workaround for Type.aliasthisOf + + auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); + ti.templateInstanceSemantic(sc, argumentList); + + m.lastf = ti.toAlias().isFuncDeclaration(); + if (!m.lastf) + goto Lnomatch; + if (ti.errors) + { + Lerror: + m.count = 1; + assert(m.lastf); + m.last = MATCH.nomatch; + return; + } + + // look forward instantiated overload function + // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic. + // it has filled overnext0d + while (ov_index--) + { + m.lastf = m.lastf.overnext0; + assert(m.lastf); + } + + tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null; + + if (m.lastf.type.ty == Terror) + goto Lerror; + auto tf = m.lastf.type.isTypeFunction(); + if (!tf.callMatch(tthis_best, argumentList, 0, null, sc)) + goto Lnomatch; + + /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, + * a template instance can be matched while instantiating + * that same template. Thus, the function type can be incomplete. Complete it. + * + * https://issues.dlang.org/show_bug.cgi?id=9208 + * For auto function, completion should be deferred to the end of + * its semantic3. Should not complete it in here. + */ + if (tf.next && !m.lastf.inferRetType) + { + m.lastf.type = tf.typeSemantic(loc, sc); + } + } + else if (m.lastf) + { + // Matches to non template function, + // or found matches were ambiguous. + assert(m.count >= 1); + } + else + { + Lnomatch: + m.count = 0; + m.lastf = null; + m.last = MATCH.nomatch; + } +} diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 317a6e6..da4a3ee 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/lex.html#tokens, Tokens) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d) @@ -124,6 +124,7 @@ enum TOK : ubyte // Leaf operators identifier, string_, + interpolated, hexadecimalString, this_, super_, @@ -380,6 +381,7 @@ enum EXP : ubyte // Leaf operators identifier, string_, + interpolated, this_, super_, halt, @@ -623,6 +625,10 @@ static immutable TOK[TOK.max + 1] Ckeywords = } } (); +struct InterpolatedSet { + // all strings in the parts are zero terminated at length+1 + string[] parts; +} /*********************************************************** */ @@ -645,7 +651,11 @@ extern (C++) struct Token struct { - const(char)* ustring; // UTF8 string + union + { + const(char)* ustring; // UTF8 string + InterpolatedSet* interpolatedSet; + } uint len; ubyte postfix; // 'c', 'w', 'd' } @@ -833,6 +843,7 @@ extern (C++) struct Token // For debugging TOK.error: "error", TOK.string_: "string", + TOK.interpolated: "interpolated string", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", TOK.onScopeFailure: "scope(failure)", @@ -910,6 +921,24 @@ nothrow: return 0; } + extern(D) void appendInterpolatedPart(const ref OutBuffer buf) { + appendInterpolatedPart(cast(const(char)*)buf[].ptr, buf.length); + } + extern(D) void appendInterpolatedPart(const(char)[] str) { + appendInterpolatedPart(str.ptr, str.length); + } + extern(D) void appendInterpolatedPart(const(char)* ptr, size_t length) { + assert(value == TOK.interpolated); + if (interpolatedSet is null) + interpolatedSet = new InterpolatedSet; + + auto s = cast(char*)mem.xmalloc_noscan(length + 1); + memcpy(s, ptr, length); + s[length] = 0; + + interpolatedSet.parts ~= cast(string) s[0 .. length]; + } + /**** * Set to contents of ptr[0..length] * Params: @@ -918,6 +947,7 @@ nothrow: */ void setString(const(char)* ptr, size_t length) { + value = TOK.string_; auto s = cast(char*)mem.xmalloc_noscan(length + 1); memcpy(s, ptr, length); s[length] = 0; @@ -941,6 +971,7 @@ nothrow: */ void setString() { + value = TOK.string_; ustring = ""; len = 0; postfix = 0; @@ -948,92 +979,110 @@ nothrow: extern (C++) const(char)* toChars() const { + return toString().ptr; + } + + /********************************* + * Returns: + * a zero-terminated string representation of the token, + * sometimes reusing a static buffer, sometimes leaking memory + */ + extern (D) const(char)[] toString() const + { const bufflen = 3 + 3 * floatvalue.sizeof + 1; - __gshared char[bufflen] buffer; - const(char)* p = &buffer[0]; + __gshared char[bufflen + 2] buffer; // extra 2 for suffixes + char* p = &buffer[0]; switch (value) { case TOK.int32Literal: - snprintf(&buffer[0], bufflen, "%d", cast(int)intvalue); - break; + const length = snprintf(p, bufflen, "%d", cast(int)intvalue); + return p[0 .. length]; + case TOK.uns32Literal: case TOK.wchar_tLiteral: - snprintf(&buffer[0], bufflen, "%uU", cast(uint)unsvalue); - break; + const length = snprintf(p, bufflen, "%uU", cast(uint)unsvalue); + return p[0 .. length]; + case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.charLiteral: - { - OutBuffer buf; - buf.writeSingleCharLiteral(cast(dchar) intvalue); - buf.writeByte('\0'); - p = buf.extractChars(); - } - break; + OutBuffer buf; + buf.writeSingleCharLiteral(cast(dchar) intvalue); + return buf.extractSlice(true); + case TOK.int64Literal: - snprintf(&buffer[0], bufflen, "%lldL", cast(long)intvalue); - break; + const length = snprintf(p, bufflen, "%lldL", cast(long)intvalue); + return p[0 .. length]; + case TOK.uns64Literal: - snprintf(&buffer[0], bufflen, "%lluUL", cast(ulong)unsvalue); - break; + const length = snprintf(p, bufflen, "%lluUL", cast(ulong)unsvalue); + return p[0 .. length]; + case TOK.float32Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "f"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'f'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.float64Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + return p[0 .. length]; + case TOK.float80Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "L"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'L'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.imaginary32Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "fi"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length ] = 'f'; + p[length + 1] = 'i'; + p[length + 2] = 0; + return p[0 .. length + 2]; + case TOK.imaginary64Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "i"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'i'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.imaginary80Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "Li"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length ] = 'L'; + p[length + 1] = 'i'; + p[length + 2] = 0; + return p[0 .. length + 2]; + case TOK.string_: + OutBuffer buf; + buf.writeByte('"'); + for (size_t i = 0; i < len;) { - OutBuffer buf; - buf.writeByte('"'); - for (size_t i = 0; i < len;) - { - dchar c; - utf_decodeChar(ustring[0 .. len], i, c); - writeCharLiteral(buf, c); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractChars(); + dchar c; + utf_decodeChar(ustring[0 .. len], i, c); + writeCharLiteral(buf, c); } - break; + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + return buf.extractSlice(true); + case TOK.hexadecimalString: + OutBuffer buf; + buf.writeByte('x'); + buf.writeByte('"'); + foreach (size_t i; 0 .. len) { - OutBuffer buf; - buf.writeByte('x'); - buf.writeByte('"'); - foreach (size_t i; 0 .. len) - { - if (i) - buf.writeByte(' '); - buf.printf("%02x", ustring[i]); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractData(); - break; + if (i) + buf.writeByte(' '); + buf.printf("%02x", ustring[i]); } + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + return buf.extractSlice(true); + case TOK.identifier: case TOK.enum_: case TOK.struct_: @@ -1062,13 +1111,11 @@ nothrow: case TOK.complex64: case TOK.complex80: case TOK.void_: - p = ident.toChars(); - break; + return ident.toString(); + default: - p = toChars(value); - break; + return tochars[value]; } - return p; } static const(char)* toChars(TOK value) diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 560942d..ef91001 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -133,6 +133,7 @@ enum class TOK : unsigned char // Leaf operators identifier, string_, + interpolated, hexadecimalString, this_, super_, @@ -390,6 +391,7 @@ enum class EXP : unsigned char // Leaf operators identifier, string_, + interpolated, this_, super_, halt, @@ -461,7 +463,12 @@ struct Token real_t floatvalue; struct - { utf8_t *ustring; // UTF8 string + { + union + { + utf8_t *ustring; // UTF8 string + void *interpolatedSet; + }; unsigned len; unsigned char postfix; // 'c', 'w', 'd' }; diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 0acadbb..be7aa99 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d) @@ -36,6 +36,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -1306,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) // attribute inference. if (fd && fd.parent && fd.parent.isTemplateInstance) { - fd.functionSemantic3(); + functionSemantic3(fd); tf = fd.type.isTypeFunction(); } @@ -1665,12 +1666,12 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } else if (auto ed = sm.isEnumDeclaration()) { - ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg); + _foreach(null, ed.members, &pushIdentsDg); } return 0; } - ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg); + _foreach(sc, sds.members, &pushIdentsDg); auto cd = sds.isClassDeclaration(); if (cd && e.ident == Id.allMembers) { @@ -1684,7 +1685,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { auto cb = (*cd.baseclasses)[i].sym; assert(cb); - ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg); + _foreach(null, cb.members, &pushIdentsDg); if (cb.baseclasses.length) pushBaseMembersDg(cb); } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 2063a95..b1ca92d 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1,7 +1,7 @@ /** * Semantic analysis for D types. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d) @@ -35,11 +35,13 @@ import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; +import dmd.enumsem; import dmd.errors; import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -228,7 +230,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb Type t = s.getType(); // type symbol, type alias, or type tuple? uint errorsave = global.errors; - int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports; + SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports; Dsymbol sm = s.searchX(loc, sc, id, flags); if (sm) @@ -380,12 +382,12 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb * loc = location to print the error messages * sc = the scope where the symbol is located * id = the id of the symbol - * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` + * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports` * * Returns: * symbol found, NULL if not */ -private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags) +private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); Dsymbol s = dsym.toAlias(); @@ -430,6 +432,123 @@ private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject i return sm; } +/*************************************************** + * Determine if type t is copyable. + * Params: + * t = type to check + * Returns: + * true if we can copy it + */ +bool isCopyable(Type t) +{ + //printf("isCopyable() %s\n", t.toChars()); + if (auto ts = t.isTypeStruct()) + { + if (ts.sym.postblit && + ts.sym.postblit.storage_class & STC.disable) + return false; + if (ts.sym.hasCopyCtor) + { + // check if there is a matching overload of the copy constructor and whether it is disabled or not + // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575 + Dsymbol ctor = search_function(ts.sym, Id.ctor); + assert(ctor); + scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue + el.type = cast() ts; + Expressions* args = new Expressions(); + args.push(el); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet); + if (!f || f.storage_class & STC.disable) + return false; + } + } + return true; +} + +/************************************ + * Determine mutability of indirections in (ref) t. + * + * Returns: When the type has any mutable indirections, returns 0. + * When all indirections are immutable, returns 2. + * Otherwise, when the type has const/inout indirections, returns 1. + * + * Params: + * isref = if true, check `ref t`; otherwise, check just `t` + * t = the type that is being checked + */ +int mutabilityOfType(bool isref, Type t) +{ + if (isref) + { + if (t.mod & MODFlags.immutable_) + return 2; + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + return 0; + } + + t = t.baseElemOf(); + + if (!t.hasPointers() || t.mod & MODFlags.immutable_) + return 2; + + /* Accept immutable(T)[] and immutable(T)* as being strongly pure + */ + if (t.ty == Tarray || t.ty == Tpointer) + { + Type tn = t.nextOf().toBasetype(); + if (tn.mod & MODFlags.immutable_) + return 2; + if (tn.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + } + + /* The rest of this is too strict; fix later. + * For example, the only pointer members of a struct may be immutable, + * which would maintain strong purity. + * (Just like for dynamic arrays and pointers above.) + */ + if (t.mod & (MODFlags.const_ | MODFlags.wild)) + return 1; + + /* Should catch delegates and function pointers, and fold in their purity + */ + return 0; +} + +/******************************************** + * Set 'purity' field of 'typeFunction'. + * Do this lazily, as the parameter types might be forward referenced. + */ +extern(C++) void purityLevel(TypeFunction typeFunction) +{ + TypeFunction tf = typeFunction; + if (tf.purity != PURE.fwdref) + return; + + typeFunction.purity = PURE.const_; // assume strong until something weakens it + + /* Evaluate what kind of purity based on the modifiers for the parameters + */ + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + + if (fparam.storageClass & (STC.lazy_ | STC.out_)) + { + typeFunction.purity = PURE.weak; + break; + } + const pref = (fparam.storageClass & STC.ref_) != 0; + if (mutabilityOfType(pref, t) == 0) + typeFunction.purity = PURE.weak; + } + + tf.purity = typeFunction.purity; +} + /****************************************** * We've mistakenly parsed `t` as a type. * Redo `t` as an Expression only if there are no type modifiers. @@ -486,6 +605,683 @@ Expression typeToExpression(Type t) } } +/************************************* + * https://issues.dlang.org/show_bug.cgi?id=14488 + * Check if the inner most base type is complex or imaginary. + * Should only give alerts when set to emit transitional messages. + * Params: + * type = type to check + * loc = The source location. + * sc = scope of the type + */ +extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc) +{ + if (sc.isDeprecated()) + return false; + // Don't complain if we're inside a template constraint + // https://issues.dlang.org/show_bug.cgi?id=21831 + if (sc.flags & SCOPE.constraint) + return false; + + Type t = type.baseElemOf(); + while (t.ty == Tpointer || t.ty == Tarray) + t = t.nextOf().baseElemOf(); + + // Basetype is an opaque enum, nothing to check. + if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype) + return false; + + if (t.isimaginary() || t.iscomplex()) + { + if (sc.flags & SCOPE.Cfile) + return true; // complex/imaginary not deprecated in C code + Type rt; + switch (t.ty) + { + case Tcomplex32: + case Timaginary32: + rt = Type.tfloat32; + break; + + case Tcomplex64: + case Timaginary64: + rt = Type.tfloat64; + break; + + case Tcomplex80: + case Timaginary80: + rt = Type.tfloat80; + break; + + default: + assert(0); + } + // @@@DEPRECATED_2.117@@@ + // Deprecated in 2.097 - Can be made an error from 2.117. + // The deprecation period is longer than usual as `cfloat`, + // `cdouble`, and `creal` were quite widely used. + if (t.iscomplex()) + { + deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead", + type.toChars(), rt.toChars()); + return true; + } + else + { + deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead", + type.toChars(), rt.toChars()); + return true; + } + } + return false; +} + +/******************************** + * 'args' are being matched to function type 'tf' + * Determine match level. + * Params: + * tf = function type + * tthis = type of `this` pointer, null if not member function + * argumentList = arguments to function call + * flag = 1: performing a partial ordering match + * errorHelper = delegate to call for error messages + * sc = context + * Returns: + * MATCHxxxx + */ +extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null) +{ + //printf("TypeFunction::callMatch() %s\n", tf.toChars()); + MATCH match = MATCH.exact; // assume exact match + ubyte wildmatch = 0; + + if (tthis) + { + Type t = tthis; + if (t.toBasetype().ty == Tpointer) + t = t.toBasetype().nextOf(); // change struct* to struct + if (t.mod != tf.mod) + { + if (MODimplicitConv(t.mod, tf.mod)) + match = MATCH.constant; + else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_)) + { + match = MATCH.constant; + } + else + return MATCH.nomatch; + } + if (tf.isWild()) + { + if (t.isWild()) + wildmatch |= MODFlags.wild; + else if (t.isConst()) + wildmatch |= MODFlags.const_; + else if (t.isImmutable()) + wildmatch |= MODFlags.immutable_; + else + wildmatch |= MODFlags.mutable; + } + } + + ParameterList* parameterList = &tf.parameterList; + const nparams = parameterList.length; + if (argumentList.length > nparams) + { + if (parameterList.varargs == VarArg.none) + { + // suppress early exit if an error message is wanted, + // so we can check any matching args are valid + if (!errorHelper) + return MATCH.nomatch; + } + // too many args; no match + match = MATCH.convert; // match ... with a "conversion" match level + } + + // https://issues.dlang.org/show_bug.cgi?id=22997 + if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) + { + if (errorHelper) + { + OutBuffer buf; + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); + errorHelper(buf.peekChars()); + } + return MATCH.nomatch; + } + const(char)* failMessage; + const(char)** pMessage = errorHelper ? &failMessage : null; + auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage); + Expression[] args; + if (!resolvedArgs) + { + if (failMessage) + { + errorHelper(failMessage); + return MATCH.nomatch; + } + + // if no message was provided, it was because of overflow which will be diagnosed below + match = MATCH.nomatch; + args = argumentList.arguments ? (*argumentList.arguments)[] : null; + } + else + { + args = (*resolvedArgs)[]; + } + + foreach (u, p; *parameterList) + { + if (u >= args.length) + break; + + Expression arg = args[u]; + if (!arg) + continue; // default argument + + Type tprm = p.type; + Type targ = arg.type; + + if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) + { + const isRef = p.isReference(); + wildmatch |= targ.deduceWild(tprm, isRef); + } + } + if (wildmatch) + { + /* Calculate wild matching modifier + */ + if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) + wildmatch = MODFlags.const_; + else if (wildmatch & MODFlags.immutable_) + wildmatch = MODFlags.immutable_; + else if (wildmatch & MODFlags.wild) + wildmatch = MODFlags.wild; + else + { + assert(wildmatch & MODFlags.mutable); + wildmatch = MODFlags.mutable; + } + } + + foreach (u, p; *parameterList) + { + MATCH m; + + assert(p); + + // One or more arguments remain + if (u < args.length) + { + Expression arg = args[u]; + if (!arg) + continue; // default argument + m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage); + } + else if (p.defaultArg) + continue; + + /* prefer matching the element type rather than the array + * type when more arguments are present with T[]... + */ + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) + goto L1; + + //printf("\tm = %d\n", m); + if (m == MATCH.nomatch) // if no match + { + L1: + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param + { + auto trailingArgs = args[u .. $]; + if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) + return vmatch < match ? vmatch : match; + // Error message was already generated in `matchTypeSafeVarArgs` + if (failMessage) + errorHelper(failMessage); + return MATCH.nomatch; + } + if (pMessage && u >= args.length) + *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`", + u + 1, parameterToChars(p, tf, false)); + // If an error happened previously, `pMessage` was already filled + else if (pMessage && !*pMessage) + *pMessage = tf.getParamError(args[u], p); + + if (errorHelper) + errorHelper(*pMessage); + return MATCH.nomatch; + } + if (m < match) + match = m; // pick worst match + } + + if (errorHelper && !parameterList.varargs && args.length > nparams) + { + // all parameters had a match, but there are surplus args + errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length)); + return MATCH.nomatch; + } + //printf("match = %d\n", match); + return match; +} + +/** + * Used by `callMatch` to check if the copy constructor may be called to + * copy the argument + * + * This is done by seeing if a call to the copy constructor can be made: + * ``` + * typeof(tprm) __copytmp; + * copytmp.__copyCtor(arg); + * ``` + */ +private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, + Expression arg, Type tprm, Scope* sc, const(char)** pMessage) +{ + auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); + tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; + tmp.dsymbolSemantic(sc); + Expression ve = new VarExp(arg.loc, tmp); + Expression e = new DotIdExp(arg.loc, ve, Id.ctor); + e = new CallExp(arg.loc, e, arg); + //printf("e = %s\n", e.toChars()); + if (dmd.expressionsem.trySemantic(e, sc)) + return true; + + if (pMessage) + { + /* https://issues.dlang.org/show_bug.cgi?id=22202 + * + * If a function was deduced by semantic on the CallExp, + * it means that resolveFuncCall completed succesfully. + * Therefore, there exists a callable copy constructor, + * however, it cannot be called because scope constraints + * such as purity, safety or nogc. + */ + OutBuffer buf; + auto callExp = e.isCallExp(); + if (auto f = callExp.f) + { + char[] s; + if (!f.isPure && sc.func.setImpure()) + s ~= "pure "; + if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) + s ~= "@safe "; + if (!f.isNogc && sc.func.setGC(arg.loc, null)) + s ~= "nogc "; + if (f.isDisabled() && !f.isGenerated()) + { + /* https://issues.dlang.org/show_bug.cgi?id=24301 + * Copy constructor is explicitly disabled + */ + buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`", + f.type.toChars()); + } + else if (s) + { + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + } + else if (f.isGenerated() && f.isDisabled()) + { + /* https://issues.dlang.org/show_bug.cgi?id=23097 + * Compiler generated copy constructor failed. + */ + buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", + argStruct.toChars()); + } + else + { + /* Although a copy constructor may exist, no suitable match was found. + * i.e: `inout` constructor creates `const` object, not mutable. + * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. + */ + goto Lnocpctor; + } + } + else + { + Lnocpctor: + buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", + argStruct.toChars(), arg.type.toChars(), tprm.toChars()); + } + + *pMessage = buf.extractChars(); + } + return false; +} + +/** + * Match a single parameter to an argument. + * + * This function is called by `TypeFunction.callMatch` while iterating over + * the list of parameter. Here we check if `arg` is a match for `p`, + * which is mostly about checking if `arg.type` converts to `p`'s type + * and some check about value reference. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The parameter of `tf` being matched + * arg = Argument being passed (bound) to `p` + * wildmatch = Wild (`inout`) matching level, derived from the full argument list + * flag = A non-zero value means we're doing a partial ordering check + * (no value semantic check) + * sc = Scope we are in + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, + Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) +{ + //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); + MATCH m; + Type targ = arg.type; + Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; + + if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) + m = MATCH.convert; + else if (flag) + { + // for partial ordering, value is an irrelevant mockup, just look at the type + m = targ.implicitConvTo(tprm); + } + else + { + const isRef = p.isReference(); + StructDeclaration argStruct, prmStruct; + + // first look for a copy constructor + if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) + { + // if the argument and the parameter are of the same unqualified struct type + argStruct = (cast(TypeStruct)targ).sym; + prmStruct = (cast(TypeStruct)tprm).sym; + } + + // check if the copy constructor may be called to copy the argument + if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) + { + if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) + return MATCH.nomatch; + m = MATCH.exact; + } + else + { + import dmd.dcast : cimplicitConvTo; + m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); + } + } + + // Non-lvalues do not match ref or out parameters + if (p.isReference()) + { + // https://issues.dlang.org/show_bug.cgi?id=13783 + // Don't use toBasetype() to handle enum types. + Type ta = targ; + Type tp = tprm; + //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); + + if (m && !arg.isLvalue()) + { + if (p.storageClass & STC.out_) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + + if (arg.op == EXP.string_ && tp.ty == Tsarray) + { + if (ta.ty != Tsarray) + { + Type tn = tp.nextOf().castMod(ta.nextOf().mod); + dinteger_t dim = (cast(StringExp)arg).len; + ta = tn.sarrayOf(dim); + } + } + else if (arg.op == EXP.slice && tp.ty == Tsarray) + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + if (ta.ty != Tsarray) + { + Type tn = ta.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + } + else if (p.storageClass & STC.constscoperef) + { + // Allow converting a literal to an `in` which is `ref` + if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) + { + Type tn = tp.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + + // Need to make this a rvalue through a temporary + m = MATCH.convert; + } + else if (global.params.rvalueRefParam != FeatureState.enabled || + p.storageClass & STC.out_ || + !arg.type.isCopyable()) // can't copy to temp for ref parameter + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + else + { + /* in functionParameters() we'll convert this + * rvalue into a temporary + */ + m = MATCH.convert; + } + } + + /* If the match is not already perfect or if the arg + is not a lvalue then try the `alias this` chain + see https://issues.dlang.org/show_bug.cgi?id=15674 + and https://issues.dlang.org/show_bug.cgi?id=21905 + */ + if (ta != tp || !arg.isLvalue()) + { + Type firsttab = ta.toBasetype(); + while (1) + { + Type tab = ta.toBasetype(); + Type tat = tab.aliasthisOf(); + if (!tat || !tat.implicitConvTo(tprm)) + break; + if (tat == tab || tat == firsttab) + break; + ta = tat; + } + } + + /* A ref variable should work like a head-const reference. + * e.g. disallows: + * ref T <- an lvalue of const(T) argument + * ref T[dim] <- an lvalue of const(T[dim]) argument + */ + if (!ta.constConv(tp)) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + } + return m; +} + +// arguments get specially formatted +private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par) +{ + if (global.gag && !global.params.v.showGaggedErrors) + return null; + // show qualification when toChars() is the same but types are different + // https://issues.dlang.org/show_bug.cgi?id=19948 + // when comparing the type with strcmp, we need to drop the qualifier + bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && + strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; + auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); + OutBuffer buf; + // only mention rvalue if it's relevant + const rv = !arg.isLvalue() && par.isReference(); + buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", + rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, + parameterToChars(par, tf, qual)); + return buf.extractChars(); +} + +/** + * Match the remaining arguments `trailingArgs` with parameter `p`. + * + * Assume we already checked that `p` is the last parameter of `tf`, + * and we want to know whether the arguments would match `p`. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The last parameter of `tf` which is variadic + * trailingArgs = The remaining arguments that should match `p` + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, + Expression[] trailingArgs, const(char)** pMessage) +{ + Type tb = p.type.toBasetype(); + + switch (tb.ty) + { + case Tsarray: + TypeSArray tsa = cast(TypeSArray)tb; + dinteger_t sz = tsa.dim.toInteger(); + if (sz != trailingArgs.length) + { + if (pMessage) + *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", + sz, trailingArgs.length); + return MATCH.nomatch; + } + goto case Tarray; + case Tarray: + { + MATCH match = MATCH.exact; + TypeArray ta = cast(TypeArray)tb; + foreach (arg; trailingArgs) + { + MATCH m; + assert(arg); + + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = p.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + m = MATCH.exact; + else if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + m = arg.implicitConvTo(ta.next); + } + } + else + m = arg.implicitConvTo(ta.next); + + if (m == MATCH.nomatch) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + if (m < match) + match = m; + } + return match; + } + case Tclass: + // We leave it up to the actual constructor call to do the matching. + return MATCH.exact; + + default: + // We can have things as `foo(int[int] wat...)` but they only match + // with an associative array proper. + if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); + return MATCH.nomatch; + } +} + +/*************************************** + * Return !=0 if type has pointers that need to + * be scanned by the GC during a collection cycle. + */ +extern(C++) bool hasPointers(Type t) +{ + bool visitType(Type _) { return false; } + bool visitDArray(TypeDArray _) { return true; } + bool visitAArray(TypeAArray _) { return true; } + bool visitPointer(TypePointer _) { return true; } + bool visitDelegate(TypeDelegate _) { return true; } + bool visitClass(TypeClass _) { return true; } + bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); } + + /* Although null isn't dereferencable, treat it as a pointer type for + * attribute inference, generic code, etc. + */ + bool visitNull(TypeNull _) { return true; } + + bool visitSArray(TypeSArray t) + { + /* Don't want to do this, because: + * struct S { T* array[0]; } + * may be a variable length struct. + */ + //if (dim.toInteger() == 0) + // return false; + + if (t.next.ty == Tvoid) + { + // Arrays of void contain arbitrary data, which may include pointers + return true; + } + else + return t.next.hasPointers(); + } + + bool visitStruct(TypeStruct t) + { + StructDeclaration sym = t.sym; + + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + error(sym.loc, "no size because of forward references"); + + sym.determineTypeProperties(); + return sym.hasPointerField; + } + + + switch(t.ty) + { + default: return visitType(t); + case Tsarray: return visitSArray(t.isTypeSArray()); + case Tarray: return visitDArray(t.isTypeDArray()); + case Taarray: return visitAArray(t.isTypeAArray()); + case Tpointer: return visitPointer(t.isTypePointer()); + case Tdelegate: return visitDelegate(t.isTypeDelegate()); + case Tstruct: return visitStruct(t.isTypeStruct()); + case Tenum: return visitEnum(t.isTypeEnum()); + case Tclass: return visitClass(t.isTypeClass()); + case Tnull: return visitNull(t.isTypeNull()); + } +} + /****************************************** * Perform semantic analysis on a type. * Params: @@ -1130,9 +1926,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { e = inferType(e, fparam.type); + Scope* sc2 = sc.push(); + sc2.inDefaultArg = true; Initializer iz = new ExpInitializer(e.loc, e); - iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret); + iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret); e = iz.initializerToExpression(); + sc2.pop(); } if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820 { @@ -1155,7 +1954,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // default arg must be an lvalue if (isRefOrOut && !isAuto && - !(global.params.previewIn && (fparam.storageClass & STC.in_)) && + !(fparam.storageClass & STC.constscoperef) && global.params.rvalueRefParam != FeatureState.enabled) e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from"); @@ -1261,13 +2060,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (tf.linkage) { case LINK.cpp: - if (global.params.previewIn) + if (fparam.storageClass & STC.constscoperef) fparam.storageClass |= STC.ref_; break; case LINK.default_, LINK.d: break; default: - if (global.params.previewIn) + if (fparam.storageClass & STC.constscoperef) { .error(loc, "cannot use `in` parameters with `extern(%s)` functions", linkageToChars(tf.linkage)); @@ -1297,7 +2096,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members || tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype) { - if (global.params.previewIn && (fparam.storageClass & STC.in_)) + if (fparam.storageClass & STC.constscoperef) { .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`", fparam.toChars(), fparam.type.toChars()); @@ -1379,7 +2178,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) fparam.storageClass &= ~(STC.TYPECTOR); // -preview=in: add `ref` storage class to suited `in` params - if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_) + if ((fparam.storageClass & (STC.constscoperef | STC.ref_)) == STC.constscoperef) { auto ts = t.baseElemOf().isTypeStruct(); const isPOD = !ts || ts.sym.isPOD(); @@ -1795,11 +2594,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type visitTag(TypeTag mtype) { //printf("TypeTag.semantic() %s\n", mtype.toChars()); + Type returnType(Type t) + { + return t.deco ? t : t.merge(); + } + if (mtype.resolved) { /* struct S s, *p; */ - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* Find the current scope by skipping tag scopes. @@ -1872,20 +2676,20 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { mtype.id = Identifier.generateId("__tag"[]); declareTag(); - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* look for pre-existing declaration */ Dsymbol scopesym; - auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace); + auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace); if (!s || s.isModule()) { // no pre-existing declaration, so declare it if (mtype.tok == TOK.enum_ && !mtype.members) .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3 declareTag(); - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* A redeclaration only happens if both declarations are in @@ -1985,7 +2789,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) declareTag(); } } - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } switch (type.ty) @@ -2017,6 +2821,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } } +extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc) +{ + //printf("+trySemantic(%s) %d\n", toChars(), global.errors); + + // Needed to display any deprecations that were gagged + auto tcopy = type.syntaxCopy(); + + const errors = global.startGagging(); + Type t = typeSemantic(type, loc, sc); + if (global.endGagging(errors) || t.ty == Terror) // if any errors happened + { + t = null; + } + else + { + // If `typeSemantic` succeeded, there may have been deprecations that + // were gagged due the `startGagging` above. Run again to display + // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107 + if (global.gaggedWarnings > 0) + typeSemantic(tcopy, loc, sc); + } + //printf("-trySemantic(%s) %d\n", toChars(), global.errors); + return t; +} + /************************************ * If an identical type to `type` is in `type.stringtable`, return * the latter one. Otherwise, add it to `type.stringtable`. @@ -2092,6 +2921,29 @@ extern (C++) Type merge(Type type) return type; } +/************************************* + * This version does a merge even if the deco is already computed. + * Necessary for types that have a deco, but are not merged. + */ +extern(C++) Type merge2(Type type) +{ + //printf("merge2(%s)\n", toChars()); + Type t = type; + assert(t); + if (!t.deco) + return t.merge(); + + auto sv = Type.stringtable.lookup(t.deco, strlen(t.deco)); + if (sv && sv.value) + { + t = sv.value; + assert(t.deco); + } + else + assert(0); + return t; +} + /*************************************** * Calculate built-in properties which just the type is necessary. * @@ -2753,7 +3605,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type } Dsymbol scopesym; - Dsymbol s = sc.search(loc, mt.ident, &scopesym); + Dsymbol s = sc.search(loc, mt.ident, scopesym); /* * https://issues.dlang.org/show_bug.cgi?id=1170 * https://issues.dlang.org/show_bug.cgi?id=10739 @@ -2776,7 +3628,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type mixinTempl.dsymbolSemantic(sc); } sds.members.foreachDsymbol( s => semanticOnMixin(s) ); - s = sc.search(loc, mt.ident, &scopesym); + s = sc.search(loc, mt.ident, scopesym); } } @@ -2891,12 +3743,12 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type // f might be a unittest declaration which is incomplete when compiled // without -unittest. That causes a segfault in checkForwardRef, see // https://issues.dlang.org/show_bug.cgi?id=20626 - if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc)) + if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && checkForwardRef(f, loc)) goto Lerr; } if (auto f = isFuncAddress(mt.exp)) { - if (f.checkForwardRef(loc)) + if (checkForwardRef(f, loc)) goto Lerr; } @@ -3794,8 +4646,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return e; } - immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; - s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); + immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0; + s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports); L1: if (!s) { @@ -4074,8 +4926,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return e; } - int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; - s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); + SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all; + s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports); L1: if (!s) @@ -4680,6 +5532,117 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi } } +/* +If `type` resolves to a dsymbol, then that +dsymbol is returned. + +Params: + type = the type that is checked + sc = the scope where the type is used + +Returns: + The dsymbol to which the type resolve or `null` + if the type does resolve to any symbol (for example, + in the case of basic types). +*/ +extern(C++) Dsymbol toDsymbol(Type type, Scope* sc) +{ + Dsymbol visitType(Type _) { return null; } + Dsymbol visitStruct(TypeStruct type) { return type.sym; } + Dsymbol visitEnum(TypeEnum type) { return type.sym; } + Dsymbol visitClass(TypeClass type) { return type.sym; } + + Dsymbol visitTraits(TypeTraits type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Terror) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitMixin(TypeMixin type) + { + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t) + s = t.toDsymbol(sc); + else if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitIdentifier(TypeIdentifier type) + { + //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); + if (!sc) + return null; + + Type t; + Expression e; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tident) + s = t.toDsymbol(sc); + if (e) + s = getDsymbol(e); + + return s; + } + + Dsymbol visitInstance(TypeInstance type) + { + Type t; + Expression e; + Dsymbol s; + //printf("TypeInstance::semantic(%s)\n", toChars()); + resolve(type, type.loc, sc, e, t, s); + if (t && t.ty != Tinstance) + s = t.toDsymbol(sc); + return s; + } + + Dsymbol visitTypeof(TypeTypeof type) + { + //printf("TypeTypeof::toDsymbol('%s')\n", toChars()); + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + Dsymbol visitReturn(TypeReturn type) + { + Expression e; + Type t; + Dsymbol s; + resolve(type, type.loc, sc, e, t, s); + return s; + } + + switch(type.ty) + { + default: return visitType(type); + case Ttraits: return visitTraits(type.isTypeTraits()); + case Tmixin: return visitMixin(type.isTypeMixin()); + case Tident: return visitIdentifier(type.isTypeIdentifier()); + case Tinstance: return visitInstance(type.isTypeInstance()); + case Ttypeof: return visitTypeof(type.isTypeTypeof()); + case Treturn: return visitReturn(type.isTypeReturn()); + case Tstruct: return visitStruct(type.isTypeStruct()); + case Tenum: return visitEnum(type.isTypeEnum()); + case Tclass: return visitClass(type.isTypeClass()); + } +} /********************************************** * Extract complex type from core.stdc.config @@ -4723,7 +5686,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) return *pt; } - Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports); + Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports); if (!s) { error(loc, "`%s` not found in core.stdc.config", id.toChars()); @@ -4748,6 +5711,700 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) return *pt; } +/******************************* + * Covariant means that 'src' can substitute for 't', + * i.e. a pure function is a match for an impure type. + * Params: + * src = source type + * t = type 'src' is covariant with + * pstc = if not null, store STCxxxx which would make it covariant + * cppCovariant = true if extern(C++) function types should follow C++ covariant rules + * Returns: + * An enum value of either `Covariant.yes` or a reason it's not covariant. + */ +extern(C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) +{ + version (none) + { + printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars()); + printf("deco = %p, %p\n", src.deco, t.deco); + // printf("ty = %d\n", next.ty); + printf("mod = %x, %x\n", src.mod, t.mod); + } + if (pstc) + *pstc = 0; + StorageClass stc = 0; + + bool notcovariant = false; + + if (src.equals(t)) + return Covariant.yes; + + TypeFunction t1 = src.isTypeFunction(); + TypeFunction t2 = t.isTypeFunction(); + + if (!t1 || !t2) + goto Ldistinct; + + if (t1.parameterList.varargs != t2.parameterList.varargs) + goto Ldistinct; + + if (t1.parameterList.parameters && t2.parameterList.parameters) + { + if (t1.parameterList.length != t2.parameterList.length) + goto Ldistinct; + + foreach (i, fparam1; t1.parameterList) + { + Parameter fparam2 = t2.parameterList[i]; + Type tp1 = fparam1.type; + Type tp2 = fparam2.type; + + if (!tp1.equals(tp2)) + { + if (tp1.ty == tp2.ty) + { + if (auto tc1 = tp1.isTypeClass()) + { + if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) + goto Lcov; + } + else if (auto ts1 = tp1.isTypeStruct()) + { + if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) + goto Lcov; + } + else if (tp1.ty == Tpointer) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + else if (tp1.ty == Tarray) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + else if (tp1.ty == Tdelegate) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + } + goto Ldistinct; + } + Lcov: + notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); + + /* https://issues.dlang.org/show_bug.cgi?id=23135 + * extern(C++) mutable parameters are not covariant with const. + */ + if (t1.linkage == LINK.cpp && cppCovariant) + { + notcovariant |= tp1.isNaked() != tp2.isNaked(); + if (auto tpn1 = tp1.nextOf()) + notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); + } + } + } + else if (t1.parameterList.parameters != t2.parameterList.parameters) + { + if (t1.parameterList.length || t2.parameterList.length) + goto Ldistinct; + } + + // The argument lists match + if (notcovariant) + goto Lnotcovariant; + if (t1.linkage != t2.linkage) + goto Lnotcovariant; + + { + // Return types + Type t1n = t1.next; + Type t2n = t2.next; + + if (!t1n || !t2n) // happens with return type inference + goto Lnotcovariant; + + if (t1n.equals(t2n)) + goto Lcovariant; + if (t1n.ty == Tclass && t2n.ty == Tclass) + { + /* If same class type, but t2n is const, then it's + * covariant. Do this test first because it can work on + * forward references. + */ + if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) + goto Lcovariant; + + // If t1n is forward referenced: + ClassDeclaration cd = (cast(TypeClass)t1n).sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (!cd.isBaseInfoComplete()) + { + return Covariant.fwdref; + } + } + if (t1n.ty == Tstruct && t2n.ty == Tstruct) + { + if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) + goto Lcovariant; + } + else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) + { + if (t1.isref && t2.isref) + { + // Treat like pointers to t1n and t2n + if (t1n.constConv(t2n) < MATCH.constant) + goto Lnotcovariant; + } + goto Lcovariant; + } + else if (t1n.ty == Tnull) + { + // NULL is covariant with any pointer type, but not with any + // dynamic arrays, associative arrays or delegates. + // https://issues.dlang.org/show_bug.cgi?id=8589 + // https://issues.dlang.org/show_bug.cgi?id=19618 + Type t2bn = t2n.toBasetype(); + if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) + goto Lcovariant; + } + // bottom type is covariant to any type + else if (t1n.ty == Tnoreturn) + goto Lcovariant; + } + goto Lnotcovariant; + +Lcovariant: + if (t1.isref != t2.isref) + goto Lnotcovariant; + + if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) + { + StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; + StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; + if (t1.isreturn) + { + stc1 |= STC.return_; + if (!t1.isScopeQual) + stc1 |= STC.ref_; + } + if (t2.isreturn) + { + stc2 |= STC.return_; + if (!t2.isScopeQual) + stc2 |= STC.ref_; + } + if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) + goto Lnotcovariant; + } + + // We can subtract 'return ref' from 'this', but cannot add it + else if (t1.isreturn && !t2.isreturn) + goto Lnotcovariant; + + /* https://issues.dlang.org/show_bug.cgi?id=23135 + * extern(C++) mutable member functions are not covariant with const. + */ + if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) + goto Lnotcovariant; + + /* Can convert mutable to const + */ + if (!MODimplicitConv(t2.mod, t1.mod)) + { + version (none) + { + //stop attribute inference with const + // If adding 'const' will make it covariant + if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) + stc |= STC.const_; + else + goto Lnotcovariant; + } + else + { + goto Ldistinct; + } + } + + /* Can convert pure to impure, nothrow to throw, and nogc to gc + */ + if (!t1.purity && t2.purity) + stc |= STC.pure_; + + if (!t1.isnothrow && t2.isnothrow) + stc |= STC.nothrow_; + + if (!t1.isnogc && t2.isnogc) + stc |= STC.nogc; + + /* Can convert safe/trusted to system + */ + if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) + { + // Should we infer trusted or safe? Go with safe. + stc |= STC.safe; + } + + if (stc) + { + if (pstc) + *pstc = stc; + goto Lnotcovariant; + } + + //printf("\tcovaraint: 1\n"); + return Covariant.yes; + +Ldistinct: + //printf("\tcovaraint: 0\n"); + return Covariant.distinct; + +Lnotcovariant: + //printf("\tcovaraint: 2\n"); + return Covariant.no; +} + +/************************************ + * Take the specified storage class for p, + * and use the function signature to infer whether + * STC.scope_ and STC.return_ should be OR'd in. + * (This will not affect the name mangling.) + * Params: + * tf = TypeFunction to use to get the signature from + * tthis = type of `this` parameter, null if none + * p = parameter to this function + * outerVars = context variables p could escape into, if any + * indirect = is this for an indirect or virtual function call? + * Returns: + * storage class with STC.scope_ or STC.return_ OR'd in + */ +StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null, + bool indirect = false) +{ + //printf("parameterStorageClass(p: %s)\n", p.toChars()); + auto stc = p.storageClass; + + // When the preview switch is enable, `in` parameters are `scope` + if (stc & STC.constscoperef) + return stc | STC.scope_; + + if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure) + return stc; + + /* If haven't inferred the return type yet, can't infer storage classes + */ + if (!tf.nextOf() || !tf.isnothrow()) + return stc; + + tf.purityLevel(); + + static bool mayHavePointers(Type t) + { + if (auto ts = t.isTypeStruct()) + { + auto sym = ts.sym; + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + // struct is forward referenced, so "may have" pointers + return true; + } + return t.hasPointers(); + } + + // See if p can escape via any of the other parameters + if (tf.purity == PURE.weak) + { + /* + * Indirect calls may escape p through a nested context + * See: + * https://issues.dlang.org/show_bug.cgi?id=24212 + * https://issues.dlang.org/show_bug.cgi?id=24213 + */ + if (indirect) + return stc; + + // Check escaping through parameters + foreach (i, fparam; tf.parameterList) + { + Type t = fparam.type; + if (!t) + continue; + t = t.baseElemOf(); // punch thru static arrays + if (t.isMutable() && t.hasPointers()) + { + if (fparam.isReference() && fparam != p) + return stc; + + if (t.ty == Tdelegate) + return stc; // could escape thru delegate + + if (t.ty == Tclass) + return stc; + + /* if t is a pointer to mutable pointer + */ + if (auto tn = t.nextOf()) + { + if (tn.isMutable() && mayHavePointers(tn)) + return stc; // escape through pointers + } + } + } + + // Check escaping through `this` + if (tthis && tthis.isMutable()) + { + foreach (VarDeclaration v; isAggregate(tthis).fields) + { + if (v.hasPointers()) + return stc; + } + } + + // Check escaping through nested context + if (outerVars && tf.isMutable()) + { + foreach (VarDeclaration v; *outerVars) + { + if (v.hasPointers()) + return stc; + } + } + } + + // Check escaping through return value + Type tret = tf.nextOf().toBasetype(); + if (tf.isref || tret.hasPointers()) + { + return stc | STC.scope_ | STC.return_ | STC.returnScope; + } + else + return stc | STC.scope_; +} + +extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset) +{ + auto tc = tthis.isTypeClass(); + if (!tc) + return false; + + if (!t || t.ty != Tclass) + return false; + + ClassDeclaration cd = t.isTypeClass().sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete()) + tc.sym.dsymbolSemantic(null); + + if (tc.sym.isBaseOf(cd, poffset)) + return true; + + return false; +} + +/******************************** + * Convert to 'const'. + */ +extern(C++) Type constOf(Type type) +{ + //printf("Type::constOf() %p %s\n", type, type.toChars()); + if (type.mod == MODFlags.const_) + return type; + if (type.mcache && type.mcache.cto) + { + assert(type.mcache.cto.mod == MODFlags.const_); + return type.mcache.cto; + } + Type t = type.makeConst(); + t = t.merge(); + t.fixTo(type); + //printf("-Type::constOf() %p %s\n", t, t.toChars()); + return t; +} + +/******************************** + * Convert to 'immutable'. + */ +extern(C++) Type immutableOf(Type type) +{ + //printf("Type::immutableOf() %p %s\n", this, toChars()); + if (type.isImmutable()) + return type; + if (type.mcache && type.mcache.ito) + { + assert(type.mcache.ito.isImmutable()); + return type.mcache.ito; + } + Type t = type.makeImmutable(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p\n", t); + return t; +} + +/******************************** + * Make type mutable. + */ +extern(C++) Type mutableOf(Type type) +{ + //printf("Type::mutableOf() %p, %s\n", type, type.toChars()); + Type t = type; + if (type.isImmutable()) + { + type.getMcache(); + t = type.mcache.ito; // immutable => naked + assert(!t || (t.isMutable() && !t.isShared())); + } + else if (type.isConst()) + { + type.getMcache(); + if (type.isShared()) + { + if (type.isWild()) + t = type.mcache.swcto; // shared wild const -> shared + else + t = type.mcache.sto; // shared const => shared + } + else + { + if (type.isWild()) + t = type.mcache.wcto; // wild const -> naked + else + t = type.mcache.cto; // const => naked + } + assert(!t || t.isMutable()); + } + else if (type.isWild()) + { + type.getMcache(); + if (type.isShared()) + t = type.mcache.sto; // shared wild => shared + else + t = type.mcache.wto; // wild => naked + assert(!t || t.isMutable()); + } + if (!t) + { + t = type.makeMutable(); + t = t.merge(); + t.fixTo(type); + } + else + t = t.merge(); + assert(t.isMutable()); + return t; +} + +extern(C++) Type sharedOf(Type type) +{ + //printf("Type::sharedOf() %p, %s\n", type, type.toChars()); + if (type.mod == MODFlags.shared_) + return type; + if (type.mcache && type.mcache.sto) + { + assert(type.mcache.sto.mod == MODFlags.shared_); + return type.mcache.sto; + } + Type t = type.makeShared(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p\n", t); + return t; +} + +extern(C++) Type sharedConstOf(Type type) +{ + //printf("Type::sharedConstOf() %p, %s\n", type, type.toChars()); + if (type.mod == (MODFlags.shared_ | MODFlags.const_)) + return type; + if (type.mcache && type.mcache.scto) + { + assert(type.mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_)); + return type.mcache.scto; + } + Type t = type.makeSharedConst(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p\n", t); + return t; +} + +/******************************** + * Make type unshared. + * 0 => 0 + * const => const + * immutable => immutable + * shared => 0 + * shared const => const + * wild => wild + * wild const => wild const + * shared wild => wild + * shared wild const => wild const + */ +extern(C++) Type unSharedOf(Type type) +{ + //printf("Type::unSharedOf() %p, %s\n", type, type.toChars()); + Type t = type; + + if (type.isShared()) + { + type.getMcache(); + if (type.isWild()) + { + if (type.isConst()) + t = type.mcache.wcto; // shared wild const => wild const + else + t = type.mcache.wto; // shared wild => wild + } + else + { + if (type.isConst()) + t = type.mcache.cto; // shared const => const + else + t = type.mcache.sto; // shared => naked + } + assert(!t || !t.isShared()); + } + + if (!t) + { + t = type.nullAttributes(); + t.mod = type.mod & ~MODFlags.shared_; + t.ctype = type.ctype; + t = t.merge(); + t.fixTo(type); + } + else + t = t.merge(); + assert(!t.isShared()); + return t; +} + +/******************************** + * Convert to 'wild'. + */ +extern(C++) Type wildOf(Type type) +{ + //printf("Type::wildOf() %p %s\n", type, type.toChars()); + if (type.mod == MODFlags.wild) + return type; + if (type.mcache && type.mcache.wto) + { + assert(type.mcache.wto.mod == MODFlags.wild); + return type.mcache.wto; + } + Type t = type.makeWild(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +extern(C++) Type wildConstOf(Type type) +{ + //printf("Type::wildConstOf() %p %s\n", type, type.toChars()); + if (type.mod == MODFlags.wildconst) + return type; + if (type.mcache && type.mcache.wcto) + { + assert(type.mcache.wcto.mod == MODFlags.wildconst); + return type.mcache.wcto; + } + Type t = type.makeWildConst(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +extern(C++) Type sharedWildOf(Type type) +{ + //printf("Type::sharedWildOf() %p, %s\n", type, type.toChars()); + if (type.mod == (MODFlags.shared_ | MODFlags.wild)) + return type; + if (type.mcache && type.mcache.swto) + { + assert(type.mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild)); + return type.mcache.swto; + } + Type t = type.makeSharedWild(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +extern(C++) Type sharedWildConstOf(Type type) +{ + //printf("Type::sharedWildConstOf() %p, %s\n", type, type.toChars()); + if (type.mod == (MODFlags.shared_ | MODFlags.wildconst)) + return type; + if (type.mcache && type.mcache.swcto) + { + assert(type.mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst)); + return type.mcache.swcto; + } + Type t = type.makeSharedWildConst(); + t = t.merge(); + t.fixTo(type); + //printf("\t%p %s\n", t, t.toChars()); + return t; +} + +/************************************ + * Apply MODxxxx bits to existing type. + */ +extern(C++) Type castMod(Type type, MOD mod) +{ + Type t; + switch (mod) + { + case 0: + t = type.unSharedOf().mutableOf(); + break; + + case MODFlags.const_: + t = type.unSharedOf().constOf(); + break; + + case MODFlags.wild: + t = type.unSharedOf().wildOf(); + break; + + case MODFlags.wildconst: + t = type.unSharedOf().wildConstOf(); + break; + + case MODFlags.shared_: + t = type.mutableOf().sharedOf(); + break; + + case MODFlags.shared_ | MODFlags.const_: + t = type.sharedConstOf(); + break; + + case MODFlags.shared_ | MODFlags.wild: + t = type.sharedWildOf(); + break; + + case MODFlags.shared_ | MODFlags.wildconst: + t = type.sharedWildConstOf(); + break; + + case MODFlags.immutable_: + t = type.immutableOf(); + break; + + default: + assert(0); + } + return t; +} + /******************************* Private *****************************************/ private: diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index 485ca3f..6ae6df0 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -1,7 +1,7 @@ /** * Generate `TypeInfo` objects, which are needed for run-time introspection of types. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d) @@ -65,6 +65,7 @@ extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope fatal(); } + import dmd.typesem : merge2; Type t = torig.merge2(); // do this since not all Type's are merge'd bool needsCodegen = false; if (!t.vtinfo) diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h index 76f623a..fe80b94 100644 --- a/gcc/d/dmd/typinf.h +++ b/gcc/d/dmd/typinf.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index bb389b6..72d8036 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -1,7 +1,7 @@ /** * This module defines some utility functions for DMD. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d) @@ -299,3 +299,44 @@ bool parseDigits(T)(ref T val, const(char)[] p, const T max = T.max) assert(i.parseDigits("420", 500) && i == 420); assert(!i.parseDigits("420", 400)); } + +/** + * Cast a `ubyte[]` to an array of larger integers as if we are on a big endian architecture + * Params: + * data = array with big endian data + * size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[] + * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)` + */ +ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) +{ + ubyte[] impl(T)() + { + auto result = new T[](data.length / T.sizeof); + foreach (i; 0 .. result.length) + { + result[i] = 0; + foreach (j; 0 .. T.sizeof) + { + result[i] |= T(data[i * T.sizeof + j]) << ((T.sizeof - 1 - j) * 8); + } + } + return cast(ubyte[]) result; + } + switch (size) + { + case 1: return data.dup; + case 2: return impl!ushort; + case 4: return impl!uint; + case 8: return impl!ulong; + default: assert(0); + } +} + +unittest +{ + ubyte[] data = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22]; + assert(cast(ulong[]) arrayCastBigEndian(data, 8) == [0xAABBCCDDEEFF1122]); + assert(cast(uint[]) arrayCastBigEndian(data, 4) == [0xAABBCCDD, 0xEEFF1122]); + assert(cast(ushort[]) arrayCastBigEndian(data, 2) == [0xAABB, 0xCCDD, 0xEEFF, 0x1122]); + assert(cast(ubyte[]) arrayCastBigEndian(data, 1) == data); +} diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h index c268bc9..dd83fd6 100644 --- a/gcc/d/dmd/version.h +++ b/gcc/d/dmd/version.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d index 5722e10..abfd8ca 100644 --- a/gcc/d/dmd/visitor.d +++ b/gcc/d/dmd/visitor.d @@ -1,7 +1,7 @@ /** * Provides a visitor class visiting all AST nodes present in the compiler. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d, _visitor.d) diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 360784a..6e3d315 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * https://www.boost.org/LICENSE_1_0.txt @@ -195,6 +195,7 @@ class ThisExp; class SuperExp; class NullExp; class StringExp; +class InterpExp; class TupleExp; class ArrayLiteralExp; class AssocArrayLiteralExp; @@ -480,6 +481,7 @@ public: virtual void visit(TypeidExp *e) { visit((Expression *)e); } virtual void visit(TraitsExp *e) { visit((Expression *)e); } virtual void visit(StringExp *e) { visit((Expression *)e); } + virtual void visit(InterpExp *e) { visit((Expression *)e); } virtual void visit(NewExp *e) { visit((Expression *)e); } virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); } virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); } diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 7e63b0b..a050588 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -204,6 +204,22 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2) return compound_expr (lexpr, expr); } +/* Compile the function literal body. */ + +static void +build_lambda_tree (FuncLiteralDeclaration *fld, Type *type = NULL) +{ + /* This check is for lambda's, remove `vthis' as function isn't nested. */ + if (fld->tok == TOK::reserved && (type == NULL || type->ty == TY::Tpointer)) + { + fld->tok = TOK::function_; + fld->vthis = NULL; + } + + /* Compile the function literal body. */ + build_decl_tree (fld); +} + /* Implements the visitor interface to build the GCC trees of all Expression AST classes emitted from the D Front-end. All visit methods accept one parameter E, which holds the frontend AST @@ -1162,7 +1178,7 @@ public: { libcall = LIBCALL_AAGETY; ptr = build_address (build_expr (e->e1)); - tinfo = build_typeinfo (e, tb1->unSharedOf ()->mutableOf ()); + tinfo = build_typeinfo (e, mutableOf (unSharedOf (tb1))); } else { @@ -2012,17 +2028,8 @@ public: void visit (FuncExp *e) final override { - Type *ftype = e->type->toBasetype (); - - /* This check is for lambda's, remove `vthis' as function isn't nested. */ - if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer) - { - e->fd->tok = TOK::function_; - e->fd->vthis = NULL; - } - - /* Compile the function literal body. */ - build_decl_tree (e->fd); + /* Compile the declaration. */ + build_lambda_tree (e->fd, e->type->toBasetype ()); /* If nested, this will be a trampoline. */ if (e->fd->isNested ()) @@ -2071,6 +2078,10 @@ public: if (e->var->isFuncDeclaration ()) result = maybe_reject_intrinsic (result); + /* Emit lambdas, same as is done in FuncExp. */ + if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ()) + build_lambda_tree (fld); + if (declaration_reference_p (e->var)) gcc_assert (POINTER_TYPE_P (TREE_TYPE (result))); else @@ -2105,19 +2116,9 @@ public: return; } - /* This check is same as is done in FuncExp for lambdas. */ - FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration (); - if (fld != NULL) - { - if (fld->tok == TOK::reserved) - { - fld->tok = TOK::function_; - fld->vthis = NULL; - } - - /* Compiler the function literal body. */ - build_decl_tree (fld); - } + /* Emit lambdas, same as is done in FuncExp. */ + if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ()) + build_lambda_tree (fld); if (this->constp_) { @@ -2169,7 +2170,7 @@ public: { /* Generate a slice for non-zero initialized aggregates, otherwise create an empty array. */ - gcc_assert (e->type == Type::tvoid->arrayOf ()->constOf ()); + gcc_assert (e->type == constOf (Type::tvoid->arrayOf ())); tree type = build_ctype (e->type); tree length = size_int (sd->dsym->structsize); @@ -2494,17 +2495,18 @@ public: for (size_t i = 0; i < e->len; i++) { - tree value = build_integer_cst (e->getCodeUnit (i), etype); + tree value = build_integer_cst (e->getIndex (i), etype); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } tree ctor = build_constructor (type, elms); TREE_CONSTANT (ctor) = 1; this->result_ = ctor; + return; } else { - /* Copy the string contents to a null terminated string. */ + /* Copy the string contents to a null terminated STRING_CST. */ dinteger_t length = (e->len * e->sz); char *string = XALLOCAVEC (char, length + e->sz); memset (string, 0, length + e->sz); @@ -2513,7 +2515,18 @@ public: /* String value and type includes the null terminator. */ tree value = build_string (length + e->sz, string); - TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); + if (e->sz <= 4) + TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); + else + { + /* Hexadecimal literal strings with an 8-byte character type are + just an alternative way to store an array of `ulong'. + Treat it as if it were a `uint[]' array instead. */ + dinteger_t resize = e->sz / 4; + TREE_TYPE (value) = make_array_type (Type::tuns32, + (length * resize) + resize); + } + value = build_address (value); if (tb->ty == TY::Tarray) @@ -2696,17 +2709,16 @@ public: void visit (AssocArrayLiteralExp *e) final override { - if (e->lowering != NULL) + if (this->constp_ && e->lowering != NULL) { /* When an associative array literal gets lowered, it's converted into a struct literal suitable for static initialization. */ - gcc_assert (this->constp_); this->result_ = build_expr (e->lowering, this->constp_, true); return ; } /* Want the mutable type for typeinfo reference. */ - Type *tb = e->type->toBasetype ()->mutableOf (); + Type *tb = mutableOf (e->type->toBasetype ()); /* Handle empty assoc array literals. */ TypeAArray *ta = tb->isTypeAArray (); diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi index e6a8a90..fe1c625 100644 --- a/gcc/d/gdc.texi +++ b/gcc/d/gdc.texi @@ -740,8 +740,10 @@ arguments like @code{va_start}. @opindex fignore-unknown-pragmas @opindex fno-ignore-unknown-pragmas -@item -fignore-unknown-pragmas -Turns off errors for unsupported pragmas. +@item -fno-ignore-unknown-pragmas +Do not recognize unsupported pragmas. Any @code{pragma()} encountered that is +not part of the D language will result in an error. This option is now +deprecated and will be removed in a future release. @opindex fmax-errors @item -fmax-errors=@var{n} diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index 16b6733..58b15be 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -84,6 +84,7 @@ struct module_info vec <tree, va_gc> *sharedctors; vec <tree, va_gc> *shareddtors; vec <tree, va_gc> *sharedctorgates; + vec <tree, va_gc> *standalonectors; vec <tree, va_gc> *unitTests; }; @@ -763,6 +764,11 @@ build_module_tree (Module *decl) tm->sdtor = build_funcs_gates_fn (get_identifier ("*__modtestdtor"), mitest.dtors, NULL); + if (mi.standalonectors) + tm->sictor + = build_funcs_gates_fn (get_identifier ("*__modtestsharedictor"), + mi.standalonectors, NULL); + if (mitest.sharedctors || mitest.sharedctorgates) tm->ssharedctor = build_funcs_gates_fn (get_identifier ("*__modtestsharedctor"), @@ -793,6 +799,11 @@ build_module_tree (Module *decl) decl->sdtor = build_funcs_gates_fn (get_identifier ("*__moddtor"), mi.dtors, NULL); + if (mi.standalonectors) + decl->sictor + = build_funcs_gates_fn (get_identifier ("*__modsharedictor"), + mi.standalonectors, NULL); + if (mi.sharedctors || mi.sharedctorgates) decl->ssharedctor = build_funcs_gates_fn (get_identifier ("*__modsharedctor"), @@ -858,8 +869,15 @@ register_module_decl (Declaration *d) /* If a static constructor, push into the current ModuleInfo. Checks for `shared' first because it derives from the non-shared constructor type in the front-end. */ - if (fd->isSharedStaticCtorDeclaration ()) - vec_safe_push (minfo->sharedctors, decl); + if (SharedStaticCtorDeclaration *sctor + = fd->isSharedStaticCtorDeclaration ()) + { + /* The `shared' static constructor was marked `@standalone'. */ + if (sctor->standalone) + vec_safe_push (minfo->standalonectors, decl); + else + vec_safe_push (minfo->sharedctors, decl); + } else if (fd->isStaticCtorDeclaration ()) vec_safe_push (minfo->ctors, decl); diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc index 8a47ac1..9d11e7e 100644 --- a/gcc/d/runtime.cc +++ b/gcc/d/runtime.cc @@ -150,11 +150,11 @@ get_libcall_type (d_libcall_type type) break; case LCT_CONST_TYPEINFO: - libcall_types[type] = Type::dtypeinfo->type->constOf (); + libcall_types[type] = constOf (Type::dtypeinfo->type); break; case LCT_CONST_CLASSINFO: - libcall_types[type] = Type::typeinfoclass->type->constOf (); + libcall_types[type] = constOf (Type::typeinfoclass->type); break; case LCT_ARRAY_VOID: @@ -202,7 +202,7 @@ get_libcall_type (d_libcall_type type) break; case LCT_IMMUTABLE_CHARPTR: - libcall_types[type] = Type::tchar->pointerTo ()->immutableOf (); + libcall_types[type] = immutableOf (Type::tchar->pointerTo ()); break; default: diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index f67113141..3dbda55 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "dmd/aggregate.h" +#include "dmd/dsymbol.h" #include "dmd/enum.h" #include "dmd/errors.h" #include "dmd/expression.h" @@ -205,7 +206,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL) /* Create object module in order to complete the semantic. */ if (!object_module->_scope) - object_module->importAll (NULL); + importAll (object_module, NULL); /* Object class doesn't exist, create a stub one that will cause an error if used. */ @@ -258,7 +259,9 @@ create_tinfo_types (Module *mod) array_type_node, array_type_node, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node, - array_type_node, ptr_type_node, ptr_type_node, NULL); + array_type_node, ptr_type_node, ptr_type_node, + d_uint_type, d_uint_type, d_uint_type, d_uint_type, + NULL); object_module = mod; } @@ -574,8 +577,8 @@ public: void visit (TypeInfoConstDeclaration *d) final override { - Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + Type *tm = mutableOf (d->tinfo); + tm = merge2 (tm); /* The vtable for TypeInfo_Const. */ this->layout_base (Type::typeinfoconst); @@ -591,8 +594,8 @@ public: void visit (TypeInfoInvariantDeclaration *d) final override { - Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + Type *tm = mutableOf (d->tinfo); + tm = merge2 (tm); /* The vtable for TypeInfo_Invariant. */ this->layout_base (Type::typeinfoinvariant); @@ -608,8 +611,8 @@ public: void visit (TypeInfoSharedDeclaration *d) final override { - Type *tm = d->tinfo->unSharedOf (); - tm = tm->merge2 (); + Type *tm = unSharedOf (d->tinfo); + tm = merge2 (tm); /* The vtable for TypeInfo_Shared. */ this->layout_base (Type::typeinfoshared); @@ -625,8 +628,8 @@ public: void visit (TypeInfoWildDeclaration *d) final override { - Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + Type *tm = mutableOf (d->tinfo); + tm = merge2 (tm); /* The vtable for TypeInfo_Inout. */ this->layout_base (Type::typeinfowild); @@ -813,6 +816,7 @@ public: void *deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; + ulong[2] nameSig immutable(void)* m_RTInfo; Information relating to interfaces, and their vtables are laid out @@ -938,6 +942,12 @@ public: this->layout_field (size_one_node); else this->layout_field (null_pointer_node); + + /* uint[4] nameSig; */ + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); } else { @@ -983,6 +993,12 @@ public: this->layout_field (build_expr (cd->getRTInfo, true)); else this->layout_field (null_pointer_node); + + /* uint[4] nameSig; */ + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); } /* Put out array of Interfaces. */ @@ -1083,7 +1099,7 @@ public: /* StructFlags m_flags; */ int m_flags = StructFlags::none; - if (ti->hasPointers ()) + if (hasPointers (ti)) m_flags |= StructFlags::hasPointers; this->layout_field (build_integer_cst (m_flags, d_uint_type)); @@ -1535,7 +1551,7 @@ create_typeinfo (Type *type, Module *mod, bool generate) create_frontend_tinfo_types (); /* Do this since not all Type's are merged. */ - Type *t = type->merge2 (); + Type *t = merge2 (type); Identifier *ident; if (!t->vtinfo) diff --git a/gcc/d/types.cc b/gcc/d/types.cc index ca574fd..4e14b15 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -1329,7 +1329,7 @@ build_ctype (Type *t) t->accept (&v); else { - Type *tb = t->castMod (0); + Type *tb = castMod (t, 0); if (!tb->ctype) tb->accept (&v); t->ctype = insert_type_modifiers (tb->ctype, t->mod); diff --git a/gcc/doc/avr-mmcu.texi b/gcc/doc/avr-mmcu.texi index 1a2c688..f38a0e0 100644 --- a/gcc/doc/avr-mmcu.texi +++ b/gcc/doc/avr-mmcu.texi @@ -38,7 +38,7 @@ @item @anchor{avr5}avr5 ``Enhanced'' devices with 16@tie{}KiB up to 64@tie{}KiB of program memory. -@*@var{mcu}@tie{}= @code{atmega16}, @code{atmega16a}, @code{atmega16hva}, @code{atmega16hva2}, @code{atmega16hvb}, @code{atmega16hvbrevb}, @code{atmega16m1}, @code{atmega16u4}, @code{atmega161}, @code{atmega162}, @code{atmega163}, @code{atmega164a}, @code{atmega164p}, @code{atmega164pa}, @code{atmega165}, @code{atmega165a}, @code{atmega165p}, @code{atmega165pa}, @code{atmega168}, @code{atmega168a}, @code{atmega168p}, @code{atmega168pa}, @code{atmega168pb}, @code{atmega169}, @code{atmega169a}, @code{atmega169p}, @code{atmega169pa}, @code{atmega32}, @code{atmega32a}, @code{atmega32c1}, @code{atmega32hvb}, @code{atmega32hvbrevb}, @code{atmega32m1}, @code{atmega32u4}, @code{atmega32u6}, @code{atmega323}, @code{atmega324a}, @code{atmega324p}, @code{atmega324pa}, @code{atmega324pb}, @code{atmega325}, @code{atmega325a}, @code{atmega325p}, @code{atmega325pa}, @code{atmega328}, @code{atmega328p}, @code{atmega328pb}, @code{atmega329}, @code{atmega329a}, @code{atmega329p}, @code{atmega329pa}, @code{atmega3250}, @code{atmega3250a}, @code{atmega3250p}, @code{atmega3250pa}, @code{atmega3290}, @code{atmega3290a}, @code{atmega3290p}, @code{atmega3290pa}, @code{atmega406}, @code{atmega64}, @code{atmega64a}, @code{atmega64c1}, @code{atmega64hve}, @code{atmega64hve2}, @code{atmega64m1}, @code{atmega64rfr2}, @code{atmega640}, @code{atmega644}, @code{atmega644a}, @code{atmega644p}, @code{atmega644pa}, @code{atmega644rfr2}, @code{atmega645}, @code{atmega645a}, @code{atmega645p}, @code{atmega649}, @code{atmega649a}, @code{atmega649p}, @code{atmega6450}, @code{atmega6450a}, @code{atmega6450p}, @code{atmega6490}, @code{atmega6490a}, @code{atmega6490p}, @code{ata5795}, @code{ata5790}, @code{ata5790n}, @code{ata5791}, @code{ata6613c}, @code{ata6614q}, @code{ata5782}, @code{ata5831}, @code{ata8210}, @code{ata8510}, @code{ata5702m322}, @code{at90pwm161}, @code{at90pwm216}, @code{at90pwm316}, @code{at90can32}, @code{at90can64}, @code{at90scr100}, @code{at90usb646}, @code{at90usb647}, @code{at94k}, @code{m3000}. +@*@var{mcu}@tie{}= @code{atmega16}, @code{atmega16a}, @code{atmega16hva}, @code{atmega16hva2}, @code{atmega16hvb}, @code{atmega16hvbrevb}, @code{atmega16m1}, @code{atmega16u4}, @code{atmega161}, @code{atmega162}, @code{atmega163}, @code{atmega164a}, @code{atmega164p}, @code{atmega164pa}, @code{atmega165}, @code{atmega165a}, @code{atmega165p}, @code{atmega165pa}, @code{atmega168}, @code{atmega168a}, @code{atmega168p}, @code{atmega168pa}, @code{atmega168pb}, @code{atmega169}, @code{atmega169a}, @code{atmega169p}, @code{atmega169pa}, @code{atmega32}, @code{atmega32a}, @code{atmega32c1}, @code{atmega32hvb}, @code{atmega32hvbrevb}, @code{atmega32m1}, @code{atmega32u4}, @code{atmega32u6}, @code{atmega323}, @code{atmega324a}, @code{atmega324p}, @code{atmega324pa}, @code{atmega324pb}, @code{atmega325}, @code{atmega325a}, @code{atmega325p}, @code{atmega325pa}, @code{atmega328}, @code{atmega328p}, @code{atmega328pb}, @code{atmega329}, @code{atmega329a}, @code{atmega329p}, @code{atmega329pa}, @code{atmega3250}, @code{atmega3250a}, @code{atmega3250p}, @code{atmega3250pa}, @code{atmega3290}, @code{atmega3290a}, @code{atmega3290p}, @code{atmega3290pa}, @code{atmega406}, @code{atmega64}, @code{atmega64a}, @code{atmega64c1}, @code{atmega64hve}, @code{atmega64hve2}, @code{atmega64m1}, @code{atmega64rfr2}, @code{atmega640}, @code{atmega644}, @code{atmega644a}, @code{atmega644p}, @code{atmega644pa}, @code{atmega644rfr2}, @code{atmega645}, @code{atmega645a}, @code{atmega645p}, @code{atmega649}, @code{atmega649a}, @code{atmega649p}, @code{atmega6450}, @code{atmega6450a}, @code{atmega6450p}, @code{atmega6490}, @code{atmega6490a}, @code{atmega6490p}, @code{ata5795}, @code{ata5790}, @code{ata5790n}, @code{ata5791}, @code{ata6613c}, @code{ata6614q}, @code{ata5782}, @code{ata5831}, @code{ata8210}, @code{ata8510}, @code{ata5787}, @code{ata5835}, @code{ata5700m322}, @code{ata5702m322}, @code{at90pwm161}, @code{at90pwm216}, @code{at90pwm316}, @code{at90can32}, @code{at90can64}, @code{at90scr100}, @code{at90usb646}, @code{at90usb647}, @code{at94k}, @code{m3000}. @item @anchor{avr51}avr51 ``Enhanced'' devices with 128@tie{}KiB of program memory. @@ -50,11 +50,11 @@ @item @anchor{avrxmega2}avrxmega2 ``XMEGA'' devices with more than 8@tie{}KiB and up to 64@tie{}KiB of program memory. -@*@var{mcu}@tie{}= @code{atxmega8e5}, @code{atxmega16a4}, @code{atxmega16a4u}, @code{atxmega16c4}, @code{atxmega16d4}, @code{atxmega16e5}, @code{atxmega32a4}, @code{atxmega32a4u}, @code{atxmega32c3}, @code{atxmega32c4}, @code{atxmega32d3}, @code{atxmega32d4}, @code{atxmega32e5}, @code{avr64da28}, @code{avr64da32}, @code{avr64da48}, @code{avr64da64}, @code{avr64db28}, @code{avr64db32}, @code{avr64db48}, @code{avr64db64}, @code{avr64dd14}, @code{avr64dd20}, @code{avr64dd28}, @code{avr64dd32}, @code{avr64ea28}, @code{avr64ea32}, @code{avr64ea48}. +@*@var{mcu}@tie{}= @code{atxmega8e5}, @code{atxmega16a4}, @code{atxmega16a4u}, @code{atxmega16c4}, @code{atxmega16d4}, @code{atxmega16e5}, @code{atxmega32a4}, @code{atxmega32a4u}, @code{atxmega32c3}, @code{atxmega32c4}, @code{atxmega32d3}, @code{atxmega32d4}, @code{atxmega32e5}, @code{avr64da28}, @code{avr64da32}, @code{avr64da48}, @code{avr64da64}, @code{avr64db28}, @code{avr64db32}, @code{avr64db48}, @code{avr64db64}, @code{avr64dd14}, @code{avr64dd20}, @code{avr64dd28}, @code{avr64dd32}, @code{avr64du28}, @code{avr64du32}, @code{avr64ea28}, @code{avr64ea32}, @code{avr64ea48}. @item @anchor{avrxmega3}avrxmega3 ``XMEGA'' devices with up to 64@tie{}KiB of combined program memory and RAM, and with program memory visible in the RAM address space. -@*@var{mcu}@tie{}= @code{attiny202}, @code{attiny204}, @code{attiny212}, @code{attiny214}, @code{attiny402}, @code{attiny404}, @code{attiny406}, @code{attiny412}, @code{attiny414}, @code{attiny416}, @code{attiny417}, @code{attiny424}, @code{attiny426}, @code{attiny427}, @code{attiny804}, @code{attiny806}, @code{attiny807}, @code{attiny814}, @code{attiny816}, @code{attiny817}, @code{attiny824}, @code{attiny826}, @code{attiny827}, @code{attiny1604}, @code{attiny1606}, @code{attiny1607}, @code{attiny1614}, @code{attiny1616}, @code{attiny1617}, @code{attiny1624}, @code{attiny1626}, @code{attiny1627}, @code{attiny3214}, @code{attiny3216}, @code{attiny3217}, @code{attiny3224}, @code{attiny3226}, @code{attiny3227}, @code{atmega808}, @code{atmega809}, @code{atmega1608}, @code{atmega1609}, @code{atmega3208}, @code{atmega3209}, @code{atmega4808}, @code{atmega4809}, @code{avr16dd14}, @code{avr16dd20}, @code{avr16dd28}, @code{avr16dd32}, @code{avr16ea28}, @code{avr16ea32}, @code{avr16ea48}, @code{avr16eb14}, @code{avr16eb20}, @code{avr16eb28}, @code{avr16eb32}, @code{avr32da28}, @code{avr32da32}, @code{avr32da48}, @code{avr32db28}, @code{avr32db32}, @code{avr32db48}, @code{avr32dd14}, @code{avr32dd20}, @code{avr32dd28}, @code{avr32dd32}, @code{avr32ea28}, @code{avr32ea32}, @code{avr32ea48}. +@*@var{mcu}@tie{}= @code{attiny202}, @code{attiny204}, @code{attiny212}, @code{attiny214}, @code{attiny402}, @code{attiny404}, @code{attiny406}, @code{attiny412}, @code{attiny414}, @code{attiny416}, @code{attiny416auto}, @code{attiny417}, @code{attiny424}, @code{attiny426}, @code{attiny427}, @code{attiny804}, @code{attiny806}, @code{attiny807}, @code{attiny814}, @code{attiny816}, @code{attiny817}, @code{attiny824}, @code{attiny826}, @code{attiny827}, @code{attiny1604}, @code{attiny1606}, @code{attiny1607}, @code{attiny1614}, @code{attiny1616}, @code{attiny1617}, @code{attiny1624}, @code{attiny1626}, @code{attiny1627}, @code{attiny3214}, @code{attiny3216}, @code{attiny3217}, @code{attiny3224}, @code{attiny3226}, @code{attiny3227}, @code{atmega808}, @code{atmega809}, @code{atmega1608}, @code{atmega1609}, @code{atmega3208}, @code{atmega3209}, @code{atmega4808}, @code{atmega4809}, @code{avr16dd14}, @code{avr16dd20}, @code{avr16dd28}, @code{avr16dd32}, @code{avr16ea28}, @code{avr16ea32}, @code{avr16ea48}, @code{avr16eb14}, @code{avr16eb20}, @code{avr16eb28}, @code{avr16eb32}, @code{avr32da28}, @code{avr32da32}, @code{avr32da48}, @code{avr32db28}, @code{avr32db32}, @code{avr32db48}, @code{avr32dd14}, @code{avr32dd20}, @code{avr32dd28}, @code{avr32dd32}, @code{avr32ea28}, @code{avr32ea32}, @code{avr32ea48}. @item @anchor{avrxmega4}avrxmega4 ``XMEGA'' devices with more than 64@tie{}KiB and up to 128@tie{}KiB of program memory. diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index f0d02c9..2b8ba19 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8960,7 +8960,7 @@ This attribute may only be applied to integral types in C, to introduce hardened boolean types. It turns the integral type into a boolean-like type with the same size and precision, that uses the specified values as representations for @code{false} and @code{true}. Underneath, it is -actually an enumerate type, but its observable behavior is like that of +actually an enumerated type, but its observable behavior is like that of @code{_Bool}, except for the strict internal representations, verified by runtime checks. @@ -12799,7 +12799,7 @@ situations. @deftypefn {Built-in Function} {void *} __builtin_stack_address () This function returns the stack pointer register, offset by -@code{STACK_POINTER_OFFSET}. +@code{STACK_ADDRESS_OFFSET} if that's defined. Conceptually, the returned address returned by this built-in function is the boundary between the stack area allocated for use by its caller, and diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 819a75d..71339b8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3204,7 +3204,9 @@ the language standard, so @option{-fconcepts} defaults to on. Some constructs that were allowed by the earlier C++ Extensions for Concepts Technical Specification, ISO 19217 (2015), but didn't make it into the standard, can additionally be enabled by -@option{-fconcepts-ts}. +@option{-fconcepts-ts}. The option @option{-fconcepts-ts} was deprecated +in GCC 14 and may be removed in GCC 15; users are expected to convert +their code to C++20 concepts. @opindex fconstexpr-depth @item -fconstexpr-depth=@var{n} @@ -3916,6 +3918,20 @@ where @code{std::minmax} returns @code{std::pair<const int&, const int&>}, and both references dangle after the end of the full expression that contains the call to @code{std::minmax}. +The warning does not warn for @code{std::span}-like classes. We consider +classes of the form: + +@smallexample +template<typename T> +struct Span @{ + T* data_; + std::size len_; +@}; +@end smallexample + +as @code{std::span}-like; that is, the class is a non-union class +that has a pointer data member and a trivial destructor. + This warning is enabled by @option{-Wall}. @opindex Wdelete-non-virtual-dtor @@ -30246,6 +30262,14 @@ Supported extension are listed below: @tab 1.0 @tab Integer conditional operations extension. +@item za64rs +@tab 1.0 +@tab Reservation set size of 64 bytes. + +@item za128rs +@tab 1.0 +@tab Reservation set size of 128 bytes. + @item zawrs @tab 1.0 @tab Wait-on-reservation-set extension. @@ -30354,6 +30378,26 @@ Supported extension are listed below: @tab 1.0 @tab Cache-block prefetch extension. +@item zic64b +@tab 1.0 +@tab Cache block size isf 64 bytes. + +@item ziccamoa +@tab 1.0 +@tab Main memory supports all atomics in A. + +@item ziccif +@tab 1.0 +@tab Main memory supports instruction fetch with atomicity requirement. + +@item zicclsm +@tab 1.0 +@tab Main memory supports misaligned loads/stores. + +@item ziccrse +@tab 1.0 +@tab Main memory supports forward progress on LR/SC sequences. + @item zicntr @tab 2.0 @tab Standard extension for base counters and timers. @@ -30663,14 +30707,16 @@ by particular CPU name. Permissible values for this option are: @samp{sifive-e20}, @samp{sifive-e21}, @samp{sifive-e24}, @samp{sifive-e31}, @samp{sifive-e34}, @samp{sifive-e76}, @samp{sifive-s21}, @samp{sifive-s51}, @samp{sifive-s54}, @samp{sifive-s76}, -@samp{sifive-u54}, @samp{sifive-u74}, and @samp{sifive-x280}. +@samp{sifive-u54}, @samp{sifive-u74}, @samp{sifive-x280}, @samp{sifive-xp450}, +@samp{sifive-x670}. @opindex mtune @item -mtune=@var{processor-string} Optimize the output for the given processor, specified by microarchitecture or particular CPU name. Permissible values for this option are: @samp{rocket}, @samp{sifive-3-series}, @samp{sifive-5-series}, @samp{sifive-7-series}, -@samp{thead-c906}, @samp{size}, and all valid options for @option{-mcpu=}. +@samp{thead-c906}, @samp{size}, @samp{sifive-p400-series}, +@samp{sifive-p600-series}, and all valid options for @option{-mcpu=}. When @option{-mtune=} is not specified, use the setting from @option{-mcpu}, the default is @samp{rocket} if both are not specified. diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 47a87d6..b0c6192 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -4275,6 +4275,10 @@ require non-@code{VOIDmode} immediate operands). 128-bit integer constant where both the high and low 64-bit word satisfy the @code{e} constraint. +@item Ws +A symbolic reference or label reference. +You can use the @code{%p} modifier to print the raw symbol. + @item Z 32-bit unsigned integer constant, or a symbolic reference known to fit that range (for immediate operands in zero-extending x86-64 diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 69ae63c..c8b8b12 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3456,6 +3456,35 @@ or type, otherwise return false. The default implementation always returns true. @end deftypefn +@defmac STACK_ADDRESS_OFFSET +Offset from the stack pointer register to the boundary address between +the stack area claimed by an active function, and stack ranges that +could get clobbered if it called another function. It should NOT +encompass any stack red zone, that is used in leaf functions. + +This value is added to the stack pointer register to compute the address +returned by @code{__builtin_stack_address}, and this is its only use. +If this macro is not defined, no offset is added. Defining it like +@code{STACK_POINTER_OFFSET} may be appropriate for many machines, but +not all. + +On SPARC, for example, the register save area is *not* considered active +or used by the active function, but rather as akin to the area in which +call-preserved registers are saved by callees, so the stack address is +above that area, even though the (unbiased) stack pointer points below +it. This enables @code{__strub_leave} to clear what would otherwise +overlap with its own register save area. + +On PowerPC, @code{STACK_POINTER_OFFSET} also reserves space for a save +area, but that area is used by the caller rather than the callee, so the +boundary address is below it. + +If the address is computed too high or too low, parts of a stack range +that should be scrubbed may be left unscrubbed, scrubbing may corrupt +active portions of the stack frame, and stack ranges may be +doubly-scrubbed by caller and callee. +@end defmac + @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY If defined to nonzero, @code{__strub_leave} will allocate a dynamic array covering the stack range that needs scrubbing before clearing it. diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 21343d4..658e1e6 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2688,6 +2688,35 @@ may reduce the size of debug information on some ports. @hook TARGET_HAVE_STRUB_SUPPORT_FOR +@defmac STACK_ADDRESS_OFFSET +Offset from the stack pointer register to the boundary address between +the stack area claimed by an active function, and stack ranges that +could get clobbered if it called another function. It should NOT +encompass any stack red zone, that is used in leaf functions. + +This value is added to the stack pointer register to compute the address +returned by @code{__builtin_stack_address}, and this is its only use. +If this macro is not defined, no offset is added. Defining it like +@code{STACK_POINTER_OFFSET} may be appropriate for many machines, but +not all. + +On SPARC, for example, the register save area is *not* considered active +or used by the active function, but rather as akin to the area in which +call-preserved registers are saved by callees, so the stack address is +above that area, even though the (unbiased) stack pointer points below +it. This enables @code{__strub_leave} to clear what would otherwise +overlap with its own register save area. + +On PowerPC, @code{STACK_POINTER_OFFSET} also reserves space for a save +area, but that area is used by the caller rather than the callee, so the +boundary address is below it. + +If the address is computed too high or too low, parts of a stack range +that should be scrubbed may be left unscrubbed, scrubbing may corrupt +active portions of the stack frame, and stack ranges may be +doubly-scrubbed by caller and callee. +@end defmac + @defmac TARGET_STRUB_USE_DYNAMIC_ARRAY If defined to nonzero, @code{__strub_leave} will allocate a dynamic array covering the stack range that needs scrubbing before clearing it. diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 2b72321..4b09c35 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -19027,6 +19027,7 @@ loc_list_from_tree_1 (tree loc, int want_address, && ! DECL_IGNORED_P (loc) && (INTEGRAL_TYPE_P (TREE_TYPE (loc)) || POINTER_TYPE_P (TREE_TYPE (loc))) + && TYPE_MODE (TREE_TYPE (loc)) != BLKmode && (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (loc))) <= DWARF2_ADDR_SIZE)) { diff --git a/gcc/ggc-common.cc b/gcc/ggc-common.cc index be4909d..caf456f 100644 --- a/gcc/ggc-common.cc +++ b/gcc/ggc-common.cc @@ -692,7 +692,7 @@ gt_pch_save (FILE *f) { gcc_assert ((uintptr_t) addr >= (uintptr_t) mmi.preferred_base && ((uintptr_t) addr + sizeof (void *) - < (uintptr_t) mmi.preferred_base + mmi.size)); + <= (uintptr_t) mmi.preferred_base + mmi.size)); if (addr == last_addr) continue; if (last_addr == NULL) diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index a46e640..5191102 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -4019,6 +4019,11 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi) maxlen = wi::to_wide (max_object_size (), prec) - 2; } + /* For -fsanitize=address, don't optimize the upper bound of the + length to be able to diagnose UB on non-zero terminated arrays. */ + if (sanitize_flags_p (SANITIZE_ADDRESS)) + maxlen = wi::max_value (TYPE_PRECISION (sizetype), UNSIGNED); + if (minlen == maxlen) { /* Fold the strlen call to a constant. */ diff --git a/gcc/gimple-iterator.cc b/gcc/gimple-iterator.cc index 517c533..55ef319 100644 --- a/gcc/gimple-iterator.cc +++ b/gcc/gimple-iterator.cc @@ -666,10 +666,11 @@ gsi_move_after (gimple_stmt_iterator *from, gimple_stmt_iterator *to) /* Move the statement at FROM so it comes right before the statement - at TO. */ + at TO using method M. M defaults to GSI_SAME_STMT. */ void -gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to) +gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to, + gsi_iterator_update m) { gimple *stmt = gsi_stmt (*from); gsi_remove (from, false); @@ -677,7 +678,7 @@ gsi_move_before (gimple_stmt_iterator *from, gimple_stmt_iterator *to) /* For consistency with gsi_move_after, it might be better to have GSI_NEW_STMT here; however, that breaks several places that expect that TO does not change. */ - gsi_insert_before (to, stmt, GSI_SAME_STMT); + gsi_insert_before (to, stmt, m); } diff --git a/gcc/gimple-iterator.h b/gcc/gimple-iterator.h index 2e83a96..78014a4 100644 --- a/gcc/gimple-iterator.h +++ b/gcc/gimple-iterator.h @@ -86,7 +86,8 @@ extern gimple_stmt_iterator gsi_for_stmt (gimple *); extern gimple_stmt_iterator gsi_for_stmt (gimple *, gimple_seq *); extern gphi_iterator gsi_for_phi (gphi *); extern void gsi_move_after (gimple_stmt_iterator *, gimple_stmt_iterator *); -extern void gsi_move_before (gimple_stmt_iterator *, gimple_stmt_iterator *); +extern void gsi_move_before (gimple_stmt_iterator *, gimple_stmt_iterator *, + gsi_iterator_update = GSI_SAME_STMT); extern void gsi_move_to_bb_end (gimple_stmt_iterator *, basic_block); extern void gsi_insert_on_edge (edge, gimple *); extern void gsi_insert_seq_on_edge (edge, gimple_seq); diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc index 0fca974..e19fc2c 100644 --- a/gcc/gimple-low.cc +++ b/gcc/gimple-low.cc @@ -790,6 +790,21 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) return; } + if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) + { + tree base = gimple_call_arg (stmt, 1); + gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR); + tree decl = TREE_OPERAND (base, 0); + if (VAR_P (decl) && TREE_STATIC (decl)) + { + /* Don't poison a variable with static storage; it might have + gotten marked before gimplify_init_constructor promoted it + to static. */ + gsi_remove (gsi, true); + return; + } + } + /* We delay folding of built calls from gimplification to here so the IL is in consistent state for the diagnostic machineries job. */ diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index af16745..41484a0 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -601,12 +601,17 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) { tree atype = (tree_fits_uhwi_p (idx) ? limb_access_type (type, idx) : m_limb_type); + tree ltype = m_limb_type; + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (var)); + if (as != TYPE_ADDR_SPACE (ltype)) + ltype = build_qualified_type (ltype, TYPE_QUALS (ltype) + | ENCODE_QUAL_ADDR_SPACE (as)); tree ret; if (DECL_P (var) && tree_fits_uhwi_p (idx)) { tree ptype = build_pointer_type (strip_array_types (TREE_TYPE (var))); unsigned HOST_WIDE_INT off = tree_to_uhwi (idx) * m_limb_size; - ret = build2 (MEM_REF, m_limb_type, + ret = build2 (MEM_REF, ltype, build_fold_addr_expr (var), build_int_cst (ptype, off)); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (var); @@ -615,7 +620,7 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) else if (TREE_CODE (var) == MEM_REF && tree_fits_uhwi_p (idx)) { ret - = build2 (MEM_REF, m_limb_type, TREE_OPERAND (var, 0), + = build2 (MEM_REF, ltype, TREE_OPERAND (var, 0), size_binop (PLUS_EXPR, TREE_OPERAND (var, 1), build_int_cst (TREE_TYPE (TREE_OPERAND (var, 1)), tree_to_uhwi (idx) @@ -633,10 +638,10 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) { unsigned HOST_WIDE_INT nelts = CEIL (tree_to_uhwi (TYPE_SIZE (type)), limb_prec); - tree atype = build_array_type_nelts (m_limb_type, nelts); + tree atype = build_array_type_nelts (ltype, nelts); var = build1 (VIEW_CONVERT_EXPR, atype, var); } - ret = build4 (ARRAY_REF, m_limb_type, var, idx, NULL_TREE, NULL_TREE); + ret = build4 (ARRAY_REF, ltype, var, idx, NULL_TREE, NULL_TREE); } if (!write_p && !useless_type_conversion_p (atype, m_limb_type)) { @@ -2159,6 +2164,8 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, gcc_assert (gimple_assign_cast_p (g)); tree rhs1 = gimple_assign_rhs1 (g); bitint_prec_kind kind = bitint_prec_small; + if (TREE_CODE (rhs1) == VIEW_CONVERT_EXPR) + rhs1 = TREE_OPERAND (rhs1, 0); gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))); if (TREE_CODE (TREE_TYPE (rhs1)) == BITINT_TYPE) kind = bitint_precision_kind (TREE_TYPE (rhs1)); @@ -5198,9 +5205,18 @@ bitint_large_huge::lower_asm (gimple *stmt) && TREE_CODE (TREE_TYPE (s)) == BITINT_TYPE && bitint_precision_kind (TREE_TYPE (s)) >= bitint_prec_large) { - int part = var_to_partition (m_map, s); - gcc_assert (m_vars[part] != NULL_TREE); - TREE_VALUE (t) = m_vars[part]; + if (SSA_NAME_IS_DEFAULT_DEF (s) + && (!SSA_NAME_VAR (s) || VAR_P (SSA_NAME_VAR (s)))) + { + TREE_VALUE (t) = create_tmp_var (TREE_TYPE (s), "bitint"); + mark_addressable (TREE_VALUE (t)); + } + else + { + int part = var_to_partition (m_map, s); + gcc_assert (m_vars[part] != NULL_TREE); + TREE_VALUE (t) = m_vars[part]; + } } } update_stmt (stmt); @@ -5253,7 +5269,8 @@ bitint_large_huge::lower_stmt (gimple *stmt) mergeable_cast_p = true; else if (TREE_CODE (TREE_TYPE (rhs1)) == BITINT_TYPE && bitint_precision_kind (TREE_TYPE (rhs1)) >= bitint_prec_large - && INTEGRAL_TYPE_P (TREE_TYPE (lhs))) + && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) + || POINTER_TYPE_P (TREE_TYPE (lhs)))) { final_cast_p = true; if (TREE_CODE (rhs1) == SSA_NAME @@ -5382,8 +5399,9 @@ bitint_large_huge::lower_stmt (gimple *stmt) be needed. */ gcc_assert (TYPE_PRECISION (lhs_type) <= 2 * limb_prec); gimple *g; - if (TREE_CODE (lhs_type) == BITINT_TYPE - && bitint_precision_kind (lhs_type) == bitint_prec_middle) + if ((TREE_CODE (lhs_type) == BITINT_TYPE + && bitint_precision_kind (lhs_type) == bitint_prec_middle) + || POINTER_TYPE_P (lhs_type)) lhs_type = build_nonstandard_integer_type (TYPE_PRECISION (lhs_type), TYPE_UNSIGNED (lhs_type)); m_data_cnt = 0; @@ -5819,7 +5837,14 @@ gimple_lower_bitint (void) if (optimize) group_case_labels_stmt (swtch); - switch_statements.safe_push (swtch); + if (gimple_switch_num_labels (swtch) == 1) + { + single_succ_edge (bb)->flags |= EDGE_FALLTHRU; + gimple_stmt_iterator gsi = gsi_for_stmt (swtch); + gsi_remove (&gsi, true); + } + else + switch_statements.safe_push (swtch); } } diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c2a6032..73cb095 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -ddf3758e4a45ca2816fb68f3e4224501a3c4c438 +e15a14e410b8fc5d28012d5b313cb6c8476c7df9 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/ast-dump.cc b/gcc/go/gofrontend/ast-dump.cc index eca0bf1..12f49e6 100644 --- a/gcc/go/gofrontend/ast-dump.cc +++ b/gcc/go/gofrontend/ast-dump.cc @@ -223,14 +223,7 @@ Ast_dump_context::dump_type(const Type* t) if (t == NULL) this->ostream() << "(nil type)"; else - // FIXME: write a type pretty printer instead of - // using mangled names. - if (this->gogo_ != NULL) - { - Backend_name bname; - t->backend_name(this->gogo_, &bname); - this->ostream() << "(" << bname.name() << ")"; - } + this->ostream() << "(" << t->message_name() << ")"; } // Dump a textual representation of a block to the diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index 7373dee..40f6d5d 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -1661,6 +1661,7 @@ Export::register_builtin_types(Gogo* gogo) this->register_builtin_type(gogo, "error", BUILTIN_ERROR); this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); + this->register_builtin_type(gogo, "any", BUILTIN_ANY); } // Register one builtin type in the export table. diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index 1f61343..be117ec 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -51,8 +51,9 @@ enum Builtin_code BUILTIN_ERROR = -19, BUILTIN_BYTE = -20, BUILTIN_RUNE = -21, + BUILTIN_ANY = -22, - SMALLEST_BUILTIN_CODE = -21 + SMALLEST_BUILTIN_CODE = -22 }; // Export data version number. New export data is written with the diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 21691fa..3cc8a72 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -1408,6 +1408,7 @@ Import::register_builtin_types(Gogo* gogo) this->register_builtin_type(gogo, "error", BUILTIN_ERROR); this->register_builtin_type(gogo, "byte", BUILTIN_BYTE); this->register_builtin_type(gogo, "rune", BUILTIN_RUNE); + this->register_builtin_type(gogo, "any", BUILTIN_ANY); } // Register a single builtin type. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index b349ad1..a39cfbf 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -270,6 +270,16 @@ Type::set_is_error() this->classification_ = TYPE_ERROR; } +// Return a string version of this type to use in an error message. + +std::string +Type::message_name() const +{ + std::string ret; + this->do_message_name(&ret); + return ret; +} + // If this is a pointer type, return the type to which it points. // Otherwise, return NULL. @@ -742,16 +752,14 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) { if (rhs->interface_type() != NULL) reason->assign(_("need explicit conversion")); - else if (lhs_orig->named_type() != NULL - && rhs_orig->named_type() != NULL) + else { - size_t len = (lhs_orig->named_type()->name().length() - + rhs_orig->named_type()->name().length() - + 100); + const std::string& lhs_name(lhs_orig->message_name()); + const std::string& rhs_name(rhs_orig->message_name()); + size_t len = lhs_name.length() + rhs_name.length() + 100; char* buf = new char[len]; snprintf(buf, len, _("cannot use type %s as type %s"), - rhs_orig->named_type()->message_name().c_str(), - lhs_orig->named_type()->message_name().c_str()); + rhs_name.c_str(), lhs_name.c_str()); reason->assign(buf); delete[] buf; } @@ -4244,6 +4252,33 @@ Integer_type::is_identical(const Integer_type* t) const return this->is_abstract_ == t->is_abstract_; } +// Message name. + +void +Integer_type::do_message_name(std::string* ret) const +{ + ret->append("<untyped "); + if (this->is_byte_) + ret->append("byte"); + else if (this->is_rune_) + ret->append("rune"); + else + { + if (this->is_unsigned_) + ret->push_back('u'); + if (this->is_abstract_) + ret->append("int"); + else + { + ret->append("int"); + char buf[10]; + snprintf(buf, sizeof buf, "%d", this->bits_); + ret->append(buf); + } + } + ret->push_back('>'); +} + // Hash code. unsigned int @@ -4382,6 +4417,21 @@ Float_type::is_identical(const Float_type* t) const return this->is_abstract_ == t->is_abstract_; } +// Message name. + +void +Float_type::do_message_name(std::string* ret) const +{ + ret->append("<untyped float"); + if (!this->is_abstract_) + { + char buf[10]; + snprintf(buf, sizeof buf, "%d", this->bits_); + ret->append(buf); + } + ret->push_back('>'); +} + // Hash code. unsigned int @@ -4496,6 +4546,21 @@ Complex_type::is_identical(const Complex_type *t) const return this->is_abstract_ == t->is_abstract_; } +// Message name. + +void +Complex_type::do_message_name(std::string* ret) const +{ + ret->append("<untyped complex"); + if (!this->is_abstract_) + { + char buf[10]; + snprintf(buf, sizeof buf, "%d", this->bits_); + ret->append(buf); + } + ret->push_back('>'); +} + // Hash code. unsigned int @@ -4661,6 +4726,10 @@ class Sink_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("<SINK>"); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -4696,6 +4765,70 @@ Type::make_sink_type() // Class Function_type. +// Message name. + +void +Function_type::do_message_name(std::string* ret) const +{ + ret->append("func"); + if (this->receiver_ != NULL) + { + ret->append(" (receiver "); + this->append_message_name(this->receiver_->type(), ret); + ret->append(") "); + } + this->append_signature(ret); +} + +// Append just the signature to RET. + +void +Function_type::append_signature(std::string* ret) const +{ + ret->push_back('('); + if (this->parameters_ != NULL) + { + bool first = true; + for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); + p != this->parameters_->end(); + ++p) + { + if (first) + first = false; + else + ret->append(", "); + this->append_message_name(p->type(), ret); + } + } + ret->push_back(')'); + + if (this->results_ != NULL) + { + if (this->results_->size() == 1) + { + ret->push_back(' '); + this->append_message_name(this->results_->front().type(), ret); + } + else + { + ret->append(" ("); + bool first = true; + for (Typed_identifier_list::const_iterator p = + this->results_->begin(); + p != this->results_->end(); + ++p) + { + if (first) + first = false; + else + ret->append(", "); + this->append_message_name(p->type(), ret); + } + ret->push_back(')'); + } + } +} + // Traversal. int @@ -5548,6 +5681,20 @@ Type::make_backend_function_type(Typed_identifier* receiver, // Class Pointer_type. +// Message name. + +void +Pointer_type::do_message_name(std::string* ret) const +{ + if (this->to_type_->is_void_type()) + ret->append("unsafe.Pointer"); + else + { + ret->push_back('*'); + this->append_message_name(this->to_type_, ret); + } +} + // Traversal. int @@ -5764,6 +5911,10 @@ class Call_multiple_result_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("<call-multiple-result>"); } + bool do_has_pointer() const { return false; } @@ -5940,6 +6091,41 @@ Struct_type::Identical_structs Struct_type::identical_structs; Struct_type::Struct_method_tables Struct_type::struct_method_tables; +// Message name. + +void +Struct_type::do_message_name(std::string* ret) const +{ + if (this->fields_ == NULL || this->fields_->empty()) + { + ret->append("struct{}"); + return; + } + + ret->append("struct {"); + + bool first = true; + for (Struct_field_list::const_iterator p = this->fields_->begin(); + p != this->fields_->end(); + ++p) + { + if (first) + first = false; + else + ret->append("; "); + + if (!p->is_anonymous()) + { + ret->append(p->field_name()); + ret->push_back(' '); + } + + this->append_message_name(p->type(), ret); + } + + ret->append(" }"); +} + // Traversal. int @@ -7344,6 +7530,35 @@ Array_type::is_identical(const Array_type* t, int flags) const return false; } +// Message name. + +void +Array_type::do_message_name(std::string* ret) const +{ + ret->push_back('['); + if (!this->is_slice_type()) + { + Numeric_constant nc; + if (!this->length_->numeric_constant_value(&nc)) + ret->append("<unknown length>"); + else + { + mpz_t val; + if (!nc.to_int(&val)) + ret->append("<unknown length>"); + else + { + char* s = mpz_get_str(NULL, 10, val); + ret->append(s); + free(s); + mpz_clear(val); + } + } + } + ret->push_back(']'); + this->append_message_name(this->element_type_, ret); +} + // Traversal. int @@ -8249,6 +8464,17 @@ Map_type::backend_zero_value(Gogo* gogo) return zvar; } +// Message name. + +void +Map_type::do_message_name(std::string* ret) const +{ + ret->append("map["); + this->append_message_name(this->key_type_, ret); + ret->push_back(']'); + this->append_message_name(this->val_type_, ret); +} + // Traversal. int @@ -8803,6 +9029,20 @@ Type::make_map_type(Type* key_type, Type* val_type, Location location) // Class Channel_type. +// Message name. + +void +Channel_type::do_message_name(std::string* ret) const +{ + if (!this->may_send_) + ret->append("<-"); + ret->append("chan"); + if (!this->may_receive_) + ret->append("<-"); + ret->push_back(' '); + this->append_message_name(this->element_type_, ret); +} + // Verify. bool @@ -9053,6 +9293,45 @@ Interface_type::method_count() const return this->all_methods_ == NULL ? 0 : this->all_methods_->size(); } +// Message name. + +void +Interface_type::do_message_name(std::string* ret) const +{ + const Typed_identifier_list* methods = (this->methods_are_finalized_ + ? this->all_methods_ + : this->parse_methods_); + if (methods == NULL || methods->empty()) + { + ret->append("interface{}"); + return; + } + + ret->append("interface {"); + + bool first = true; + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); + ++p) + { + if (first) + first = false; + else + ret->append("; "); + + if (!p->name().empty()) + ret->append(p->name()); + + Function_type* ft = p->type()->function_type(); + if (ft == NULL) + this->append_message_name(p->type(), ret); + else + ft->append_signature(ret); + } + + ret->append(" }"); +} + // Traversal. int @@ -10295,10 +10574,10 @@ Named_type::name() const // Return the name of the type to use in an error message. -std::string -Named_type::message_name() const +void +Named_type::do_message_name(std::string* ret) const { - return this->named_object_->message_name(); + ret->append(this->named_object_->message_name()); } // Return the base type for this type. We have to be careful about @@ -12819,6 +13098,17 @@ Forward_declaration_type::add_existing_method(Named_object* nom) no->type_declaration_value()->add_existing_method(nom); } +// Message name. + +void +Forward_declaration_type::do_message_name(std::string* ret) const +{ + if (this->is_defined()) + this->append_message_name(this->real_type(), ret); + else + ret->append(this->named_object_->message_name()); +} + // Traversal. int diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 3dd3279..cbc7ce0 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -575,6 +575,10 @@ class Type static Named_type* make_builtin_named_type(const char* name, Type* type); + // Return a string version of this type to use in an error message. + std::string + message_name() const; + // Traverse a type. static int traverse(Type*, Traverse*); @@ -1095,6 +1099,10 @@ class Type // Functions implemented by the child class. + // Message name. + virtual void + do_message_name(std::string*) const = 0; + // Traverse the subtypes. virtual int do_traverse(Traverse*); @@ -1195,6 +1203,11 @@ class Type type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*, const Methods*, bool only_value_methods); + // For the benefit of child class message name construction. + void + append_message_name(const Type* type, std::string* ret) const + { type->do_message_name(ret); } + // For the benefit of child class reflection string generation. void append_reflection(const Type* type, Gogo* gogo, std::string* ret) const @@ -1656,6 +1669,10 @@ class Error_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("<ERROR>"); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -1683,6 +1700,10 @@ class Void_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("void"); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -1712,6 +1733,10 @@ class Boolean_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("<untyped bool>"); } + bool do_compare_is_identity(Gogo*) { return true; } @@ -1797,6 +1822,9 @@ class Integer_type : public Type { this->is_rune_ = true; } protected: + void + do_message_name(std::string* ret) const; + bool do_compare_is_identity(Gogo*) { return true; } @@ -1874,6 +1902,9 @@ class Float_type : public Type is_identical(const Float_type* t) const; protected: + void + do_message_name(std::string* ret) const; + bool do_compare_is_identity(Gogo*) { return false; } @@ -1952,6 +1983,9 @@ class Complex_type : public Type is_identical(const Complex_type* t) const; protected: + void + do_message_name(std::string*) const; + bool do_compare_is_identity(Gogo*) { return false; } @@ -2009,6 +2043,10 @@ class String_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("<untyped string>"); } + bool do_has_pointer() const { return true; } @@ -2166,7 +2204,14 @@ class Function_type : public Type is_backend_function_type() const { return false; } + // Append just the signature of the function type. + void + append_signature(std::string*) const; + protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -2293,6 +2338,9 @@ class Pointer_type : public Type make_pointer_type_descriptor_type(); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -2346,6 +2394,10 @@ class Nil_type : public Type { } protected: + void + do_message_name(std::string* ret) const + { ret->append("<NIL>"); } + bool do_compare_is_identity(Gogo*) { return false; } @@ -2671,6 +2723,9 @@ class Struct_type : public Type write_to_c_header(std::ostream&) const; protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -2851,6 +2906,9 @@ class Array_type : public Type write_equal_function(Gogo*, Named_object* function, Named_type*); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse* traverse); @@ -2999,6 +3057,9 @@ class Map_type : public Type static const int bucket_size = 8; protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -3118,6 +3179,9 @@ class Channel_type : public Type select_case_type(); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse* traverse) { return Type::traverse(this->element_type_, traverse); } @@ -3273,6 +3337,9 @@ class Interface_type : public Type { return this->methods_are_finalized_; } protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse*); @@ -3450,12 +3517,6 @@ class Named_type : public Type const std::string& name() const; - // Return the name of the type for an error message. The difference - // is that if the type is defined in a different package, this will - // return PACKAGE.NAME. - std::string - message_name() const; - // Return the underlying type. Type* real_type() @@ -3599,6 +3660,9 @@ class Named_type : public Type convert(Gogo*); protected: + void + do_message_name(std::string* ret) const; + int do_traverse(Traverse* traverse) { return Type::traverse(this->type_, traverse); } @@ -3758,6 +3822,9 @@ class Forward_declaration_type : public Type add_existing_method(Named_object*); protected: + void + do_message_name(std::string*) const; + int do_traverse(Traverse* traverse); diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc index e1b0701..0ee063c 100644 --- a/gcc/ipa-strub.cc +++ b/gcc/ipa-strub.cc @@ -2052,36 +2052,17 @@ walk_regimplify_phi (gphi *stmt) return needs_commit; } -/* Create a reference type to use for PARM when turning it into a reference. - NONALIASED causes the reference type to gain its own separate alias set, so - that accessing the indirectly-passed parm won'will not add aliasing - noise. */ +/* Create a reference type to use for PARM when turning it into a + reference. */ static tree -build_ref_type_for (tree parm, bool nonaliased = true) +build_ref_type_for (tree parm) { gcc_checking_assert (TREE_CODE (parm) == PARM_DECL); tree ref_type = build_reference_type (TREE_TYPE (parm)); - if (!nonaliased) - return ref_type; - - /* Each PARM turned indirect still points to the distinct memory area at the - wrapper, and the reference in unchanging, so we might qualify it, but... - const is not really important, since we're only using default defs for the - reference parm anyway, and not introducing any defs, and restrict seems to - cause trouble. E.g., libgnat/s-concat3.adb:str_concat_3 has memmoves that, - if it's wrapped, the memmoves are deleted in dse1. Using a distinct alias - set seems to not run afoul of this problem, and it hopefully enables the - compiler to tell the pointers do point to objects that are not otherwise - aliased. */ - tree qref_type = build_variant_type_copy (ref_type); - - TYPE_ALIAS_SET (qref_type) = new_alias_set (); - record_alias_subset (TYPE_ALIAS_SET (qref_type), get_alias_set (ref_type)); - - return qref_type; + return ref_type; } /* Add cgraph edges from current_function_decl to callees in SEQ with frequency @@ -2909,9 +2890,7 @@ pass_ipa_strub::execute (function *) if with transparent reference, and the wrapper doesn't take any extra parms that could point into wrapper's parms. So we can probably drop the TREE_ADDRESSABLE and keep the TRUE. */ - tree ref_type = build_ref_type_for (nparm, - true - || !TREE_ADDRESSABLE (parm)); + tree ref_type = build_ref_type_for (nparm); DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type; relayout_decl (nparm); diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index a7cb813..87f789d 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,18 @@ +2024-02-02 Antoni Boucher <bouanto@zoho.com> + + * docs/topics/compatibility.rst (LIBGCCJIT_ABI_27): New ABI tag. + * docs/topics/expressions.rst: Document gcc_jit_context_new_sizeof. + * jit-playback.cc (new_sizeof): New method. + * jit-playback.h (new_sizeof): New method. + * jit-recording.cc (recording::context::new_sizeof, + recording::memento_of_sizeof::replay_into, + recording::memento_of_sizeof::make_debug_string, + recording::memento_of_sizeof::write_reproducer): New methods. + * jit-recording.h (class memento_of_sizeof): New class. + * libgccjit.cc (gcc_jit_context_new_sizeof): New function. + * libgccjit.h (gcc_jit_context_new_sizeof): New function. + * libgccjit.map: New function. + 2024-01-19 Antoni Boucher <bouanto@zoho.com> * jit-builtins.cc (ensure_optimization_builtins_exist): Add diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index cbf5b41..9cfb054 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -390,3 +390,10 @@ on functions and variables: * :func:`gcc_jit_function_add_string_attribute` * :func:`gcc_jit_function_add_integer_array_attribute` * :func:`gcc_jit_lvalue_add_string_attribute` + +.. _LIBGCCJIT_ABI_27: + +``LIBGCCJIT_ABI_27`` +-------------------- +``LIBGCCJIT_ABI_27`` covers the addition of +:func:`gcc_jit_context_new_sizeof` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 35ee05c..c3f4f61 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -126,6 +126,20 @@ Simple expressions underlying string, so it is valid to pass in a pointer to an on-stack buffer. +.. function:: gcc_jit_rvalue *\ + gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, \ + gcc_jit_type *type) + + Generate an rvalue that is equal to the size of ``type``. + + The parameter ``type`` must be non-NULL. + + This is equivalent to this C code: + + .. code-block:: c + + sizeof (type) + Constructor expressions *********************** diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 84df6c1..e277b01 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -1112,6 +1112,16 @@ new_rvalue_from_const <void *> (type *type, playback::rvalue * playback::context:: +new_sizeof (type *type) +{ + tree inner = TYPE_SIZE_UNIT (type->as_tree ()); + return new rvalue (this, inner); +} + +/* Construct a playback::rvalue instance (wrapping a tree). */ + +playback::rvalue * +playback::context:: new_string_literal (const char *value) { /* Compare with c-family/c-common.cc: fix_string_type. */ diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 05bafcd..aa6a086 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -163,6 +163,9 @@ public: HOST_TYPE value); rvalue * + new_sizeof (type *type); + + rvalue * new_string_literal (const char *value); rvalue * diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 6ffadbe..68a2e86 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -1077,6 +1077,21 @@ recording::context::new_global_init_rvalue (lvalue *variable, gbl->set_rvalue_init (init); /* Needed by the global for write dump. */ } +/* Create a recording::memento_of_sizeof instance and add it + to this context's list of mementos. + + Implements the post-error-checking part of + gcc_jit_context_new_sizeof. */ + +recording::rvalue * +recording::context::new_sizeof (recording::type *type) +{ + recording::rvalue *result = + new memento_of_sizeof (this, NULL, type); + record (result); + return result; +} + /* Create a recording::memento_of_new_string_literal instance and add it to this context's list of mementos. @@ -5457,6 +5472,43 @@ memento_of_new_rvalue_from_const <void *>::write_reproducer (reproducer &r) } // namespace recording +/* The implementation of class gcc::jit::recording::memento_of_sizeof. */ + +/* Implementation of pure virtual hook recording::memento::replay_into + for recording::memento_of_sizeof. */ + +void +recording::memento_of_sizeof::replay_into (replayer *r) +{ + set_playback_obj (r->new_sizeof (m_type->playback_type ())); +} + +/* Implementation of recording::memento::make_debug_string for + sizeof expressions. */ + +recording::string * +recording::memento_of_sizeof::make_debug_string () +{ + return string::from_printf (m_ctxt, + "sizeof (%s)", + m_type->get_debug_string ()); +} + +/* Implementation of recording::memento::write_reproducer for sizeof + expressions. */ + +void +recording::memento_of_sizeof::write_reproducer (reproducer &r) +{ + const char *id = r.make_identifier (this, "rvalue"); + r.write (" gcc_jit_rvalue *%s =\n" + " gcc_jit_context_new_sizeof (%s, /* gcc_jit_context *ctxt */\n" + " %s); /* gcc_jit_type *type */\n", + id, + r.get_identifier (get_context ()), + r.get_identifier (m_type)); +} + /* The implementation of class gcc::jit::recording::memento_of_new_string_literal. */ /* Implementation of pure virtual hook recording::memento::replay_into diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index ab5ba6c..d8d16f4 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -170,6 +170,9 @@ public: HOST_TYPE value); rvalue * + new_sizeof (type *type); + + rvalue * new_string_literal (const char *value); rvalue * @@ -1605,6 +1608,31 @@ private: HOST_TYPE m_value; }; +class memento_of_sizeof : public rvalue +{ +public: + memento_of_sizeof (context *ctxt, + location *loc, + type *type) + : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_INT)), + m_type (type) {} + + void replay_into (replayer *r) final override; + + void visit_children (rvalue_visitor *) final override {} + +private: + string * make_debug_string () final override; + void write_reproducer (reproducer &r) final override; + enum precedence get_precedence () const final override + { + return PRECEDENCE_PRIMARY; + } + +private: + type *m_type; +}; + class memento_of_new_string_literal : public rvalue { public: diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index bf0150f..f40a978 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -2076,6 +2076,24 @@ gcc_jit_context_null (gcc_jit_context *ctxt, /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::context::new_sizeof method in + jit-recording.cc. */ + +gcc_jit_rvalue * +gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, + gcc_jit_type *type) +{ + RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + RETURN_NULL_IF_FAIL (type, ctxt, NULL, "NULL type"); + JIT_LOG_FUNC (ctxt->get_logger ()); + + return ((gcc_jit_rvalue *)ctxt + ->new_sizeof (type)); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::context::new_string_literal method in jit-recording.cc. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 235cab0..74e847b 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1093,6 +1093,18 @@ extern gcc_jit_rvalue * gcc_jit_context_null (gcc_jit_context *ctxt, gcc_jit_type *pointer_type); +#define LIBGCCJIT_HAVE_gcc_jit_context_new_sizeof + +/* Generates an rvalue that is equal to the size of type. + + This API entrypoint was added in LIBGCCJIT_ABI_27; you can test for its + presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_sizeof */ + +extern gcc_jit_rvalue * +gcc_jit_context_new_sizeof (gcc_jit_context *ctxt, + gcc_jit_type *type); + /* String literals. */ extern gcc_jit_rvalue * gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index dfb8a9d..99aa597 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -284,3 +284,8 @@ LIBGCCJIT_ABI_26 { gcc_jit_lvalue_add_string_attribute; gcc_jit_function_add_integer_array_attribute; } LIBGCCJIT_ABI_25; + +LIBGCCJIT_ABI_27 { + global: + gcc_jit_context_new_sizeof; +} LIBGCCJIT_ABI_26; diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog index 9237324..afd5bff 100644 --- a/gcc/m2/ChangeLog +++ b/gcc/m2/ChangeLog @@ -1,3 +1,52 @@ +2024-02-03 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/113730 + * gm2-compiler/M2Base.mod (IsUserType): New procedure function. + (MixTypes): Use IsUserType instead of IsType before calling MixTypes. + * gm2-compiler/M2GenGCC.mod (GetTypeMode): Remove and import from + SymbolTable. + (CodeBinaryCheck): Replace call to MixTypes with MixTypesBinary. + (CodeBinary): Replace call to MixTypes with MixTypesBinary. + (CodeIfLess): Replace MixTypes with ComparisonMixTypes. + (CodeIfGre): Replace MixTypes with ComparisonMixTypes. + (CodeIfLessEqu): Replace MixTypes with ComparisonMixTypes. + (CodeIfGreEqu): Replace MixTypes with ComparisonMixTypes. + (CodeIfEqu): Replace MixTypes with ComparisonMixTypes. + (CodeIfNotEqu): Replace MixTypes with ComparisonMixTypes. + (ComparisonMixTypes): New procedure function. + * gm2-compiler/M2Quads.mod (BuildEndFor): Replace GenQuadO + with GenQuadOtok and pass tokenpos for the operands to the AddOp + and XIndrOp. + (CheckRangeIncDec): Check etype against NulSym and dtype for a + pointer and set etype to Address. + (BuildAddAdrFunction): New variable opa. Convert operand to an + address and save result in opa. Replace GenQuad with GenQuadOtok. + (BuildSubAdrFunction): New variable opa. Convert operand to an + address and save result in opa. Replace GenQuad with GenQuadOtok. + (BuildDiffAdrFunction): New variable opa. Convert operand to an + address and save result in opa. Replace GenQuad with GenQuadOtok. + (calculateMultipicand): Replace GenQuadO with GenQuadOtok. + (ConvertToAddress): New procedure function. + (BuildDynamicArray): Convert index to address before adding to + the base. + * gm2-compiler/SymbolTable.def (GetTypeMode): New procedure function. + * gm2-compiler/SymbolTable.mod (GetTypeMode): New procedure + function implemented (moved from M2GenGCC.mod). + * gm2-libs/SArgs.mod (GetArg): Replace cast to PtrToChar with ADDRESS. + +2024-02-01 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/111627 + PR modula2/112506 + * gm2-compiler/M2Comp.mod (Pass0CheckMod): Test IsDefImp before + checking IsDefinitionForC. + +2024-01-31 Gaius Mulley <gaiusmod2@gmail.com> + + * gm2-compiler/M2Comp.mod (Pass0CheckMod): Tidy up comment. + * gm2-compiler/P1Build.bnf (PossiblyExportIdent): Replace + PushTF with PushTFtok. + 2024-01-26 Gaius Mulley <gaiusmod2@gmail.com> * gm2-compiler/M2Check.mod (dumpIndice): New procedure. diff --git a/gcc/m2/gm2-compiler/M2Base.mod b/gcc/m2/gm2-compiler/M2Base.mod index 04a0e4e..b867769 100644 --- a/gcc/m2/gm2-compiler/M2Base.mod +++ b/gcc/m2/gm2-compiler/M2Base.mod @@ -85,7 +85,8 @@ FROM M2Size IMPORT Size, MakeSize ; FROM M2System IMPORT Address, Byte, Word, System, Loc, InitSystem, IntegerN, CardinalN, WordN, SetN, RealN, ComplexN, IsCardinalN, IsIntegerN, IsRealN, IsComplexN, - IsGenericSystemType, IsSameSizePervasiveType ; + IsGenericSystemType, IsSameSizePervasiveType, + IsSystemType ; FROM M2Options IMPORT NilChecking, WholeDivChecking, WholeValueChecking, @@ -1990,7 +1991,7 @@ BEGIN mt2 := FindMetaType(t2) ; CASE Expr[mt1, mt2] OF - no : MetaErrorT2 (NearTok, 'type incompatibility between {%1as} and {%2as}', t1, t2) ; + no : MetaErrorT2 (NearTok, 'type incompatibility between {%1asd} and {%2asd}', t1, t2) ; FlushErrors (* unrecoverable at present *) | warnfirst, first : RETURN( t1 ) | @@ -2005,6 +2006,16 @@ END MixMetaTypes ; (* + IsUserType - return TRUE if type was created by the user as a synonym. +*) + +PROCEDURE IsUserType (type: CARDINAL) : BOOLEAN ; +BEGIN + RETURN IsType (type) AND (NOT IsBaseType (type)) AND (NOT IsSystemType (type)) +END IsUserType ; + + +(* MixTypes - given types, t1 and t2, returns a type symbol that provides expression type compatibility. NearTok is used to identify the source position if a type @@ -2074,10 +2085,10 @@ BEGIN ELSE RETURN( CType ) END - ELSIF IsType(t1) + ELSIF IsUserType (t1) THEN RETURN( MixTypes(GetType(t1), t2, NearTok) ) - ELSIF IsType(t2) + ELSIF IsUserType (t2) THEN RETURN( MixTypes(t1, GetType(t2), NearTok) ) ELSIF (t1=GetLowestType(t1)) AND (t2=GetLowestType(t2)) diff --git a/gcc/m2/gm2-compiler/M2Comp.mod b/gcc/m2/gm2-compiler/M2Comp.mod index 48ea7b7..c10c301 100644 --- a/gcc/m2/gm2-compiler/M2Comp.mod +++ b/gcc/m2/gm2-compiler/M2Comp.mod @@ -869,11 +869,11 @@ BEGIN END ELSIF GenModuleList THEN - IF NOT IsDefinitionForC (sym) + IF IsDefImp (sym) AND (NOT IsDefinitionForC (sym)) THEN (* The implementation module is only useful if -fgen-module-list= is - used (to gather all dependencies) although we do not insist upon finding the - implementation module. *) + used (to gather all dependencies). Note that we do not insist + upon finding the implementation module. *) LibName := NIL ; IF FindSourceModFile (SymName, FileName, LibName) THEN diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod index 92ca39f..25bfbf8 100644 --- a/gcc/m2/gm2-compiler/M2GenGCC.mod +++ b/gcc/m2/gm2-compiler/M2GenGCC.mod @@ -76,7 +76,7 @@ FROM SymbolTable IMPORT PushSize, PopSize, PushValue, PopValue, GetPriority, GetNeedSavePriority, PutConstString, PutConst, PutConstSet, PutConstructor, - GetSType, + GetSType, GetTypeMode, HasVarParameters, NulSym ; @@ -2944,21 +2944,6 @@ END DefaultConvertGM2 ; (* - GetTypeMode - -*) - -PROCEDURE GetTypeMode (sym: CARDINAL) : CARDINAL ; -BEGIN - IF GetMode(sym)=LeftValue - THEN - RETURN( Address ) - ELSE - RETURN( GetType(sym) ) - END -END GetTypeMode ; - - -(* FoldConstBecomes - returns a Tree containing op3. The tree will have been folded and type converted if necessary. @@ -3523,7 +3508,7 @@ BEGIN DeclareConstant (op2pos, op2) ; location := TokenToLocation (op1pos) ; - type := MixTypes (FindType (op2), FindType (op3), op3pos) ; + type := MixTypesBinary (op2, op3, op1pos, MustCheckOverflow (quad)) ; ConvertBinaryOperands (location, tl, tr, type, op2, op3) ; lowestType := GetLType (op1) ; @@ -3554,6 +3539,23 @@ END CodeBinaryCheck ; (* + MixTypesBinary - depending upon check do not check pointer arithmetic. +*) + +PROCEDURE MixTypesBinary (left, right: CARDINAL; + tokpos: CARDINAL; check: BOOLEAN) : CARDINAL ; +BEGIN + IF (NOT check) AND + (IsPointer (GetTypeMode (left)) OR IsPointer (GetTypeMode (right))) + THEN + RETURN Address + ELSE + RETURN MixTypes (FindType (left), FindType (right), tokpos) + END +END MixTypesBinary ; + + +(* CodeBinary - encode a binary arithmetic operation. *) @@ -3576,7 +3578,7 @@ BEGIN DeclareConstant (op2pos, op2) ; location := TokenToLocation (op1pos) ; - type := MixTypes (FindType (op2), FindType (op3), op1pos) ; + type := MixTypesBinary (op2, op3, op1pos, MustCheckOverflow (quad)) ; ConvertBinaryOperands (location, tl, tr, type, op2, op3) ; tv := binop (location, tl, tr, FALSE) ; @@ -6742,9 +6744,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildLessThan(location, tl, tr), NIL, string(CreateLabelName(op3))) @@ -6839,9 +6841,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildGreaterThan(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -6935,9 +6937,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildLessThanOrEqual(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -7031,9 +7033,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildGreaterThanOrEqual(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -7147,6 +7149,24 @@ END CodeIfSetNotEqu ; (* + ComparisonMixTypes - +*) + +PROCEDURE ComparisonMixTypes (left, right: CARDINAL; tokpos: CARDINAL) : CARDINAL ; +BEGIN + IF IsGenericSystemType (left) + THEN + RETURN left + ELSIF IsGenericSystemType (right) + THEN + RETURN right + ELSE + RETURN MixTypes (left, right, tokpos) + END +END ComparisonMixTypes ; + + +(* CodeIfEqu - codes the quadruple if op1 = op2 then goto op3 *) @@ -7185,9 +7205,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildEqualTo(location, tl, tr), NIL, string(CreateLabelName(op3))) END @@ -7234,9 +7254,9 @@ BEGIN ELSE ConvertBinaryOperands(location, tl, tr, - MixTypes(SkipType(GetType(op1)), - SkipType(GetType(op2)), - CurrentQuadToken), + ComparisonMixTypes (SkipType (GetType (op1)), + SkipType (GetType (op2)), + CurrentQuadToken), op1, op2) ; DoJump(location, BuildNotEqualTo(location, tl, tr), NIL, string(CreateLabelName(op3))) diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod index a666a4e..a23fa32 100644 --- a/gcc/m2/gm2-compiler/M2Quads.mod +++ b/gcc/m2/gm2-compiler/M2Quads.mod @@ -132,6 +132,7 @@ FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown, ForeachFieldEnumerationDo, ForeachLocalSymDo, GetExported, PutImported, GetSym, GetLibName, + GetTypeMode, IsUnused, NulSym ; @@ -266,7 +267,7 @@ IMPORT M2Error ; CONST DebugStackOn = TRUE ; DebugVarients = FALSE ; - BreakAtQuad = 53 ; + BreakAtQuad = 189 ; DebugTokPos = FALSE ; TYPE @@ -4628,9 +4629,11 @@ BEGIN is counting down. The above test will generate a more precise error message, so we suppress overflow detection here. *) - GenQuadO (bytok, AddOp, tsym, tsym, BySym, FALSE) ; + GenQuadOtok (bytok, AddOp, tsym, tsym, BySym, FALSE, + bytok, bytok, bytok) ; CheckPointerThroughNil (idtok, IdSym) ; - GenQuadO (idtok, XIndrOp, IdSym, GetSType (IdSym), tsym, FALSE) + GenQuadOtok (idtok, XIndrOp, IdSym, GetSType (IdSym), tsym, FALSE, + idtok, idtok, idtok) ELSE BuildRange (InitForLoopEndRangeCheck (IdSym, BySym)) ; IncQuad := NextQuad ; @@ -4639,7 +4642,8 @@ BEGIN is counting down. The above test will generate a more precise error message, so we suppress overflow detection here. *) - GenQuadO (idtok, AddOp, IdSym, IdSym, BySym, FALSE) + GenQuadOtok (idtok, AddOp, IdSym, IdSym, BySym, FALSE, + bytok, bytok, bytok) END ; GenQuadO (endpostok, GotoOp, NulSym, NulSym, ForQuad, FALSE) ; BackPatch (PopFor (), NextQuad) ; @@ -7104,6 +7108,11 @@ VAR BEGIN dtype := GetDType(des) ; etype := GetDType(expr) ; + IF (etype = NulSym) AND IsPointer (GetTypeMode (des)) + THEN + expr := ConvertToAddress (tokenpos, expr) ; + etype := Address + END ; IF WholeValueChecking AND (NOT MustNotCheckBounds) THEN IF tok=PlusTok @@ -7966,6 +7975,7 @@ VAR combinedtok, functok, optok : CARDINAL ; + opa, ReturnVar, NoOfParam, OperandSym, @@ -7986,7 +7996,9 @@ BEGIN THEN ReturnVar := MakeTemporary (combinedtok, RightValue) ; PutVar (ReturnVar, Address) ; - GenQuad (AddOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ; + opa := ConvertToAddress (optok, DereferenceLValue (optok, OperandSym)) ; + GenQuadOtok (combinedtok, AddOp, ReturnVar, VarSym, opa, TRUE, + combinedtok, combinedtok, combinedtok) ; PushTFtok (ReturnVar, Address, combinedtok) ELSE MetaErrorT1 (functok, @@ -8041,6 +8053,7 @@ VAR ReturnVar, NoOfParam, OperandSym, + opa, VarSym : CARDINAL ; BEGIN PopT (NoOfParam) ; @@ -8059,7 +8072,9 @@ BEGIN THEN ReturnVar := MakeTemporary (combinedtok, RightValue) ; PutVar (ReturnVar, Address) ; - GenQuad (SubOp, ReturnVar, VarSym, DereferenceLValue (optok, OperandSym)) ; + opa := ConvertToAddress (optok, DereferenceLValue (optok, OperandSym)) ; + GenQuadOtok (combinedtok, SubOp, ReturnVar, VarSym, opa, TRUE, + combinedtok, combinedtok, combinedtok) ; PushTFtok (ReturnVar, Address, combinedtok) ELSE MetaErrorT1 (functok, @@ -8119,6 +8134,7 @@ VAR TempVar, NoOfParam, OperandSym, + opa, VarSym : CARDINAL ; BEGIN PopT (NoOfParam) ; @@ -8139,7 +8155,9 @@ BEGIN THEN TempVar := MakeTemporary (vartok, RightValue) ; PutVar (TempVar, Address) ; - GenQuad (SubOp, TempVar, VarSym, DereferenceLValue (optok, OperandSym)) ; + opa := ConvertToAddress (optok, DereferenceLValue (optok, OperandSym)) ; + GenQuadOtok (combinedtok, SubOp, TempVar, VarSym, opa, TRUE, + combinedtok, combinedtok, combinedtok) ; (* Build macro: CONVERT( INTEGER, TempVar ) *) @@ -10281,10 +10299,12 @@ BEGIN IF IsAModula2Type (OperandT (1)) THEN ReturnVar := MakeTemporary (resulttok, ImmediateValue) ; + PutVar (ReturnVar, Cardinal) ; GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT (1), FALSE) ELSIF IsVar (OperandT (1)) THEN ReturnVar := MakeTemporary (resulttok, ImmediateValue) ; + PutVar (ReturnVar, Cardinal) ; GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, GetSType (OperandT (1)), FALSE) ELSE MetaErrorT1 (resulttok, @@ -10307,6 +10327,7 @@ BEGIN paramtok := OperandTtok (1) ; resulttok := MakeVirtualTok (functok, functok, paramtok) ; ReturnVar := MakeTemporary (resulttok, ImmediateValue) ; + PutVar (ReturnVar, Cardinal) ; GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Record, FALSE) ELSE resulttok := MakeVirtualTok (functok, functok, paramtok) ; @@ -11212,7 +11233,8 @@ BEGIN GenHigh (tok, tk, dim, arraySym) ; tl := MakeTemporary (tok, RightValue) ; PutVar (tl, Cardinal) ; - GenQuadO (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE) ; + GenQuadOtok (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE, + tok, tok, tok) ; tj := calculateMultipicand (tok, arraySym, arrayType, dim) ; ti := MakeTemporary (tok, RightValue) ; PutVar (ti, Cardinal) ; @@ -11223,6 +11245,29 @@ END calculateMultipicand ; (* + ConvertToAddress - convert sym to an address. +*) + +PROCEDURE ConvertToAddress (tokpos: CARDINAL; sym: CARDINAL) : CARDINAL ; +VAR + adr: CARDINAL ; +BEGIN + IF GetSType (sym) = Address + THEN + RETURN sym + ELSE + PushTF (RequestSym (tokpos, MakeKey ('CONVERT')), NulSym) ; + PushT (Address) ; + PushTtok (sym, tokpos) ; + PushT(2) ; (* Two parameters *) + BuildConvertFunction ; + PopT (adr) ; + RETURN adr + END +END ConvertToAddress ; + + +(* BuildDynamicArray - Builds the array referencing for dynamic arrays. The Stack is expected to contain: @@ -11259,7 +11304,8 @@ VAR PtrToBase, Base, Dim, rw, - ti, tj, tk : CARDINAL ; + ti, tj, tk, + tka : CARDINAL ; BEGIN DisplayStack ; Sym := OperandT (2) ; @@ -11349,19 +11395,23 @@ BEGIN *) BackEndType := MakePointer (combinedTok, NulName) ; PutPointer (BackEndType, GetSType (Type)) ; + (* Create a temporary pointer for addition. *) + tka := ConvertToAddress (combinedTok, tk) ; IF Dim = GetDimension (Type) THEN PutLeftValueFrontBackType (Adr, GetSType(Type), BackEndType) ; - GenQuad (AddOp, Adr, Base, tk) ; + GenQuadOtok (combinedTok, AddOp, Adr, Base, tka, FALSE, + combinedTok, combinedTok, combinedTok) ; PopN (2) ; PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok) ELSE (* more to index *) PutLeftValueFrontBackType (Adr, Type, BackEndType) ; - GenQuad (AddOp, Adr, Base, tk) ; + GenQuadOtok (combinedTok, AddOp, Adr, Base, tka, FALSE, + combinedTok, combinedTok, combinedTok) ; PopN (2) ; PushTFADrwtok (Adr, GetSType(Adr), ArraySym, Dim, rw, combinedTok) END diff --git a/gcc/m2/gm2-compiler/P1Build.bnf b/gcc/m2/gm2-compiler/P1Build.bnf index 5d7254f..a3534fc 100644 --- a/gcc/m2/gm2-compiler/P1Build.bnf +++ b/gcc/m2/gm2-compiler/P1Build.bnf @@ -374,7 +374,7 @@ VAR nothing: CARDINAL ; BEGIN AddNameToScope(makekey(currentstring)) ; - PushTF(makekey(currentstring), identtok) ; + PushTFtok(makekey(currentstring), identtok, GetTokenNo()) ; CheckExplicitExported ; IF NOT IsAutoPushOn() THEN diff --git a/gcc/m2/gm2-compiler/SymbolTable.def b/gcc/m2/gm2-compiler/SymbolTable.def index 958591a..6cbc5c2 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.def +++ b/gcc/m2/gm2-compiler/SymbolTable.def @@ -105,7 +105,7 @@ EXPORT QUALIFIED NulSym, AddSymToModuleScope, GetType, GetLType, GetSType, GetDType, SkipType, SkipTypeAndSubrange, - GetLowestType, + GetLowestType, GetTypeMode, GetSym, GetLocalSym, GetDeclareSym, GetRecord, FromModuleGetSym, GetOAFamily, @@ -1175,6 +1175,14 @@ PROCEDURE GetDType (sym: CARDINAL) : CARDINAL ; (* + GetTypeMode - return the type of sym, it returns Address is the + symbol is a LValue. +*) + +PROCEDURE GetTypeMode (sym: CARDINAL) : CARDINAL ; + + +(* GetSym - searches the current scope (and previous scopes if the scope tranparent allows) for a symbol with Name. *) diff --git a/gcc/m2/gm2-compiler/SymbolTable.mod b/gcc/m2/gm2-compiler/SymbolTable.mod index d939d58..7cef7ee 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.mod +++ b/gcc/m2/gm2-compiler/SymbolTable.mod @@ -112,6 +112,8 @@ CONST UnboundedAddressName = "_m2_contents" ; UnboundedHighName = "_m2_high_%d" ; + BreakSym = 5293 ; + TYPE ConstLitPoolEntry = POINTER TO RECORD sym : CARDINAL ; @@ -1015,6 +1017,14 @@ END FinalSymbol ; (* + stop - a debugger convenience hook. +*) + +PROCEDURE stop ; +END stop ; + + +(* NewSym - Sets Sym to a new symbol index. *) @@ -1028,6 +1038,10 @@ BEGIN SymbolType := DummySym END ; PutIndice(Symbols, sym, pSym) ; + IF sym = BreakSym + THEN + stop + END ; INC(FreeSymbol) END NewSym ; @@ -6603,6 +6617,22 @@ END GetConstLitType ; (* + GetTypeMode - return the type of sym, it returns Address is the + symbol is a LValue. +*) + +PROCEDURE GetTypeMode (sym: CARDINAL) : CARDINAL ; +BEGIN + IF GetMode (sym) = LeftValue + THEN + RETURN( Address ) + ELSE + RETURN( GetType (sym) ) + END +END GetTypeMode ; + + +(* GetLocalSym - only searches the scope Sym for a symbol with name and returns the index to the symbol. *) diff --git a/gcc/m2/gm2-libs/SArgs.mod b/gcc/m2/gm2-libs/SArgs.mod index b1996cc..d6cb448 100644 --- a/gcc/m2/gm2-libs/SArgs.mod +++ b/gcc/m2/gm2-libs/SArgs.mod @@ -65,10 +65,8 @@ BEGIN i := VAL (INTEGER, n) ; IF i < GetArgC () THEN - (* ppc := ADDRESS (VAL (PtrToPtrToChar, ArgV) + (i * CARDINAL (TSIZE(PtrToChar)))) ; *) - ppc := ADDRESS (PtrToChar (GetArgV ()) + (n * TSIZE (PtrToChar))) ; + ppc := ADDRESS (ADDRESS (GetArgV ()) + (n * TSIZE (PtrToChar))) ; s := InitStringCharStar (ppc^) ; - RETURN TRUE ELSE s := NIL ; diff --git a/gcc/match.pd b/gcc/match.pd index e42ecaf..711c3a1 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -6754,19 +6754,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >= TYPE_PRECISION (TREE_TYPE (@10))) && (TYPE_UNSIGNED (TREE_TYPE (@00)) == TYPE_UNSIGNED (TREE_TYPE (@10)))) - || (TREE_CODE (@10) == INTEGER_CST + || (TREE_CODE (@1) == INTEGER_CST && INTEGRAL_TYPE_P (TREE_TYPE (@00)) - && int_fits_type_p (@10, TREE_TYPE (@00))))) + && int_fits_type_p (@1, TREE_TYPE (@00))))) (cmp @00 (convert @10)) - (if (TREE_CODE (@10) == INTEGER_CST + (if (TREE_CODE (@1) == INTEGER_CST && INTEGRAL_TYPE_P (TREE_TYPE (@00)) - && !int_fits_type_p (@10, TREE_TYPE (@00))) + && !int_fits_type_p (@1, TREE_TYPE (@00))) (with { tree min = lower_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00)); tree max = upper_bound_in_type (TREE_TYPE (@10), TREE_TYPE (@00)); - bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @10)); - bool below = integer_nonzerop (const_binop (LT_EXPR, type, @10, min)); + bool above = integer_nonzerop (const_binop (LT_EXPR, type, max, @1)); + bool below = integer_nonzerop (const_binop (LT_EXPR, type, @1, min)); } (if (above || below) (if (cmp == EQ_EXPR || cmp == NE_EXPR) @@ -9592,18 +9592,18 @@ and, /* Detect simplification for vector condition folding where - c = mask1 ? (masked_op mask2 a b) : b + c = mask1 ? (masked_op mask2 a b els) : els into - c = masked_op (mask1 & mask2) a b + c = masked_op (mask1 & mask2) a b els where the operation can be partially applied to one operand. */ (for cond_op (COND_BINARY) (simplify (vec_cond @0 - (cond_op:s @1 @2 @3 @4) @3) + (cond_op:s @1 @2 @3 @4) @4) (cond_op (bit_and @1 @0) @2 @3 @4))) /* And same for ternary expressions. */ @@ -9611,7 +9611,7 @@ and, (for cond_op (COND_TERNARY) (simplify (vec_cond @0 - (cond_op:s @1 @2 @3 @4 @5) @4) + (cond_op:s @1 @2 @3 @4 @5) @5) (cond_op (bit_and @1 @0) @2 @3 @4 @5))) /* For pointers @0 and @2 and nonnegative constant offset @1, look for diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index a5656aa..c0ff212 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,7 @@ +2024-02-05 Joseph Myers <josmyers@redhat.com> + + * zh_CN.po: Update. + 2023-07-31 Joseph Myers <joseph@codesourcery.com> * sv.po: Update. diff --git a/gcc/po/zh_CN.po b/gcc/po/zh_CN.po index 42661f6..0462ba2 100644 --- a/gcc/po/zh_CN.po +++ b/gcc/po/zh_CN.po @@ -4,7 +4,7 @@ # Meng Jie <zuxy.meng@gmail.com>, 2005-2014. # Jeff Bai <jeffbai@aosc.xyz>, 2015. # Mingye Wang (Arthur2e5) <arthur200126@gmail.com>, 2015, 2016. -# Boyuan Yang <073plan@gmail.com>, 2019, 2023. +# Boyuan Yang <073plan@gmail.com>, 2019, 2023, 2024. # Zixing Zhou <zixingzhou@foxmail.com>, 2023. # # Fellow translatiors: @@ -32,19 +32,19 @@ # msgid "" msgstr "" -"Project-Id-Version: gcc 13.1-b20230409\n" +"Project-Id-Version: gcc 13.2.0\n" "Report-Msgid-Bugs-To: https://gcc.gnu.org/bugs/\n" "POT-Creation-Date: 2023-07-26 18:38+0000\n" -"PO-Revision-Date: 2023-04-13 22:07-0400\n" +"PO-Revision-Date: 2024-02-05 15:48-0500\n" "Last-Translator: Boyuan Yang <073plan@gmail.com>\n" "Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Bugs: Report translation errors to the Language-Team address.\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 2.4.3\n" +"X-Bugs: Report translation errors to the Language-Team address.\n" +"X-Generator: Poedit 3.4.2\n" #: cif-code.def:39 msgid "function not considered for inlining" @@ -67,7 +67,6 @@ msgid "function not inlinable" msgstr "函数不能内联" #: cif-code.def:60 -#, fuzzy msgid "function body can be overwritten at link time" msgstr "函数体可能在链接时被改写" @@ -221,10 +220,9 @@ msgid "permerror: " msgstr "永久错误:" #: config/i386/djgpp.h:143 -#, fuzzy, c-format -#| msgid "-f%s not supported: ignored" +#, c-format msgid "-f%s ignored (not supported for DJGPP)\n" -msgstr "-f%s 不受支持:已忽略" +msgstr "-f%s 已被忽略(不支持 DJGPP)\n" #. The remainder are real diagnostic types. #: fortran/gfc-diagnostic.def:33 @@ -372,8 +370,7 @@ msgid "rdynamic is not supported" msgstr "不支持 rdynamic" #: config/dragonfly.h:76 config/i386/freebsd.h:82 config/i386/freebsd64.h:35 -#: config/ia64/freebsd.h:26 config/rs6000/sysv4.h:750 -#: config/sparc/freebsd.h:45 +#: config/ia64/freebsd.h:26 config/rs6000/sysv4.h:750 config/sparc/freebsd.h:45 msgid "consider using '-pg' instead of '-p' with gprof(1)" msgstr "与 gprof(1) 一起使用时请考虑使用‘-pg’以代替‘-p’" @@ -434,7 +431,6 @@ msgid "Darwin does not support -mfentry or associated options" msgstr "Darwin 不支持 -mfentry 以及相关选项" #: config/i386/sol2.h:59 -#, fuzzy msgid "-mx32 is not supported on Solaris" msgstr "Solaris 不支持 -mx32" @@ -451,10 +447,8 @@ msgid "-msingle-float and -msoft-float cannot both be specified" msgstr "不能同时指定 -msingle-float 和 -msoft-float" #: config/moxie/moxiebox.h:43 -#, fuzzy -#| msgid "Assume target CPU is configured as little endian" msgid "this target is little-endian" -msgstr "假定目标 CPU 被配置为小端在前" +msgstr "该目标为小端序" #: config/msp430/msp430.h:90 msgid "-mcode-region requires the large memory model (-mlarge)" @@ -468,16 +462,14 @@ msgstr "-mdata-region 需要大内存模型(-mlarge)" msgid "You need a C startup file for -msys-crt0=" msgstr "-msys-crt0 需要指定C语言启动文件" -#: config/pa/pa-hpux11.h:134 config/pa/pa-hpux11.h:137 -#: config/pa/pa64-hpux.h:29 config/pa/pa64-hpux.h:32 config/pa/pa64-hpux.h:41 -#: config/pa/pa64-hpux.h:44 +#: config/pa/pa-hpux11.h:134 config/pa/pa-hpux11.h:137 config/pa/pa64-hpux.h:29 +#: config/pa/pa64-hpux.h:32 config/pa/pa64-hpux.h:41 config/pa/pa64-hpux.h:44 #, fuzzy msgid "warning: consider linking with '-static' as system libraries with" msgstr "警告:考虑链接时使用‘-static’因为系统库" -#: config/pa/pa-hpux11.h:135 config/pa/pa-hpux11.h:138 -#: config/pa/pa64-hpux.h:30 config/pa/pa64-hpux.h:33 config/pa/pa64-hpux.h:42 -#: config/pa/pa64-hpux.h:45 +#: config/pa/pa-hpux11.h:135 config/pa/pa-hpux11.h:138 config/pa/pa64-hpux.h:30 +#: config/pa/pa64-hpux.h:33 config/pa/pa64-hpux.h:42 config/pa/pa64-hpux.h:45 msgid " profiling support are only provided in archive format" msgstr "取样支持只支持存档格式" @@ -486,9 +478,8 @@ msgid " conflicting code gen style switches are used" msgstr "使用了相互冲突的代码生成风格" #: config/rs6000/freebsd64.h:114 -#, fuzzy msgid "consider using `-pg' instead of `-p' with gprof(1)" -msgstr "与 gprof(1) 一起使用时请考虑使用‘-pg’以代替‘-p’" +msgstr "与 gprof(1) 一起使用时请考虑使用‘-pg’而非‘-p’" #: config/rs6000/rs6000.h:170 msgid "Missing -mcpu option in ASM_CPU_SPEC?" @@ -515,9 +506,8 @@ msgid "SH2a does not support little-endian" msgstr "SH2a 不支持小端在前" #: config/sparc/linux64.h:142 -#, fuzzy msgid "-fsanitize=address is not supported in this configuration" -msgstr "%s 不为这个配置所支持" +msgstr "该配置不支持 -fsanitize=address" #: config/sparc/linux64.h:156 config/sparc/linux64.h:162 #: config/sparc/netbsd-elf.h:103 config/sparc/netbsd-elf.h:112 @@ -538,14 +528,12 @@ msgid "-c or -S required for Ada" msgstr "Ada 需要指定 -c 或 -S" #: ada/gcc-interface/lang-specs.h:56 -#, fuzzy msgid "-c required for gnat2why" -msgstr "Ada 需要指定 -c 或 -S" +msgstr "gnat2why 需要 -c" #: ada/gcc-interface/lang-specs.h:67 -#, fuzzy msgid "-c required for gnat2scil" -msgstr "Ada 需要指定 -c 或 -S" +msgstr "gnat2scil 需要 -c" #: fortran/lang-specs.h:60 fortran/lang-specs.h:74 msgid "gfortran does not support -E without -cpp" @@ -613,7 +601,7 @@ msgstr "不起作用。为向前兼容保留的选项。" #: fortran/lang.opt:218 #, no-c-format msgid "Warn if the type of a variable might be not interoperable with C." -msgstr "对可能不与C语言互通的类型给出警告" +msgstr "对可能不与C语言互通的类型给出警告。" #: fortran/lang.opt:226 #, fuzzy, no-c-format @@ -627,10 +615,9 @@ msgid "Warn about equality comparisons involving REAL or COMPLEX expressions." msgstr "" #: fortran/lang.opt:238 -#, fuzzy, no-c-format -#| msgid "Warn about most implicit conversions" +#, no-c-format msgid "Warn about most implicit conversions." -msgstr "对大多数隐式类型转换给出警告" +msgstr "对大多数隐式类型转换给出警告。" #: fortran/lang.opt:242 #, fuzzy, no-c-format @@ -641,7 +628,7 @@ msgstr "可能缺少括号的情况下给出警告" #: fortran/lang.opt:250 #, no-c-format msgid "Warn if loops have been interchanged." -msgstr "当循环被互换时给出警告" +msgstr "当循环被互换时给出警告。" #: fortran/lang.opt:254 #, fuzzy, no-c-format @@ -686,7 +673,7 @@ msgstr "当格式字符串不是字面量时给出警告" #: fortran/lang.opt:298 #, no-c-format msgid "Warn that -fno-automatic may break recursion." -msgstr "当 -fno-automatic 可能破坏递归时给警告" +msgstr "当 -fno-automatic 可能破坏递归时给警告。" #: fortran/lang.opt:306 #, fuzzy, no-c-format @@ -782,7 +769,7 @@ msgstr "无论选择何种标准,所有内建过程均可用" #: fortran/lang.opt:394 #, no-c-format msgid "Allow a BOZ literal constant to appear in an invalid context and with X instead of Z." -msgstr "允许 BOZ 字面常量在无效上下文中出现,并且使用 X 代替 Z" +msgstr "允许 BOZ 字面常量在无效上下文中出现,并且使用 X 代替 Z." #: fortran/lang.opt:402 #, fuzzy, no-c-format @@ -817,7 +804,7 @@ msgstr "对为过程参数而临时创建的数组产生一个运行时警告" #: fortran/lang.opt:425 #, no-c-format msgid "-fconvert=<big-endian|little-endian|native|swap|r16_ieee|r16_ibm>\tThe endianness used for unformatted files." -msgstr "-fconvert=<big-endian|little-endian|native|swap|r16_ieee|r16_ibm>\t用于非格式化文件的字节序" +msgstr "-fconvert=<big-endian|little-endian|native|swap|r16_ieee|r16_ibm>\t用于非格式化文件的字节序。" #: fortran/lang.opt:450 #, fuzzy, no-c-format @@ -1045,9 +1032,9 @@ msgid "Try to interchange loops if profitable." msgstr "" #: fortran/lang.opt:619 -#, fuzzy, no-c-format +#, no-c-format msgid "Enable front end optimization." -msgstr "启用链接时优化。" +msgstr "启用前端优化。" #: fortran/lang.opt:623 #, fuzzy, no-c-format @@ -1092,7 +1079,7 @@ msgstr "-finit-real=<zero|nan|inf|-inf>\t初始化局部实变量" #: fortran/lang.opt:669 #, no-c-format msgid "-finline-arg-packing\tPerform argument packing inline." -msgstr "-finline-arg-packing\t内联执行参数打包" +msgstr "-finline-arg-packing\t内联执行参数打包。" #: fortran/lang.opt:673 #, fuzzy, no-c-format @@ -1158,34 +1145,34 @@ msgid "Enable range checking during compilation." msgstr "启用编译时范围检查" #: fortran/lang.opt:737 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(4) as a REAL(8)." -msgstr "解译任何真实 (4) 作为真实 (8)" +msgstr "将所有 REAL(4) 解译为 REAL(8)。" #: fortran/lang.opt:741 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(4) as a REAL(10)." -msgstr "解译任何真实 (4) 作为真实 (10)" +msgstr "将所有 REAL(4) 解译为 REAL(10)。" #: fortran/lang.opt:745 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(4) as a REAL(16)." -msgstr "解译任何真实 (4) 作为真实 (16)" +msgstr "将所有 REAL(4) 解译为 REAL(16)。" #: fortran/lang.opt:749 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(8) as a REAL(4)." -msgstr "解译任何真实 (8) 作为真实 (4)" +msgstr "将所有 REAL(8) 解译为 REAL(4)。" #: fortran/lang.opt:753 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(8) as a REAL(10)." -msgstr "解译任何真实 (8) 作为真实 (10)" +msgstr "将所有 REAL(8) 解译为 REAL(10)。" #: fortran/lang.opt:757 -#, fuzzy, no-c-format +#, no-c-format msgid "Interpret any REAL(8) as a REAL(16)." -msgstr "解译任何真实 (8) 作为真实 (16)" +msgstr "将所有 REAL(8) 解译为 REAL(16)。" #: fortran/lang.opt:761 #, fuzzy, no-c-format @@ -1280,40 +1267,34 @@ msgid "Statically link the GCC Quad-Precision Math Library (libquadmath)." msgstr "静态链接 GNU Fortran 助手库(libgfortran)" #: fortran/lang.opt:872 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2003 standard" +#, no-c-format msgid "Conform to the ISO Fortran 2003 standard." -msgstr "遵循 ISO Fortran 2003 标准" +msgstr "遵循 ISO Fortran 2003 标准。" #: fortran/lang.opt:876 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2008 standard" +#, no-c-format msgid "Conform to the ISO Fortran 2008 standard." -msgstr "遵循 ISO Fortran 2008 标准" +msgstr "遵循 ISO Fortran 2008 标准。" #: fortran/lang.opt:880 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2008 standard including TS 29113" +#, no-c-format msgid "Conform to the ISO Fortran 2008 standard including TS 29113." -msgstr "遵循 ISO Fortran 2008 标准,包括 TS 29113" +msgstr "遵循 ISO Fortran 2008 标准,包括 TS 29113." #: fortran/lang.opt:884 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 2008 standard" +#, no-c-format msgid "Conform to the ISO Fortran 2018 standard." -msgstr "遵循 ISO Fortran 2008 标准" +msgstr "遵循 ISO Fortran 2008 标准。" #: fortran/lang.opt:888 -#, fuzzy, no-c-format -#| msgid "Conform to the ISO Fortran 95 standard" +#, no-c-format msgid "Conform to the ISO Fortran 95 standard." -msgstr "遵循 ISO Fortran 95 标准" +msgstr "遵循 ISO Fortran 95 标准。" #: fortran/lang.opt:892 -#, fuzzy, no-c-format -#| msgid "Conform to nothing in particular" +#, no-c-format msgid "Conform to nothing in particular." -msgstr "不特别遵循任何标准" +msgstr "不特别遵循任何标准。" #: fortran/lang.opt:896 #, fuzzy, no-c-format @@ -1322,10 +1303,9 @@ msgid "Accept extensions to support legacy code." msgstr "接受一定的扩展以支持传统的代码" #: rust/lang.opt:47 rust/lang.opt:51 c-family/c.opt:1407 c-family/c.opt:1411 -#, fuzzy, no-c-format -#| msgid "Warn when a variable is unused" +#, no-c-format msgid "Warn when a const variable is unused." -msgstr "有未使用的变量时警告" +msgstr "有未使用的常变量时警告。" #: rust/lang.opt:55 c-family/c.opt:1399 #, fuzzy, no-c-format @@ -1396,10 +1376,9 @@ msgid "-A<question>=<answer>\tAssert the <answer> to <question>. Putting '-' be msgstr "-A<问题>=<答案>\t给出问题的答案。在问题前加一个‘-’将禁用其答案" #: c-family/c.opt:186 -#, fuzzy, no-c-format -#| msgid "Do not discard comments" +#, no-c-format msgid "Do not discard comments." -msgstr "不丢弃注释" +msgstr "不丢弃注释。" #: c-family/c.opt:190 #, fuzzy, no-c-format @@ -1438,16 +1417,14 @@ msgid "-I <dir>\tAdd <dir> to the end of the main include path." msgstr "-I <目录>\t将目录添加至主包含路径末尾" #: c-family/c.opt:217 -#, fuzzy, no-c-format -#| msgid "Generate make dependencies" +#, no-c-format msgid "Generate make dependencies." -msgstr "生成 make 依赖项" +msgstr "生成 make 依赖项。" #: c-family/c.opt:221 -#, fuzzy, no-c-format -#| msgid "Generate make dependencies and compile" +#, no-c-format msgid "Generate make dependencies and compile." -msgstr "生成 make 依赖规则并编译" +msgstr "生成 make 依赖规则并编译。" #: c-family/c.opt:225 #, fuzzy, no-c-format @@ -1456,34 +1433,29 @@ msgid "-MF <file>\tWrite dependency output to the given file." msgstr "-MF <文件>\t将依赖项输出到给定文件" #: c-family/c.opt:229 -#, fuzzy, no-c-format -#| msgid "Treat missing header files as generated files" +#, no-c-format msgid "Treat missing header files as generated files." -msgstr "将缺失的头文件看作生成的文件" +msgstr "将缺失的头文件视为生成的文件。" #: c-family/c.opt:233 -#, fuzzy, no-c-format -#| msgid "Like -M but ignore system header files" +#, no-c-format msgid "Like -M but ignore system header files." -msgstr "与 -M 类似但是忽略系统头文件" +msgstr "与 -M 类似,但是忽略系统头文件。" #: c-family/c.opt:237 -#, fuzzy, no-c-format -#| msgid "Like -MD but ignore system header files" +#, no-c-format msgid "Like -MD but ignore system header files." -msgstr "与 -MD 类似但是忽略系统头文件" +msgstr "与 -MD 类似,但是忽略系统头文件。" #: c-family/c.opt:241 -#, fuzzy, no-c-format -#| msgid "Generate run time type descriptor information" +#, no-c-format msgid "Generate C++ Module dependency information." -msgstr "生成运行时类型描述信息" +msgstr "生成 C++ 模块依赖信息。" #: c-family/c.opt:249 -#, fuzzy, no-c-format -#| msgid "Generate phony targets for all headers" +#, no-c-format msgid "Generate phony targets for all headers." -msgstr "为所有头文件生成伪目标" +msgstr "为所有头文件生成伪目标。" #: c-family/c.opt:253 #, fuzzy, no-c-format @@ -1717,10 +1689,9 @@ msgid "Warn about C++23 constructs in code compiled with an older standard." msgstr "" #: c-family/c.opt:483 -#, fuzzy, no-c-format -#| msgid "Warn about casting functions to incompatible types" +#, no-c-format msgid "Warn about casts between incompatible function types." -msgstr "当把函数转换为不兼容类型时给出警告" +msgstr "当把函数转换为不兼容类型时给出警告。" #: c-family/c.opt:487 #, fuzzy, no-c-format @@ -1753,10 +1724,9 @@ msgstr "当下标类型为“char”时给出警告" #: c-family/c.opt:1620 c-family/c.opt:1624 c-family/c.opt:1628 #: c-family/c.opt:1632 c-family/c.opt:1636 c-family/c.opt:1640 #: config/i386/i386.opt:999 -#, fuzzy, no-c-format -#| msgid "Deprecated. This switch has no effect" +#, no-c-format msgid "Removed in GCC 9. This switch has no effect." -msgstr "已弃用。此开关不起作用。" +msgstr "已在 GCC 9 被移除。此开关不起作用。" #: c-family/c.opt:511 #, fuzzy, no-c-format @@ -2479,10 +2449,9 @@ msgid "Warn if a class interface has no superclass. Root classes may use an att msgstr "" #: c-family/c.opt:1127 -#, fuzzy, no-c-format -#| msgid "Warn if a C-style cast is used in a program" +#, no-c-format msgid "Warn if a C-style cast is used in a program." -msgstr "程序使用 C 风格的类型转换时给出警告" +msgstr "程序使用 C 风格的类型转换时给出警告。" #: c-family/c.opt:1131 #, fuzzy, no-c-format @@ -2875,12 +2844,12 @@ msgstr "" #: c-family/c.opt:1477 #, no-c-format msgid "Warn when a literal '0' is used as null pointer." -msgstr "在字面“0”被用作空指针时给出警告" +msgstr "在字面“0”被用作空指针时给出警告。" #: c-family/c.opt:1481 #, no-c-format msgid "Warn about useless casts." -msgstr "对无用的类型转换给出警告" +msgstr "对无用的类型转换给出警告。" #: c-family/c.opt:1485 #, no-c-format @@ -3210,7 +3179,7 @@ msgstr "除非必需,不生成 DLL 导出的内联函数" #: c-family/c.opt:1880 #, no-c-format msgid "Allow implicit conversions between vectors with differing numbers of subparts and/or differing element types." -msgstr "允许具有不同元素数量和/或元素类型的向量间的转换" +msgstr "允许具有不同元素数量和/或元素类型的向量间的转换。" #: c-family/c.opt:1884 #, no-c-format @@ -5772,7 +5741,7 @@ msgstr "为避免硬件失常,在 CSYNC 或 SSYNC 指令前添加一些 NOP #: config/bfin/bfin.opt:61 #, no-c-format msgid "Avoid speculative loads to work around a hardware anomaly." -msgstr "禁用投机载入以避免一个硬件异常" +msgstr "禁用投机载入以避免一个硬件异常。" #: config/bfin/bfin.opt:65 #, fuzzy, no-c-format @@ -7650,7 +7619,7 @@ msgstr "控制产生的倒数估计。" #: config/i386/i386.opt:590 #, no-c-format msgid "Generate cld instruction in the function prologue." -msgstr "在函数序言中生成 cld 指令" +msgstr "在函数序言中生成 cld 指令。" #: config/i386/i386.opt:594 #, fuzzy, no-c-format @@ -7675,7 +7644,7 @@ msgstr "进行海法调度,当处理器是 bdver1 时也进行派遣调度" #: config/i386/i386.opt:613 #, no-c-format msgid "Use 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer." -msgstr "自动向量化时使用 128 位 AVX 指令而不是 256 位 AVX 指令" +msgstr "自动向量化时使用 128 位 AVX 指令而不是 256 位 AVX 指令。" #: config/i386/i386.opt:617 #, fuzzy, no-c-format @@ -7777,7 +7746,7 @@ msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2 和 AVX 内建 #: config/i386/i386.opt:715 #, no-c-format msgid "Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX and AVX2 built-in functions and code generation." -msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX 和 AVX2 内建函数及代码生成" +msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX 和 AVX2 内建函数及代码生成。" #: config/i386/i386.opt:719 #, no-c-format @@ -7787,12 +7756,12 @@ msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2 #: config/i386/i386.opt:723 #, no-c-format msgid "Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2 and AVX512F and AVX512PF built-in functions and code generation." -msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512PF 内建函数及代码生成" +msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512PF 内建函数及代码生成。" #: config/i386/i386.opt:727 #, no-c-format msgid "Support MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2 and AVX512F and AVX512ER built-in functions and code generation." -msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512ER 内建函数及代码生成" +msgstr "支持 MMX、SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVX、AVX2、AVX512F 和 AVX512ER 内建函数及代码生成。" #: config/i386/i386.opt:731 #, no-c-format @@ -7958,7 +7927,7 @@ msgstr "支持 PCLMUL 内建函数及代码生成。" #: config/i386/i386.opt:847 #, no-c-format msgid "Support BMI built-in functions and code generation." -msgstr "支持 BMI 内建函数及代码生成" +msgstr "支持 BMI 内建函数及代码生成。" #: config/i386/i386.opt:851 #, no-c-format @@ -9758,7 +9727,7 @@ msgstr "开启调试输出" #: config/sparc/sparc.opt:254 #, no-c-format msgid "Enable strict 32-bit psABI struct return checking." -msgstr "启用严格的 32 位 psABI 结构返回检查" +msgstr "启用严格的 32 位 psABI 结构返回检查。" #: config/sparc/sparc.opt:258 #, fuzzy, no-c-format @@ -11631,7 +11600,7 @@ msgstr "" #: config/rx/elf.opt:38 config/rx/rx.opt:99 #, no-c-format msgid "Specifies the number of registers to reserve for interrupt handlers." -msgstr "指定保留给中断处理函数使用的寄存器的数量" +msgstr "指定保留给中断处理函数使用的寄存器的数量。" #: config/rx/elf.opt:44 config/rx/rx.opt:105 #, no-c-format @@ -11662,7 +11631,7 @@ msgstr "启用使用 RX FPU 指令。这是默认值。" #: config/rx/rx.opt:50 #, no-c-format msgid "Specify the target RX cpu type." -msgstr "选择目标 RX CPU 的类型" +msgstr "指定目标 RX CPU 的类型。" #: config/rx/rx.opt:71 #, no-c-format @@ -12915,7 +12884,7 @@ msgstr "为缺少 MMU 和 FPU 的 SH4 400 系列生成代码" #: config/sh/sh.opt:122 #, no-c-format msgid "Generate code for SH4 500 series (FPU-less)." -msgstr "为缺少 FPU 的 SH4 500 系列生成代码" +msgstr "为缺少 FPU 的 SH4 500 系列生成代码。" #: config/sh/sh.opt:127 #, fuzzy, no-c-format @@ -15236,7 +15205,7 @@ msgstr "在调试转储中不输出前一条和后一条指令号码" #: common.opt:1559 #, no-c-format msgid "Enable CFI tables via GAS assembler directives." -msgstr "用 GAS 汇编指示来启用 CFI 表" +msgstr "用 GAS 汇编指示来启用 CFI 表。" #: common.opt:1563 #, fuzzy, no-c-format @@ -16639,7 +16608,7 @@ msgstr "将条件存储转换为非条件存储" #: common.opt:2922 #, no-c-format msgid "Perform conversions of switch initializations." -msgstr "转换开关初始化" +msgstr "转换开关初始化。" #: common.opt:2926 #, fuzzy, no-c-format @@ -18413,7 +18382,7 @@ msgstr "" #: params.opt:950 #, no-c-format msgid "The minimal probability of speculation success (in percents), so that speculative insn will be scheduled." -msgstr "以百分比表示的投机成功的最小概率,影响对投机指令的调度" +msgstr "以百分比表示的投机成功的最小概率,影响对投机指令的调度。" #: params.opt:954 #, no-c-format @@ -20615,8 +20584,7 @@ msgstr "使用‘%%&’ 时没有指定任何动态 TLS 引用" msgid "invalid %%J value" msgstr "无效 %%J 值" -#: config/alpha/alpha.cc:5169 config/ia64/ia64.cc:5578 -#: config/or1k/or1k.cc:1249 +#: config/alpha/alpha.cc:5169 config/ia64/ia64.cc:5578 config/or1k/or1k.cc:1249 #, c-format msgid "invalid %%r value" msgstr "无效 %%r 值" @@ -20801,8 +20769,7 @@ msgstr "代码‘%c’的操作数无效" #: config/arm/arm.cc:24675 config/arm/arm.cc:24702 config/arm/arm.cc:24709 #: config/bfin/bfin.cc:1441 config/bfin/bfin.cc:1448 config/bfin/bfin.cc:1455 #: config/bfin/bfin.cc:1462 config/bfin/bfin.cc:1471 config/bfin/bfin.cc:1478 -#: config/bfin/bfin.cc:1485 config/bfin/bfin.cc:1492 -#: config/nds32/nds32.cc:3546 +#: config/bfin/bfin.cc:1485 config/bfin/bfin.cc:1492 config/nds32/nds32.cc:3546 #, c-format msgid "invalid operand for code '%c'" msgstr "代码‘%c’的操作数无效" @@ -22097,9 +22064,9 @@ msgstr "({匿名})" #: c/c-parser.cc:20351 c/gimple-parser.cc:406 c/gimple-parser.cc:447 #: c/gimple-parser.cc:456 c/gimple-parser.cc:665 c/gimple-parser.cc:2261 #: c/gimple-parser.cc:2298 c/gimple-parser.cc:2377 c/gimple-parser.cc:2404 -#: c/c-parser.cc:3671 c/c-parser.cc:3861 c/c-parser.cc:3896 -#: c/c-parser.cc:12051 c/gimple-parser.cc:2069 c/gimple-parser.cc:2126 -#: cp/parser.cc:15350 cp/parser.cc:33084 cp/parser.cc:33720 +#: c/c-parser.cc:3671 c/c-parser.cc:3861 c/c-parser.cc:3896 c/c-parser.cc:12051 +#: c/gimple-parser.cc:2069 c/gimple-parser.cc:2126 cp/parser.cc:15350 +#: cp/parser.cc:33084 cp/parser.cc:33720 #, gcc-internal-format msgid "expected %<;%>" msgstr "需要%<;%>" @@ -22151,8 +22118,8 @@ msgstr "需要 %<;%>、%<,%> 或 %<)%>" msgid "expected %<(%>" msgstr "需要%<(%>" -#: c/c-parser.cc:5444 c/c-parser.cc:5446 c/c-parser.cc:13856 -#: cp/parser.cc:33735 cp/parser.cc:37503 go/gofrontend/embed.cc:439 +#: c/c-parser.cc:5444 c/c-parser.cc:5446 c/c-parser.cc:13856 cp/parser.cc:33735 +#: cp/parser.cc:37503 go/gofrontend/embed.cc:439 #, gcc-internal-format msgid "expected %<[%>" msgstr "需要%<[%>" @@ -22160,8 +22127,8 @@ msgstr "需要%<[%>" #: c/c-parser.cc:6099 c/c-parser.cc:12394 c/c-parser.cc:19377 #: c/c-parser.cc:19463 c/c-parser.cc:20121 c/c-parser.cc:20993 #: c/c-parser.cc:24656 c/gimple-parser.cc:399 c/gimple-parser.cc:2337 -#: c/c-parser.cc:3658 c/c-parser.cc:3885 c/c-parser.cc:11946 -#: cp/parser.cc:21039 cp/parser.cc:33729 go/gofrontend/embed.cc:370 +#: c/c-parser.cc:3658 c/c-parser.cc:3885 c/c-parser.cc:11946 cp/parser.cc:21039 +#: cp/parser.cc:33729 go/gofrontend/embed.cc:370 #, gcc-internal-format msgid "expected %<{%>" msgstr "需要%<{%>" @@ -24658,27 +24625,26 @@ msgstr "类型属性在定义后被忽略" #: c-family/c-attribs.cc:5812 c-family/c-common.cc:6056 #: c-family/c-common.cc:6059 config/darwin.cc:2143 config/arm/arm.cc:7444 #: config/arm/arm.cc:7472 config/arm/arm.cc:7489 config/avr/avr.cc:10158 -#: config/csky/csky.cc:6498 config/csky/csky.cc:6520 -#: config/h8300/h8300.cc:4968 config/h8300/h8300.cc:4992 -#: config/i386/i386-options.cc:3434 config/i386/i386-options.cc:3592 -#: config/i386/i386-options.cc:3824 config/i386/i386-options.cc:3854 -#: config/ia64/ia64.cc:785 config/loongarch/loongarch.cc:6539 -#: config/rs6000/rs6000.cc:20476 ada/gcc-interface/utils.cc:6588 -#: ada/gcc-interface/utils.cc:6604 ada/gcc-interface/utils.cc:6642 -#: ada/gcc-interface/utils.cc:6659 ada/gcc-interface/utils.cc:6676 -#: ada/gcc-interface/utils.cc:6691 ada/gcc-interface/utils.cc:6707 -#: ada/gcc-interface/utils.cc:6733 ada/gcc-interface/utils.cc:6802 -#: ada/gcc-interface/utils.cc:6829 ada/gcc-interface/utils.cc:6850 -#: ada/gcc-interface/utils.cc:6871 ada/gcc-interface/utils.cc:6919 -#: ada/gcc-interface/utils.cc:6935 ada/gcc-interface/utils.cc:6990 -#: c/c-decl.cc:4788 c/c-decl.cc:4791 c/c-decl.cc:4806 c/c-parser.cc:5433 -#: cp/tree.cc:5032 d/d-attribs.cc:480 d/d-attribs.cc:699 d/d-attribs.cc:720 -#: d/d-attribs.cc:736 d/d-attribs.cc:753 d/d-attribs.cc:785 d/d-attribs.cc:914 -#: d/d-attribs.cc:973 d/d-attribs.cc:989 d/d-attribs.cc:1005 -#: d/d-attribs.cc:1154 d/d-attribs.cc:1167 d/d-attribs.cc:1384 -#: d/d-attribs.cc:1402 d/d-attribs.cc:1449 d/d-attribs.cc:1487 -#: d/d-attribs.cc:1503 d/d-attribs.cc:1560 d/d-attribs.cc:1588 -#: jit/dummy-frontend.cc:185 lto/lto-lang.cc:288 +#: config/csky/csky.cc:6498 config/csky/csky.cc:6520 config/h8300/h8300.cc:4968 +#: config/h8300/h8300.cc:4992 config/i386/i386-options.cc:3434 +#: config/i386/i386-options.cc:3592 config/i386/i386-options.cc:3824 +#: config/i386/i386-options.cc:3854 config/ia64/ia64.cc:785 +#: config/loongarch/loongarch.cc:6539 config/rs6000/rs6000.cc:20476 +#: ada/gcc-interface/utils.cc:6588 ada/gcc-interface/utils.cc:6604 +#: ada/gcc-interface/utils.cc:6642 ada/gcc-interface/utils.cc:6659 +#: ada/gcc-interface/utils.cc:6676 ada/gcc-interface/utils.cc:6691 +#: ada/gcc-interface/utils.cc:6707 ada/gcc-interface/utils.cc:6733 +#: ada/gcc-interface/utils.cc:6802 ada/gcc-interface/utils.cc:6829 +#: ada/gcc-interface/utils.cc:6850 ada/gcc-interface/utils.cc:6871 +#: ada/gcc-interface/utils.cc:6919 ada/gcc-interface/utils.cc:6935 +#: ada/gcc-interface/utils.cc:6990 c/c-decl.cc:4788 c/c-decl.cc:4791 +#: c/c-decl.cc:4806 c/c-parser.cc:5433 cp/tree.cc:5032 d/d-attribs.cc:480 +#: d/d-attribs.cc:699 d/d-attribs.cc:720 d/d-attribs.cc:736 d/d-attribs.cc:753 +#: d/d-attribs.cc:785 d/d-attribs.cc:914 d/d-attribs.cc:973 d/d-attribs.cc:989 +#: d/d-attribs.cc:1005 d/d-attribs.cc:1154 d/d-attribs.cc:1167 +#: d/d-attribs.cc:1384 d/d-attribs.cc:1402 d/d-attribs.cc:1449 +#: d/d-attribs.cc:1487 d/d-attribs.cc:1503 d/d-attribs.cc:1560 +#: d/d-attribs.cc:1588 jit/dummy-frontend.cc:185 lto/lto-lang.cc:288 #, gcc-internal-format msgid "%qE attribute ignored" msgstr "%qE属性被忽略" @@ -26135,7 +26101,7 @@ msgstr "无法获取程序状态:%s" #: collect-utils.cc:120 #, gcc-internal-format, gfc-internal-format msgid "%s terminated with signal %d [%s]%s" -msgstr "%s 以信号 %d [%s]%s 退出。" +msgstr "%s 以信号 %d [%s]%s 退出" #: collect-utils.cc:136 #, gcc-internal-format, gfc-internal-format @@ -26731,7 +26697,7 @@ msgstr "在比较周围组合变量时假定有符号数从不溢出" #: fold-const.cc:13568 #, gcc-internal-format msgid "fold check: original tree changed by fold" -msgstr "折叠检查: 原始树因折叠而改变 " +msgstr "折叠检查: 原始树因折叠而改变" #: function.cc:253 #, fuzzy, gcc-internal-format @@ -34471,8 +34437,7 @@ msgstr "线程局部的 COMMON 数据没有实现" msgid "requested alignment for %q+D is greater than implemented alignment of %wu" msgstr "%q+D需要的对齐边界大于实现的对齐边界 %wu" -#: varasm.cc:2304 c/c-decl.cc:5725 c/c-parser.cc:1789 -#: m2/gm2-gcc/m2type.cc:1259 +#: varasm.cc:2304 c/c-decl.cc:5725 c/c-parser.cc:1789 m2/gm2-gcc/m2type.cc:1259 #, gcc-internal-format msgid "storage size of %q+D isn%'t known" msgstr "%q+D的存储大小未知" @@ -34892,9 +34857,8 @@ msgstr "%qE属性需要一个字符串常量作为实参" msgid "section attribute cannot be specified for local variables" msgstr "不能为局部变量指定节属性" -#: c-family/c-attribs.cc:2284 config/bfin/bfin.cc:4796 -#: config/bfin/bfin.cc:4847 config/bfin/bfin.cc:4873 config/bfin/bfin.cc:4886 -#: d/d-attribs.cc:1055 +#: c-family/c-attribs.cc:2284 config/bfin/bfin.cc:4796 config/bfin/bfin.cc:4847 +#: config/bfin/bfin.cc:4873 config/bfin/bfin.cc:4886 d/d-attribs.cc:1055 #, gcc-internal-format msgid "section of %q+D conflicts with previous declaration" msgstr "%q+D的节与早先的声明冲突" @@ -38904,8 +38868,7 @@ msgstr "-malign-functions=%d 不在 0 和 %d 之间" msgid "%<-mbranch-cost=%d%> is not between 0 and 5" msgstr "%sbranch-cost=%d%s不在 0 和 5 之间" -#: common/config/i386/i386-common.cc:1873 -#: common/config/s390/s390-common.cc:137 +#: common/config/i386/i386-common.cc:1873 common/config/s390/s390-common.cc:137 #, gcc-internal-format msgid "%<-fsplit-stack%> currently only supported on GNU/Linux" msgstr "%<-fsplit-stack%>只在 GNU/Linux 下被支持" @@ -40239,8 +40202,8 @@ msgstr "L%d 缓存延迟未知,对 %s 来说" msgid "bad value %qs for %<-mmemory-latency%>" msgstr "-mmemory-latency 开关的值%qs错误" -#: config/alpha/alpha.cc:6657 config/alpha/alpha.cc:6660 -#: config/arc/arc.cc:7099 config/arc/arc.cc:7373 config/s390/s390.cc:949 +#: config/alpha/alpha.cc:6657 config/alpha/alpha.cc:6660 config/arc/arc.cc:7099 +#: config/arc/arc.cc:7373 config/s390/s390.cc:949 #, gcc-internal-format msgid "bad builtin fcode" msgstr "错误的内建 fcode" @@ -43254,14 +43217,12 @@ msgstr "%qs属性只能应用于函数" msgid "%qE cannot have both %qs and %qs attributes" msgstr "%qE不能同时有%<mips16%>和%<nomips16%>属性" -#: config/mips/mips.cc:1475 config/mips/mips.cc:1481 -#: config/nios2/nios2.cc:4487 +#: config/mips/mips.cc:1475 config/mips/mips.cc:1481 config/nios2/nios2.cc:4487 #, gcc-internal-format msgid "%qE redeclared with conflicting %qs attributes" msgstr "%qE重声明有冲突的属性%qs" -#: config/mips/mips.cc:1513 config/mips/mips.cc:1567 -#: config/riscv/riscv.cc:4022 +#: config/mips/mips.cc:1513 config/mips/mips.cc:1567 config/riscv/riscv.cc:4022 #, fuzzy, gcc-internal-format #| msgid "%qE attribute requires a string constant argument" msgid "%qE attribute requires a string argument" @@ -45355,7 +45316,7 @@ msgstr "%qE属性的实参不是一个字符串常量" #: config/s390/s390.cc:10240 #, gcc-internal-format msgid "total size of local variables exceeds architecture limit" -msgstr "局部变量大小总和超过架构极限。" +msgstr "局部变量大小总和超过架构极限" #: config/s390/s390.cc:11647 #, fuzzy, gcc-internal-format @@ -47970,8 +47931,8 @@ msgstr "需要行尾" msgid "ISO C forbids an empty translation unit" msgstr "ISO C 不允许翻译单元为空" -#: c/c-parser.cc:1796 c/c-parser.cc:1805 c/c-parser.cc:23171 -#: cp/parser.cc:47460 cp/semantics.cc:3400 cp/semantics.cc:3409 +#: c/c-parser.cc:1796 c/c-parser.cc:1805 c/c-parser.cc:23171 cp/parser.cc:47460 +#: cp/semantics.cc:3400 cp/semantics.cc:3409 #, gcc-internal-format msgid "%qs without corresponding %qs" msgstr "" @@ -49361,8 +49322,7 @@ msgstr "%H折叠变量需要正整常数表达式" msgid "%<iterator%> modifier incompatible with %qs" msgstr "%qs必须与%qs一起使用" -#: c/c-parser.cc:16994 cp/parser.cc:40371 cp/parser.cc:40760 -#: cp/parser.cc:40810 +#: c/c-parser.cc:16994 cp/parser.cc:40371 cp/parser.cc:40760 cp/parser.cc:40810 #, fuzzy, gcc-internal-format msgid "invalid depend kind" msgstr "无效的调度类型" @@ -49634,8 +49594,8 @@ msgstr "联合定义后需要%<;%>" msgid "expected %<==%>, %<<%> or %<>%> comparison in %<if%> condition" msgstr "" -#: c/c-parser.cc:19446 cp/parser.cc:42128 cp/parser.cc:42411 -#: cp/parser.cc:42505 cp/parser.cc:42523 +#: c/c-parser.cc:19446 cp/parser.cc:42128 cp/parser.cc:42411 cp/parser.cc:42505 +#: cp/parser.cc:42523 #, fuzzy, gcc-internal-format msgid "invalid form of %<#pragma omp atomic compare%>" msgstr "%<#pragma omp atomic%>运算符无效" @@ -50583,7 +50543,7 @@ msgstr "要求全局寄存器变量%qD的地址" #: c/c-typeck.cc:5233 d/d-codegen.cc:721 #, gcc-internal-format msgid "address of register variable %qD requested" -msgstr "要求寄存器变量%qD的地址。" +msgstr "要求寄存器变量 %qD 的地址" #: c/c-typeck.cc:5372 #, gcc-internal-format @@ -51224,8 +51184,7 @@ msgstr "初始值设定项末尾有多余的花括号组" msgid "braces around scalar initializer" msgstr "标量初始化带花括号" -#: c/c-typeck.cc:9291 c/c-typeck.cc:10775 cp/typeck2.cc:1242 -#: cp/typeck2.cc:1600 +#: c/c-typeck.cc:9291 c/c-typeck.cc:10775 cp/typeck2.cc:1242 cp/typeck2.cc:1600 #, gcc-internal-format msgid "initialization of flexible array member in a nested context" msgstr "在嵌套的上下文中初始化可变数组成员" @@ -53212,7 +53171,7 @@ msgstr "备选 2: %q+#F" #: cp/call.cc:13226 #, gcc-internal-format msgid "ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:" -msgstr "ISO C++ 认为有歧义,尽管第一个备选的最差类型转换要好于第二个备选的最差类型转换" +msgstr "ISO C++ 认为有歧义,尽管第一个备选的最差类型转换要好于第二个备选的最差类型转换:" #: cp/call.cc:13627 #, fuzzy, gcc-internal-format @@ -54201,8 +54160,8 @@ msgstr "成员%qD是未初始化的引用" msgid "%qs cannot be constant evaluated because the argument cannot be interpreted" msgstr "" -#: cp/constexpr.cc:5632 cp/constexpr.cc:7723 -#: rust/backend/rust-constexpr.cc:872 rust/backend/rust-constexpr.cc:2492 +#: cp/constexpr.cc:5632 cp/constexpr.cc:7723 rust/backend/rust-constexpr.cc:872 +#: rust/backend/rust-constexpr.cc:2492 #, fuzzy, gcc-internal-format #| msgid "dereferencing %<void *%> pointer" msgid "dereferencing a null pointer" @@ -82565,9 +82524,9 @@ msgid "The base procedure at %L must have an explicit interface" msgstr "%3$L处 %2$s 中的过程‘%1$s’没有显式接口" #: fortran/trans-openmp.cc:8043 -#, fuzzy, gcc-internal-format +#, gcc-internal-format msgid "Cannot find symbol %qs" -msgstr "在类%qs中找不到可溢出的寄存器" +msgstr "无法找到符号 %qs" #: fortran/trans-openmp.cc:8054 #, fuzzy, gcc-internal-format @@ -82679,7 +82638,7 @@ msgstr "gfc_trans_code():错误的语句代码" #: go/gofrontend/embed.cc:278 #, gcc-internal-format msgid "invalid embedcfg: not a JSON object" -msgstr "" +msgstr "无效的 embedcfg:不是 JSON 对象" #: go/gofrontend/embed.cc:285 #, fuzzy, gcc-internal-format @@ -82695,7 +82654,7 @@ msgstr "" #: go/gofrontend/embed.cc:297 #, gcc-internal-format msgid "invalid embedcfg: missing Files" -msgstr "" +msgstr "无效的 embedcfg:缺失文件" #: go/gofrontend/embed.cc:302 #, gcc-internal-format @@ -82766,8 +82725,7 @@ msgid "extraneous data at end of file" msgstr "初始值设定项末尾有多余的花括号组" #: go/gofrontend/embed.cc:645 -#, fuzzy, gcc-internal-format -#| msgid "Unexpected EOF" +#, gcc-internal-format msgid "unexpected EOF" msgstr "非预期的文件结束" @@ -83496,9 +83454,9 @@ msgid "nullability specifier %qE cannot be applied to multi-level pointer type % msgstr "" #: objc/objc-act.cc:1778 -#, fuzzy, gcc-internal-format +#, gcc-internal-format msgid "the dot syntax is not available in Objective-C 1.0" -msgstr "%<@synthesize%> 在 Objective-C 1.0 里不可用" +msgstr "点语法在 Objective-C 1.0 中不可用" #. We know that 'class_name' is an Objective-C class name as the #. parser won't call this function if it is not. This is only a @@ -83515,15 +83473,14 @@ msgid "could not find interface for class %qE" msgstr "找不到类%qE的接口" #: objc/objc-act.cc:1808 objc/objc-act.cc:7144 -#, fuzzy, gcc-internal-format -#| msgid "%qD is not a variable" +#, gcc-internal-format msgid "class %qE is unavailable" -msgstr "%qD不是一个变量" +msgstr "类 %qE 不可用" #: objc/objc-act.cc:1810 objc/objc-act.cc:7001 objc/objc-act.cc:7146 #, gcc-internal-format msgid "class %qE is deprecated" -msgstr "已弃用类%qE" +msgstr "已弃用类 %qE" #: objc/objc-act.cc:1839 #, gcc-internal-format @@ -84001,15 +83958,14 @@ msgid "cannot find interface declaration for %qE, superclass of %qE" msgstr "找不到%2$qE超类%1$qE的接口声明" #: objc/objc-act.cc:6999 -#, fuzzy, gcc-internal-format -#| msgid "%qD is not a variable" +#, gcc-internal-format msgid "class %qE is not available" -msgstr "%qD不是一个变量" +msgstr "类 %qE 不可用" #: objc/objc-act.cc:7032 #, gcc-internal-format msgid "reimplementation of class %qE" -msgstr "类%qE的重新实现" +msgstr "类 %qE 的重新实现" #: objc/objc-act.cc:7065 #, gcc-internal-format @@ -84137,10 +84093,9 @@ msgid "definition of protocol %qE not found" msgstr "找不到协议%qE的方法定义" #: objc/objc-act.cc:8272 -#, fuzzy, gcc-internal-format -#| msgid "protocol %qE is deprecated" +#, gcc-internal-format msgid "protocol %qE is unavailable" -msgstr "已弃用协议%qE" +msgstr "协议 %qE 不可用" #. It would be nice to use warn_deprecated_use() here, but #. we are using TREE_CHAIN (which is supposed to be the diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 9a1a3c8..4ccb86e 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -435,8 +435,10 @@ update_known_bitmask (irange &r, tree_code code, bit_value_unop (code, sign, prec, &widest_value, &widest_mask, TYPE_SIGN (lh.type ()), TYPE_PRECISION (lh.type ()), - widest_int::from (lh_bits.value (), sign), - widest_int::from (lh_bits.mask (), sign)); + widest_int::from (lh_bits.value (), + TYPE_SIGN (lh.type ())), + widest_int::from (lh_bits.mask (), + TYPE_SIGN (lh.type ()))); break; case GIMPLE_BINARY_RHS: bit_value_binop (code, sign, prec, &widest_value, &widest_mask, diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index a834a8f..f1220b0 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,842 @@ +2024-01-30 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-full-decls.h + (class TraitImplItem): Remove forward declaration. + (class AssociatedItem): Add forward declaration. + * ast/rust-ast.h + (class TraitImplItem): Remove. + (class TraitItem): Inherit from AssociatedItem. + (SingleASTNode::take_trait_impl_item): + Return std::unique_ptr<AssociatedItem> instead of + std::unique_ptr<TraitImplItem>. + * ast/rust-item.h + (class Function): Inherit from AssociatedItem instead of + TraitImplItem. + (class TypeAlias): Likewise. + (class ConstantItem): Likewise. + (class TraitImpl): Store items as AssociatedItem. + * expand/rust-derive-clone.cc + (DeriveClone::clone_fn): Return std::unique_ptr<AssociatedItem>. + (DeriveClone::clone_impl): Take std::unique_ptr<AssociatedItem>. + * expand/rust-derive-clone.h + (DeriveClone::clone_fn): Return std::unique_ptr<AssociatedItem>. + (DeriveClone::clone_impl): Take std::unique_ptr<AssociatedItem>. + * expand/rust-expand-visitor.cc + (ExpandVisitor::visit): Handle changes to + SingleASTNode::take_trait_impl_item. + * parse/rust-parse-impl.h + (Parser::parse_impl): Parse TraitImpl as containing AssociatedItem. + (Parser::parse_trait_impl_item): Return + std::unique_ptr<AssociatedItem>. + (Parser::parse_trait_impl_function_or_method): Likewise. + * parse/rust-parse.h + (Parser::parse_trait_impl_item): Return + std::unique_ptr<AssociatedItem>. + (Parser::parse_trait_impl_function_or_method): Likewise. + +2024-01-30 Robert Goss <goss.robert@gmail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit) Add additional check + * typecheck/rust-hir-type-check-struct-field.h: A helper method to make error added + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::resolve) Update message + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * hir/rust-ast-lower-type.cc (ASTLoweringTypeBounds::visit): fix for lifetimes + (ASTLowerWhereClauseItem::visit): fix for lifetimes + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * parse/rust-parse-impl.h (Parser::parse_where_clause): fix parsing + (Parser::parse_where_clause_item): fix parsing + (Parser::parse_type_bound_where_clause_item): fix parsing + (Parser::parse_trait_bound): fix parsing + * parse/rust-parse.h: fix parsing + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * lex/rust-lex.cc (Lexer::dump_and_skip): + Changed " " to '\n' + +2024-01-30 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-fragment.cc + (Fragment::assert_single_fragment): Update. + * ast/rust-ast.h + (class TraitImplItem): Move definition before that of TraitItem. + (class TraitItem): + Inherit from TraitImplItem instead of AssociatedItem. + (class SingleASTNode): Unify handling of associated items. + (SingleASTNode::take_assoc_item): Move from... + (SingleASTNode::take_impl_item): ...here, but leave stub calling + take_assoc_item behind. + (SingleASTNode::take_trait_item): + Cast associated item to TraitItem. + (SingleASTNode::take_trait_impl_item): + Cast associated item to TraitImplItem. + * ast/rust-ast.cc + (SingleASTNode::SingleASTNode): + Unify handling of associated items. + (SingleASTNode::operator=): Likewise. + (SingleASTNode::accept_vis): Likewise. + (SingleASTNode::is_error): Likewise. + (SingleASTNode::as_string): Likewise. + * ast/rust-item.h + (class Function): Remove direct inheritence from AssociatedItem. + (class ConstantItem): Likewise. + * ast/rust-macro.h + (class MacroInvocation): + Remove direct inheritence from AssociatedItem and TraitImplItem. + +2024-01-30 Robert Goss <goss.robert@gmail.com> + + * typecheck/rust-hir-type-check-struct-field.h: Allow visit to return a bool + * typecheck/rust-hir-type-check-struct.cc: Improve check of repeat fields + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * parse/rust-parse-impl.h (Parser::parse_inherent_impl_item): + Added switch-case for ASYNC token. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): + Enclose const in single quotes. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): + Added check for `async` functions inside trait. + * parse/rust-parse-impl.h (Parser::parse_trait_item): + Added switch-case for ASYNC token. + +2024-01-30 Nirmal Patel <nirmal@nirmal.dev> + + * lex/rust-lex.cc (Lexer::parse_byte_string): Handle newline + while parsing byte strings + (Lexer::parse_string): Handle newline while parsing strings + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): Use new API. + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Use new API. + * typecheck/rust-tyty-cmp.h: Remove old API. + * typecheck/rust-tyty.cc (FnPtr::is_equal): Use new API. + * typecheck/rust-tyty.h: Remove old API. + * typecheck/rust-unify.cc (UnifyRules::expect_fnptr): Use new API. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * hir/rust-ast-lower-type.cc (ASTLoweringType::visit): For lifetimes. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_lifetime): Propagate static + requirement. + * hir/rust-ast-lower-base.h: Propagate static requirement. + * hir/rust-ast-lower-implitem.h: Propagate static requirement. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Propagate static requirement. + * hir/rust-ast-lower-type.cc (ASTLoweringType::translate): Propagate static requirement. + (ASTLoweringType::visit): Propagate static requirement. + * hir/rust-ast-lower-type.h: Propagate static requirement. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * parse/rust-parse-impl.h (Parser::parse_generic_param): Lifetime elision control. + (Parser::parse_lifetime_where_clause_item): Lifetime elision control. + (Parser::parse_type_param_bound): Lifetime elision control. + (Parser::parse_lifetime_bounds): Lifetime elision control. + (Parser::parse_lifetime): Lifetime elision control. + (Parser::parse_path_generic_args): Lifetime elision control. + (Parser::parse_self_param): Lifetime elision control. + (Parser::parse_break_expr): Lifetime elision control. + (Parser::parse_continue_expr): Lifetime elision control. + (Parser::parse_reference_type_inner): Lifetime elision control. + * parse/rust-parse.h: Lifetime elision control. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * ast/rust-ast.h: Elided lifetime static constructor + * ast/rust-type.h: Default lifetime to elided. + * parse/rust-parse-impl.h (Parser::parse_lifetime_param): Use elided lifetime. + (Parser::parse_lifetime): Use elided lifetime/ + (Parser::lifetime_from_token): Use elided lifetime. + (Parser::parse_self_param): Use elided lifetime. + (Parser::parse_reference_type_inner): Use elided lifetime. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * parse/rust-parse-impl.h (Parser::lifetime_from_token): Fix matched pattern. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): + Added check for `async` function inside trait. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * parse/rust-parse-impl.h (Parser::parse_trait_impl_item): + Handled `async` items + +2024-01-30 Raiki Tamura <tamaron1203@gmail.com> + + * Make-lang.in: Add .o files + * backend/rust-mangle.cc (struct V0Path): moved to splitted files + (v0_path): Likewise. + (legacy_mangle_name): Likewise. + (legacy_mangle_canonical_path): Likewise. + (legacy_hash): Likewise. + (v0_tuple_prefix): Likewise. + (v0_numeric_prefix): Likewise. + (v0_simple_type_prefix): Likewise. + (v0_complex_type_prefix): Likewise. + (v0_integer_62): Likewise. + (v0_opt_integer_62): Likewise. + (v0_disambiguator): Likewise. + (v0_type_prefix): Likewise. + (v0_generic_args): Likewise. + (v0_identifier): Likewise. + (v0_type_path): Likewise. + (v0_function_path): Likewise. + (v0_scope_path): Likewise. + (v0_crate_path): Likewise. + (v0_inherent_or_trait_impl_path): Likewise. + (v0_closure): Likewise. + (legacy_mangle_item): Likewise. + (v0_mangle_item): Likewise. + * backend/rust-mangle.h (legacy_mangle_item): Likewise. + (v0_mangle_item): Likewise. + * backend/rust-mangle-legacy.cc: New file. + * backend/rust-mangle-v0.cc: New file. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * checks/errors/borrowck/rust-bir-place.h: Cleanup. + * checks/errors/borrowck/rust-borrow-checker.h: Cleanup. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * typecheck/rust-tyty.h (BaseType::is): Cast API. + (SubstitutionRef>): Cast API. + (BaseType::as): Cast API. + (BaseType::try_as): Cast API. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * typecheck/rust-tyty.h (class ClosureType): Inherit interface. + (class FnPtr): Inherit interface. + (class FnType): Inherit interface. + (class CallableTypeInterface): New interface. + (BaseType::is): Detect interface members API. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path): Refactor. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * checks/errors/borrowck/rust-bir-builder-internal.h: Replace nodiscard. + * checks/errors/borrowck/rust-bir-place.h: Replace nodiscard. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * typecheck/rust-tyty.h: Fix nodiscard to warn unused. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * hir/tree/rust-hir-item.h: Ad lifetime getter. + * hir/tree/rust-hir-path.h: Make getter const ref. + * hir/tree/rust-hir.h: Const ref and new getter. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in (GRS_OBJS): Add rust-attribs.o. + * backend/rust-builtins.cc (builtin_const, builtin_noreturn) + (builtin_novops): Remove. + (BuiltinsContext::lookup_simple_builtin): Adjust. + (BuiltinsContext::setup_overflow_fns): Remove. + (BuiltinsContext::define_function_type): Set builtin type to + errormark so the builtin is considered unavailable. + (BuiltinsContext::setup_math_fns): Remove. + (BuiltinsContext::setup_atomic_fns): Remove. + (build_c_type_nodes): Refactor based on D frontend. + (BuiltinsContext::define_builtin_types): Likewise. + (DEF_PRIMITIVE_TYPE): New. + (DEF_FUNCTION_TYPE_0): New. + (DEF_FUNCTION_TYPE_1): New. + (DEF_FUNCTION_TYPE_2): New. + (DEF_FUNCTION_TYPE_3): New. + (DEF_FUNCTION_TYPE_4): New. + (DEF_FUNCTION_TYPE_5): New. + (DEF_FUNCTION_TYPE_6): New. + (DEF_FUNCTION_TYPE_7): New. + (DEF_FUNCTION_TYPE_8): New. + (DEF_FUNCTION_TYPE_9): New. + (DEF_FUNCTION_TYPE_10): New. + (DEF_FUNCTION_TYPE_11): New. + (DEF_FUNCTION_TYPE_VAR_0): New. + (DEF_FUNCTION_TYPE_VAR_1): New. + (DEF_FUNCTION_TYPE_VAR_2): New. + (DEF_FUNCTION_TYPE_VAR_3): New. + (DEF_FUNCTION_TYPE_VAR_4): New. + (DEF_FUNCTION_TYPE_VAR_5): New. + (DEF_FUNCTION_TYPE_VAR_6): New. + (DEF_FUNCTION_TYPE_VAR_7): New. + (DEF_FUNCTION_TYPE_VAR_11): New. + (DEF_POINTER_TYPE): New. + (BuiltinsContext::setup): Adjust. + (BuiltinsContext::define_builtin_attributes): New. + (DEF_ATTR_NULL_TREE): New. + (DEF_ATTR_INT): New. + (DEF_ATTR_STRING): New. + (DEF_ATTR_IDENT): New. + (DEF_ATTR_TREE_LIST): New. + (handle_flags): Remove. + (BuiltinsContext::define_builtins): New. + (DEF_BUILTIN): New. + (BuiltinsContext::define_builtin): Remove. + (BuiltinsContext::register_rust_mappings): New. Add all missing + builtins. + (BuiltinsContext::lookup_gcc_builtin): Adjust. + * backend/rust-builtins.h (DEF_PRIMITIVE_TYPE): New. + (DEF_FUNCTION_TYPE_0): New. + (DEF_FUNCTION_TYPE_1): New. + (DEF_FUNCTION_TYPE_2): New. + (DEF_FUNCTION_TYPE_3): New. + (DEF_FUNCTION_TYPE_4): New. + (DEF_FUNCTION_TYPE_5): New. + (DEF_FUNCTION_TYPE_6): New. + (DEF_FUNCTION_TYPE_7): New. + (DEF_FUNCTION_TYPE_8): New. + (DEF_FUNCTION_TYPE_9): New. + (DEF_FUNCTION_TYPE_10): New. + (DEF_FUNCTION_TYPE_11): New. + (DEF_FUNCTION_TYPE_VAR_0): New. + (DEF_FUNCTION_TYPE_VAR_1): New. + (DEF_FUNCTION_TYPE_VAR_2): New. + (DEF_FUNCTION_TYPE_VAR_3): New. + (DEF_FUNCTION_TYPE_VAR_4): New. + (DEF_FUNCTION_TYPE_VAR_5): New. + (DEF_FUNCTION_TYPE_VAR_6): New. + (DEF_FUNCTION_TYPE_VAR_7): New. + (DEF_FUNCTION_TYPE_VAR_11): New. + (DEF_POINTER_TYPE): New. + (DEF_ATTR_NULL_TREE): New. + (DEF_ATTR_INT): New. + (DEF_ATTR_STRING): New. + (DEF_ATTR_IDENT): New. + (DEF_ATTR_TREE_LIST): New. + * backend/rust-compile-intrinsic.cc (Intrinsics::compile): Add + comment. + (op_with_overflow_inner): Adjust. + (copy_handler_inner): Adjust. + (prefetch_data_handler): Adjust. + (build_atomic_builtin_name): Adjust. + (atomic_load_handler_inner): Adjust. + (uninit_handler): Adjust. + (move_val_init_handler): Adjust. + (expect_handler_inner): Adjust. + * rust-gcc.cc (fetch_overflow_builtins): Adjust. + * rust-lang.cc (rust_localize_identifier): Adjust. + (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): New. + * rust-attribs.cc: New file. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-cfg-strip.cc (CfgStrip::visit): Change calls from visitor + to default visitor. + (CfgStrip::go): Add call to visit crate. + * expand/rust-cfg-strip.h (class CfgStrip): Update prototypes and + remove empty ones. + * ast/rust-ast-visitor.cc: add WhereClause condition check. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-expand-visitor.cc (ExpandVisitor::go): Add call to visit + on the crate. + (ExpandVisitor::visit): Remove some visit functions in favor of their + default visitor counterpart. + * expand/rust-expand-visitor.h (class ExpandVisitor): Inherit from + default visitor and remove now useless function prototypes. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Remove + duplicated functions. + * resolve/rust-default-resolver.h (class DefaultResolver): Make the + default resolver inherit from the default visitor. + +2024-01-30 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/rust-feature.cc + (Feature::name_hash_map): + Add entries for Name::LANG_ITEMS and Name::NO_CORE. + * checks/errors/rust-feature.h + (Feature::Name::LANG_ITEMS): New. + (Feature::Name::NO_CORE): New. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::setup_abi_options): + Renamed `WIN64` to `WIN_64` + * util/rust-abi.cc (get_abi_from_string): Likewise + (get_string_from_abi): Likewise + * util/rust-abi.h (enum ABI): Likewise + +2024-01-30 Nobel Singh <nobel2073@gmail.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + check for const funtion. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + a validation check and emit an error depending on the context. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Adapt defintion + getter. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * expand/rust-cfg-strip.cc (CfgStrip::visit): Likewise. + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): Likewise. + * hir/rust-ast-lower-implitem.h: Likewise. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Likewise. + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Likewise. + * resolve/rust-ast-resolve-stmt.h: Likewise. + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Likewise. + * util/rust-attributes.cc (AttributeChecker::visit): Likewise. + * parse/rust-parse-impl.h: Allow empty function body during parsing. + * ast/rust-ast.cc (Function::Function): Constructor now take an + optional for the body. + (Function::operator=): Adapt to new optional member. + (Function::as_string): Likewise. + * ast/rust-item.h (class Function): Make body optional and do not + rely on nullptr anymore. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * resolve/rust-early-name-resolver.cc (EarlyNameResolver::resolve_generic_args): + Move function. + (EarlyNameResolver::resolve_qualified_path_type): Likewise. + (EarlyNameResolver::visit): Add a top level visit function for crate + and remove duplicated code. + * resolve/rust-early-name-resolver.h (class EarlyNameResolver): Update + overriden function list. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * util/rust-attributes.cc (AttributeChecker::visit): Add visit function + for crates. + * util/rust-attributes.h (class AttributeChecker): Update function + prototypes. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-feature-gate.cc (FeatureGate::visit): Add a visit + function for the crate level. + (FeatureGate::check): Add call to crate visit. + * checks/errors/rust-feature-gate.h (class FeatureGate): Remove now + useless visit functions (traversal only). + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + const check. + * checks/errors/rust-ast-validation.h: Add visit function prototype. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + async const check. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_vis_item): Allow parsing async + items in const. + (Parser::parse_async_item): Account for const offset during async + lookahead. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-builder.cc (AstBuilder::fn_qualifiers): Change + constructor to match the new arguments. + * ast/rust-ast-collector.cc (TokenCollector::visit): Change behavior + to handle both const and async specifiers at the same time. + * ast/rust-ast.cc (FunctionQualifiers::as_string): Likewise. + * ast/rust-item.h (class FunctionQualifiers): Remove AsyncConstStatus + and replace it with both Async and Const status. Also change the safety + arguments to use an enum instead of a boolean. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_qualifiers): + Update constructor call. + * hir/tree/rust-hir-item.h: Add Const and Async status, remove + AsyncConstStatus, update the constructor. + * hir/tree/rust-hir.cc (FunctionQualifiers::as_string): Update with + the new status. + * parse/rust-parse-impl.h (Parser::parse_function_qualifiers): Update + constructor call. + * util/rust-common.h (enum Mutability): Make an enum class. + (enum class): Add Async and Const enum class to avoid booleans. + (enum Unsafety): Change to an enum class. + +2024-01-30 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-full-decls.h + (class InherentImplItem): Remove. + * ast/rust-ast.h + (class InherentImplItem): Remove. + (class SingleASTNode): + Store pointer to AssociatedItem instead of InherentImplItem. + * ast/rust-ast.cc + (SingleASTNode::SingleASTNode): + Use clone_associated_item instead of clone_inherent_impl_item. + (SingleASTNode::operator=): Likewise. + * ast/rust-item.h + (class InherentImpl): + Use AssociatedItem rather than InherentImplItem. + (class Function): Likewise. + (class ConstantItem): Likewise. + * ast/rust-macro.h + (class MacroInvocation): Likewise. + * expand/rust-expand-visitor.cc + (ExpandVisitor::visit): Likewise. + * parse/rust-parse-impl.h + (Parser::parse_impl): Likewise. + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_inherent_impl_function_or_method): Likewise. + * parse/rust-parse.h + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_inherent_impl_function_or_method): Likewise. + +2024-01-30 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::compile_locals_for_block): removed + * backend/rust-compile-base.h: update header + * backend/rust-compile-block.cc (CompileBlock::visit): remove old logic + * backend/rust-compile-expr.cc (CompileExpr::generate_closure_function): likewise + * backend/rust-compile-stmt.cc (CompileStmt::visit): likewise + * backend/rust-compile-var-decl.h: ensure we setup tuple bindings correctly + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-item.h: Add safety getter to modules. + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Check + a module's safety and emit an error when meeting an unsafe module. + * checks/errors/rust-ast-validation.h: Add function prototype. + * parse/rust-parse-impl.h (Parser::parse_module): Move the module locus + to the first token instead of the mod keyword. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_vis_item): Dispatch to parse + module when meeting an unsafe module. + (Parser::parse_module): Set unsafe status when the parser encounter an + unsafe keyword. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-item.h: Add safety status to Modules in the AST. + * parse/rust-parse-impl.h (Parser::parse_module): Adapt constructors. + +2024-01-30 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/tree/rust-hir-pattern.h + (class TupleItems): New. + (class TupleStructItems): Inherit from TupleItems. + (class TuplePatternItems): Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::insert_or_error_out): New functions. + (TopLevel::handle_use_dec): New function. + (flatten_rebind): Likewise. + (flatten_list): Likewise. + (flatten_glob): Likewise. + (flatten): Likewise. + (TopLevel::visit): Visit various `use` declaration nodes. + * resolve/rust-toplevel-name-resolver-2.0.h: Declare functions and + visitors. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::visit): Remove visitors. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-item.h (class UseTree): Add `node_id` member. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::insert_or_error_out): Add documentation comment. + (TopLevel::go): Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc + (Early::insert_once): New function. + (Early::visit): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Store mappings + after having resolved them. + * resolve/rust-late-name-resolver-2.0.h: Add `TypePath` visitor. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc + (Late::setup_builtin_types): New function. + (Late::go): Setup builtin types. + * resolve/rust-late-name-resolver-2.0.h: + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::map_usage): New function. + * resolve/rust-name-resolution-context.h: Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-name-resolution-context.h: Store a reference to the + mappings. + * resolve/rust-name-resolution-context.cc + (NameResolutionContext::NameResolutionContext): Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Use + the DefaultResolver in the toplevel visitor. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile late name resolver. + * resolve/rust-late-name-resolver-2.0.cc: New file. + * resolve/rust-late-name-resolver-2.0.h: New file. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-name-resolution-context.h: Add a Labels stack. + +2024-01-30 M V V S Manoj Kumar <mvvsmanojkumar@gmail.com> + + * parse/rust-parse-impl.h (Parser::parse_item): Likewise. + (Parser::parse_vis_item): Likewise. + (Parser::parse_async_item): Likewise. + * parse/rust-parse.h: Made declaration for parse_async_item. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * lex/rust-lex.cc (Lexer::classify_keyword): Update keyword map name. + * lex/rust-token.h (enum PrimitiveCoreType): Remove some deprecated + comments. + * util/rust-keyword-values.cc (get_keywords): Update the keyword map + name. + (RS_TOKEN): Define as empty + (RS_TOKEN_KEYWORD_2015): Add the emission value. + (RS_TOKEN_KEYWORD_2018): Likewise. + * util/rust-keyword-values.h (RS_KEYWORD_LIST): Introduce the keyword + list. + (RS_TOKEN_KEYWORD_2018): Define multiple new keywords. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Replace raw value. + * parse/rust-parse-impl.h (Parser::is_macro_rules_def): Likewise. + (Parser::parse_item): Likewise. + (Parser::parse_vis_item): Likewise. + (Parser::parse_macro_rules_def): Likewise. + (Parser::parse_union): Likewise. + (Parser::parse_trait_impl_item): Likewise. + (Parser::parse_stmt): Likewise. + (Parser::parse_stmt_or_expr): Likewise. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * util/rust-keyword-values.h (class WeakKeywords): Add new class with + weak keyword constexpr. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Replace raw value + with keyword call. + * ast/rust-ast.h: Likewise. + * parse/rust-parse-impl.h (Parser::parse_path_ident_segment): Likewise. + (Parser::parse_macro_match_fragment): Likewise. + (Parser::parse_extern_crate): Likewise. + (Parser::parse_use_tree): Likewise. + (Parser::parse_const_item): Likewise. + (Parser::parse_literal_expr): Likewise. + (Parser::parse_maybe_named_param): Likewise. + (Parser::parse_pattern_no_alt): Likewise. + (Parser::left_denotation): Likewise. + (Parser::parse_path_in_expression_pratt): Likewise. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * lex/rust-token.h (enum PrimitiveCoreType): Add await keyword + definition. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * lex/rust-token.h (enum PrimitiveCoreType): Change macro for + underscore in token list. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * lex/rust-token.h (enum PrimitiveCoreType): Change enum macro calls. + (RS_TOKEN_KEYWORD): Remove generic token keyword macro. + (RS_TOKEN_KEYWORD_2015): Introduce keywords for edition 2015. + (RS_TOKEN_KEYWORD_2018): Likewise with edition 2018. + * lex/rust-token.cc (RS_TOKEN_KEYWORD): Remove old macro definition. + (RS_TOKEN_KEYWORD_2015): Replace with 2015 definition... + (RS_TOKEN_KEYWORD_2018): ... and 2018 definition. + * util/rust-keyword-values.cc (RS_TOKEN_KEYWORD): Likewise. + (RS_TOKEN_KEYWORD_2015): Likewise. + (RS_TOKEN_KEYWORD_2018): Likewise. + * util/rust-keyword-values.h (RS_TOKEN_KEYWORD): Likewise. + (RS_TOKEN_KEYWORD_2015): Likewise. + (RS_TOKEN_KEYWORD_2018): Likewise. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * lex/rust-token.h (enum PrimitiveCoreType): Change keyword suffix from + tok to kw. + * ast/rust-ast-collector.cc (TokenCollector::visit): Update suffix to + match the new declaration. + * lex/rust-lex.cc (Lexer::parse_raw_identifier): Likewise. + * parse/rust-parse-impl.h (can_tok_start_type): Likewise. + (Parser::parse_item): Likewise. + (Parser::parse_vis_item): Likewise. + (Parser::parse_extern_crate): Likewise. + (Parser::parse_function): Likewise. + (Parser::parse_function_qualifiers): Likewise. + (Parser::parse_struct): Likewise. + (Parser::parse_enum): Likewise. + (Parser::parse_static_item): Likewise. + (Parser::parse_trait_item): Likewise. + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_trait_impl_item): Likewise. + (Parser::parse_extern_block): Likewise. + (Parser::parse_external_item): Likewise. + (Parser::parse_stmt): Likewise. + (Parser::parse_return_expr): Likewise. + (Parser::parse_match_expr): Likewise. + (Parser::parse_type): Likewise. + (Parser::parse_for_prefixed_type): Likewise. + (Parser::parse_type_no_bounds): Likewise. + (Parser::parse_stmt_or_expr): Likewise. + * parse/rust-parse.cc (peculiar_fragment_match_compatible): Likewie. + * util/rust-token-converter.cc (convert): Likewise. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + zero field check during ast validation pass. + * checks/errors/rust-ast-validation.h: Add union visit function + prototype. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + ast validation pass to reject variadic arguments on regular functions. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add auto + trait associated item check in AST validation pass. + * parse/rust-parse-impl.h: Remove old error emission done during + parsing pass. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Reject + auto traits with super traits. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/rust-ast-validation.cc (ASTValidation::visit): Add + check for generics on auto traits. + * checks/errors/rust-ast-validation.h: Add visit function prototype. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.hxx: Remove debug log. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): Format. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.h: New method. + * resolve/rust-forever-stack.hxx: Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.h: New method. + * resolve/rust-forever-stack.hxx: Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.hxx: Do not copy segment when + dereferencing iterator in `find_starting_point`. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.h: Fix `ForeverStack::resolve_path` + signature. + * resolve/rust-forever-stack.hxx: Likewise. + * resolve/rust-early-name-resolver-2.0.cc (Early::visit): Use new API. + (Early::visit_attributes): Likewise. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.hxx: Add specific behavior for + `ForeverStack::get` when dealing with labels. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-forever-stack.h: Improve resolve_path API. + * resolve/rust-forever-stack.hxx: Likewise and fix implementation. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-rib.h: Add Namespace enum. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Change Path API to be more consistent. + * ast/rust-path.h: Likewise. + * ast/rust-ast-collector.cc (TokenCollector::visit): Use new API. + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): Likewise. + * resolve/rust-ast-resolve-path.cc (ResolvePath::resolve_path): Likewise. + * resolve/rust-forever-stack.hxx: Likewise. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_function): Early return on + unrecoverable errors. + (Parser::parse_trait_item): Likewise. + (Parser::parse_self_param): Update return type. + * parse/rust-parse.h (enum ParseSelfError): Add enumeration to describe + different self parameter parsing errors. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_self_param): Fix the loop + exit condition. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-item.h (struct Visibility): Move Visibility from here... + * ast/rust-ast.h (struct Visibility): ...to here. + * parse/rust-parse-impl.h (Parser::parse_trait_item): Parse visibility + before giving it back to the item parsing function. + (Parser::parse_trait_type): Add visibility modifier. + * parse/rust-parse.h (RUST_PARSE_H): Change function prototype. + 2024-01-18 Arthur Cohen <arthur.cohen@embecosm.com> * backend/rust-compile-base.cc (HIRCompileBase::resolve_method_address): diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index c7215cf..36dd522 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -1305,7 +1305,7 @@ simplify_context::simplify_unary_operation_1 (rtx_code code, machine_mode mode, > GET_MODE_UNIT_SIZE (mode) ? FLOAT_TRUNCATE : FLOAT_EXTEND, mode, - XEXP (op, 0), mode); + XEXP (op, 0), GET_MODE (XEXP (op, 0))); /* (float_truncate (float x)) is (float x) */ if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 512d3ce..3fb20ec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,942 @@ +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR c++/113788 + * g++.dg/parse/pr113788.C: New test. + +2024-02-06 Marek Polacek <polacek@redhat.com> + + PR c++/94231 + * g++.dg/cpp0x/deleted17.C: New test. + +2024-02-06 Andrew Carlotti <andrew.carlotti@arm.com> + + * g++.target/aarch64/mv-symbols1.C: New test. + * g++.target/aarch64/mv-symbols2.C: Ditto. + * g++.target/aarch64/mv-symbols3.C: Ditto. + * g++.target/aarch64/mv-symbols4.C: Ditto. + * g++.target/aarch64/mv-symbols5.C: Ditto. + * g++.target/aarch64/mvc-symbols1.C: Ditto. + * g++.target/aarch64/mvc-symbols2.C: Ditto. + * g++.target/aarch64/mvc-symbols3.C: Ditto. + * g++.target/aarch64/mvc-symbols4.C: Ditto. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/110676 + * gcc.dg/asan/pr110676.c: New test. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113736 + * gcc.dg/bitint-86.c: New test. + +2024-02-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113759 + * gcc.c-torture/compile/pr113759.c: New test. + +2024-02-06 Jason Merrill <jason@redhat.com> + + PR c++/107291 + * g++.dg/cpp2a/spaceship-eq17.C: New test. + +2024-02-05 Jason Merrill <jason@redhat.com> + + PR c++/109359 + * g++.dg/ext/frounding-math1.C: New test. + +2024-02-05 Jason Merrill <jason@redhat.com> + + PR c++/111286 + * g++.dg/cpp0x/initlist-array22.C: New test. + +2024-02-05 H.J. Lu <hjl.tools@gmail.com> + + PR target/113689 + * gcc.target/i386/pr113689-1.c: New file. + * gcc.target/i386/pr113689-2.c: Likewise. + * gcc.target/i386/pr113689-3.c: Likewise. + +2024-02-05 Jakub Jelinek <jakub@redhat.com> + + PR c/113740 + * gcc.dg/bitint-85.c: New test. + +2024-02-05 Richard Ball <richard.ball@arm.com> + + * lib/target-supports.exp: Add v8_1_m_main_pacbti. + * g++.target/arm/bti_thunk.C: New test. + +2024-02-05 H.J. Lu <(no_default)> + + * gcc.target/i386/apx-ndd.c: Updated. + +2024-02-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113707 + * gcc.dg/torture/pr113707-1.c: New testcase. + * gcc.dg/torture/pr113707-2.c: Likewise. + +2024-02-05 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113737 + * gcc.dg/bitint-84.c: New test. + +2024-02-05 Monk Chiang <monk.chiang@sifive.com> + + * gcc.target/riscv/mcpu-sifive-p450.c: New test. + * gcc.target/riscv/mcpu-sifive-p670.c: New test. + +2024-02-04 Jeff Law <jlaw@ventanamicro.com> + + * gcc.target/riscv/reg_subreg_costs.c: New test. + Co-authored-by: Jivan Hakobyan <jivanhakobyan9@gmail.com> + +2024-02-03 John David Anglin <danglin@gcc.gnu.org> + + * gcc.dg/pr84877.c: Adjust xfail parentheses. + +2024-02-03 Jerry DeLisle <jvdelisle@gcc.gnu.org> + + PR libfortran/111022 + * gfortran.dg/fmt_error_10.f: Show D+0 exponent. + * gfortran.dg/pr96436_4.f90: Show E+0 exponent. + * gfortran.dg/pr96436_5.f90: Show E+0 exponent. + * gfortran.dg/pr111022.f90: New test. + +2024-02-03 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113722 + * gcc.dg/pr113722.c: New test. + +2024-02-03 Patrick Palka <ppalka@redhat.com> + + PR c++/110006 + PR c++/112769 + * g++.dg/cpp2a/class-deduction-alias18.C: New test. + * g++.dg/cpp2a/concepts-friend16.C: New test. + +2024-02-03 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/113730 + * gm2/extensions/fail/arith1.mod: New test. + * gm2/extensions/fail/arith2.mod: New test. + * gm2/extensions/fail/arith3.mod: New test. + * gm2/extensions/fail/arith4.mod: New test. + * gm2/extensions/fail/arithpromote.mod: New test. + * gm2/extensions/fail/extensions-fail.exp: New test. + * gm2/linking/fail/badimp.def: New test. + * gm2/linking/fail/badimp.mod: New test. + * gm2/linking/fail/linking-fail.exp: New test. + * gm2/linking/fail/testbadimp.mod: New test. + +2024-02-02 Tamar Christina <tamar.christina@arm.com> + + PR tree-optimization/113588 + PR tree-optimization/113467 + * gcc.dg/vect/vect-early-break_108-pr113588.c: New test. + * gcc.dg/vect/vect-early-break_109-pr113588.c: New test. + +2024-02-02 Andrew Pinski <quic_apinski@quicinc.com> + + * gcc.dg/vect/vect-avg-1.c: Check optimized dump + for `vector *signed short` instead of the `vect` dump. + * gcc.dg/vect/vect-avg-11.c: Likewise. + * gcc.dg/vect/vect-avg-12.c: Likewise. + * gcc.dg/vect/vect-avg-13.c: Likewise. + * gcc.dg/vect/vect-avg-14.c: Likewise. + * gcc.dg/vect/vect-avg-2.c: Likewise. + * gcc.dg/vect/vect-avg-3.c: Likewise. + * gcc.dg/vect/vect-avg-4.c: Likewise. + * gcc.dg/vect/vect-avg-5.c: Likewise. + * gcc.dg/vect/vect-avg-6.c: Likewise. + * gcc.dg/vect/vect-avg-7.c: Likewise. + * gcc.dg/vect/vect-avg-8.c: Likewise. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR libgcc/113604 + * gcc.dg/torture/bitint-53.c: New test. + * gcc.dg/torture/bitint-55.c: New test. + +2024-02-02 Antoni Boucher <bouanto@zoho.com> + + * jit.dg/all-non-failing-tests.h: New test. + * jit.dg/test-sizeof.c: New test. + +2024-02-02 Jason Merrill <jason@redhat.com> + + PR c++/110084 + * g++.dg/cpp2a/spaceship-synth-neg3.C: Check error message. + * g++.dg/cpp2a/spaceship-eq16.C: New test. + +2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + PR target/113697 + * gcc.target/riscv/rvv/autovec/pr113697.c: New test. + +2024-02-02 Iain Sandoe <iain@sandoe.co.uk> + + * lib/target-supports.exp (check_effective_target_shared): + Allow the external symbols referenced in the test to be undefined. + +2024-02-02 Iain Sandoe <iain@sandoe.co.uk> + + * g++.dg/ubsan/ubsan.exp:Add a parameter to init to say that + we expect the C++ driver to provide paths for libstdc++. + * gcc.dg/ubsan/ubsan.exp: Add a parameter to init to say that + we need a path added for libstdc++. + * gdc.dg/ubsan/ubsan.exp: Likewise. + * gfortran.dg/ubsan/ubsan.exp: Likewise. + * lib/ubsan-dg.exp: Handle a single parameter to init that + requests addition of a path to libstdc++ to link flags. + +2024-02-02 Iain Sandoe <iain@sandoe.co.uk> + + * g++.dg/asan/asan.exp: Add a parameter to init to say that + we expect the C++ driver to provide paths for libstdc++. + * g++.dg/hwasan/hwasan.exp: Likewise + * gcc.dg/asan/asan.exp: Add a parameter to init to say that + we need a path added for libstdc++. + * gcc.dg/hwasan/hwasan.exp: Likewise. + * gdc.dg/asan/asan.exp: Likewise. + * gfortran.dg/asan/asan.exp: Likewise. + * lib/asan-dg.exp: Handle a single parameter to init that + requests addition of a path to libstdc++ to link flags. + * lib/hwasan-dg.exp: Likewise. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113691 + * gcc.dg/bitint-83.c: New test. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113692 + * gcc.dg/bitint-82.c: New test. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113699 + * gcc.dg/bitint-81.c: New test. + +2024-02-02 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113705 + * g++.dg/opt/pr113705.C: New test. + +2024-02-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/pr71321.c (scan-assembler-not): Avoid multiline + matches. + +2024-02-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/sse2-stv-1.c (dg-options): Add -mno-stackrealign. + +2024-02-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/pr80569.c: Require gas. + +2024-02-02 Lehua Ding <lehua.ding@rivai.ai> + + Revert: + 2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * gcc.target/riscv/rvv/autovec/poly_licm-1.c: New test. + * gcc.target/riscv/rvv/autovec/poly_licm-2.c: New test. + +2024-02-02 Iain Sandoe <iain@sandoe.co.uk> + + PR target/112863 + * lib/obj-c++.exp: Decide on whether to present -B or -L to + reference the paths to uninstalled libobjc/libobjc-gnu and + libstdc++ and use that to generate the link flags. + +2024-02-02 Iain Sandoe <iain@sandoe.co.uk> + + PR target/112862 + * gfortran.dg/coarray/caf.exp: Remove duplicate additions of + libatomic handling. + * gfortran.dg/dg.exp: Likewise. + * lib/gfortran.exp: Decide on whether to present -B or -L to + reference the paths to uninstalled libgfortran, libqadmath and + libatomic and use that to generate the link flags. + +2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * gcc.target/riscv/rvv/autovec/poly_licm-1.c: New test. + * gcc.target/riscv/rvv/autovec/poly_licm-2.c: New test. + +2024-02-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/pieces-memcpy-7.c (dg-additional-options): Add + -mno-stackrealign. + * gcc.target/i386/pieces-memcpy-8.c: Likewise. + * gcc.target/i386/pieces-memcpy-9.c: Likewise. + * gcc.target/i386/pieces-memset-36.c: Likewise. + * gcc.target/i386/pieces-memset-40.c: Likewise. + * gcc.target/i386/pieces-memset-9.c: Likewise. + +2024-02-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/apx-ndd-cmov.c (scan-assembler-times): Allow for + cmovl.e, cmovl.ge. + +2024-02-02 Jason Merrill <jason@redhat.com> + + PR c++/112439 + * g++.dg/cpp2a/no_unique_address15.C: New test. + +2024-02-02 Jason Merrill <jason@redhat.com> + + PR c++/113638 + * g++.dg/cpp1y/var-templ-array1.C: New test. + +2024-02-02 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c: New test. + +2024-02-02 Jiahao Xu <xujiahao@loongson.cn> + + * gcc.target/loongarch/larch-frecipe-intrinsic.c: New test. + +2024-02-02 Li Wei <liwei@loongson.cn> + + * gfortran.dg/vect/vect-10.f90: New test. + +2024-02-02 Xi Ruoyao <xry111@xry111.site> + + * gcc.target/loongarch/func-call-extreme-1.c (dg-options): + Use -O2 instead of -O0 to ensure the pcalau12i/addi/lu32i/lu52i + instruction sequences are not reordered by the compiler. + (NOIPA): Disallow interprocedural optimizations. + * gcc.target/loongarch/func-call-extreme-2.c: Remove the content + duplicated from func-call-extreme-1.c, include it instead. + (dg-options): Likewise. + * gcc.target/loongarch/func-call-extreme-3.c (dg-options): + Likewise. + * gcc.target/loongarch/func-call-extreme-4.c (dg-options): + Likewise. + * gcc.target/loongarch/cmodel-extreme-1.c: New test. + * gcc.target/loongarch/cmodel-extreme-2.c: New test. + * g++.target/loongarch/cmodel-extreme-mi-thunk-1.C: New test. + * g++.target/loongarch/cmodel-extreme-mi-thunk-2.C: New test. + * g++.target/loongarch/cmodel-extreme-mi-thunk-3.C: New test. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c: New test. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c: New test. + * gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c: New test. + +2024-02-02 Lulu Cheng <chenglulu@loongson.cn> + + * gcc.target/loongarch/attr-model-5.c: New test. + * gcc.target/loongarch/func-call-extreme-5.c: New test. + * gcc.target/loongarch/func-call-extreme-6.c: New test. + * gcc.target/loongarch/tls-extreme-macro.c: New test. + +2024-02-01 Marek Polacek <polacek@redhat.com> + + * g++.dg/warn/Wdangling-reference21.C: New test. + +2024-02-01 John David Anglin <danglin@gcc.gnu.org> + + * gnat.dg/trampoline3.adb: xfail scan-assembler-not + check on hppa*-*-*. + +2024-02-01 Patrick Palka <ppalka@redhat.com> + + PR c++/112737 + * g++.dg/template/ttp42.C: New test. + * g++.dg/template/ttp43.C: New test. + +2024-02-01 Marek Polacek <polacek@redhat.com> + + PR c++/112437 + * g++.dg/cpp2a/concepts-throw1.C: New test. + * g++.dg/eh/throw4.C: New test. + +2024-02-01 Monk Chiang <monk.chiang@sifive.com> + + * gcc.target/riscv/za-ext.c: New test. + * gcc.target/riscv/zi-ext.c: New test. + +2024-02-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/pr38534-1.c: Add -fomit-frame-pointer to + dg-options. + * gcc.target/i386/pr38534-2.c: Likewise. + * gcc.target/i386/pr38534-3.c: Likewise. + * gcc.target/i386/pr38534-4.c: Likewise. + +2024-02-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/no-callee-saved-1.c: Add -fomit-frame-pointer to + dg-options. + * gcc.target/i386/no-callee-saved-2.c: Likewise. + +2024-02-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/avx512vl-stv-rotatedi-1.c: Add -mstv + -mno-stackrealign to dg-options. + +2024-02-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/pr70321.c: Add -fomit-frame-pointer to + dg-options. + +2024-02-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * g++.dg/ext/attr-section2.C (scan-assembler): Quote dots. Allow + for double-quoted section name. + * g++.dg/ext/attr-section2a.C: Likewise. + * g++.dg/ext/attr-section2b.C: Likewise. + +2024-02-01 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113693 + * gcc.dg/pr113693.c: New testcase. + +2024-02-01 Jakub Jelinek <jakub@redhat.com> + Jason Merrill <jason@redhat.com> + + PR c++/113531 + * g++.dg/asan/initlist1.C: New test. + +2024-02-01 Roger Sayle <roger@nextmovesoftware.com> + Richard Biener <rguenther@suse.de> + + PR target/113560 + * g++.target/i386/pr113560.C: New test case. + * gcc.target/i386/pr113560.c: Likewise. + * gcc.dg/pr87954.c: Update test case. + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + Revert: + 2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + PR target/113249 + * g++.target/riscv/rvv/base/bug-1.C: use default scheduling + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-102.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-108.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-114.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-119.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-12.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-16.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-17.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-19.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-21.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-23.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-25.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-27.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-29.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-31.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-33.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-35.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-4.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-40.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-44.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-50.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-56.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-62.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-68.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-74.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-79.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-8.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-84.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-90.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-96.c: ditto + * gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c: ditto + * gcc.target/riscv/rvv/base/pr108185-1.c: ditto + * gcc.target/riscv/rvv/base/pr108185-2.c: ditto + * gcc.target/riscv/rvv/base/pr108185-3.c: ditto + * gcc.target/riscv/rvv/base/pr108185-4.c: ditto + * gcc.target/riscv/rvv/base/pr108185-5.c: ditto + * gcc.target/riscv/rvv/base/pr108185-6.c: ditto + * gcc.target/riscv/rvv/base/pr108185-7.c: ditto + * gcc.target/riscv/rvv/base/shift_vx_constraint-1.c: ditto + * gcc.target/riscv/rvv/vsetvl/pr111037-3.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c: ditto + * gfortran.dg/vect/vect-8.f90: ditto + +2024-02-01 Edwin Lu <ewlu@rivosinc.com> + + PR target/113249 + * g++.target/riscv/rvv/base/bug-1.C: use default scheduling + * gcc.target/riscv/rvv/autovec/reduc/reduc_call-2.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-102.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-108.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-114.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-119.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-12.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-16.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-17.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-19.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-21.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-23.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-25.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-27.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-29.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-31.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-33.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-35.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-4.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-40.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-44.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-50.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-56.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-62.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-68.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-74.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-79.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-8.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-84.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-90.c: ditto + * gcc.target/riscv/rvv/base/binop_vx_constraint-96.c: ditto + * gcc.target/riscv/rvv/base/float-point-dynamic-frm-30.c: ditto + * gcc.target/riscv/rvv/base/pr108185-1.c: ditto + * gcc.target/riscv/rvv/base/pr108185-2.c: ditto + * gcc.target/riscv/rvv/base/pr108185-3.c: ditto + * gcc.target/riscv/rvv/base/pr108185-4.c: ditto + * gcc.target/riscv/rvv/base/pr108185-5.c: ditto + * gcc.target/riscv/rvv/base/pr108185-6.c: ditto + * gcc.target/riscv/rvv/base/pr108185-7.c: ditto + * gcc.target/riscv/rvv/base/shift_vx_constraint-1.c: ditto + * gcc.target/riscv/rvv/vsetvl/pr111037-3.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-28.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-29.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-32.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_back_prop-33.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-17.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-18.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_single_block-19.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-10.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-11.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-12.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-4.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-5.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-6.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-7.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-8.c: ditto + * gcc.target/riscv/rvv/vsetvl/vlmax_switch_vtype-9.c: ditto + * gfortran.dg/vect/vect-8.f90: ditto + +2024-02-01 Andrew Pinski <quic_apinski@quicinc.com> + + PR target/113657 + * gcc.target/aarch64/acle/ls64_strict_align.c: New test. + +2024-01-31 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/113253 + * gcc.dg/analyzer/deref-before-check-pr113253.c: New test. + +2024-01-31 Joseph Myers <josmyers@redhat.com> + + PR c/112571 + * gcc.dg/c23-enum-9.c, gcc.dg/c23-enum-10.c: New tests. + +2024-01-31 Robin Dapp <rdapp@ventanamicro.com> + + * gcc.target/aarch64/sve/pre_cond_share_1.c: XFAIL. + * gcc.target/riscv/rvv/autovec/pr113607-run.c: New test. + * gcc.target/riscv/rvv/autovec/pr113607.c: New test. + +2024-01-31 Martin Uecker <uecker@tugraz.at> + + PR c/113438 + * gcc.dg/pr113438.c: New test. + +2024-01-31 Jonathan Yong <10walls@gmail.com> + + * c-c++-common/analyzer/uninit-pr108968-register.c: + Use __UINTPTR_TYPE__ instead of unsigned long for LLP64. + +2024-01-31 Gaius Mulley <gaiusmod2@gmail.com> + + PR modula2/111627 + * gm2/pim/pass/stdio.mod: Moved to... + * gm2/pim/pass/teststdio.mod: ...here. + * gm2/pim/run/pass/builtins.mod: Moved to... + * gm2/pim/run/pass/testbuiltins.mod: ...here. + * gm2/pim/run/pass/math.mod: Moved to... + * gm2/pim/run/pass/testmath.mod: ...here. + * gm2/pim/run/pass/math2.mod: Moved to... + * gm2/pim/run/pass/testmath2.mod: ...here. + +2024-01-31 Tamar Christina <tamar.christina@arm.com> + + PR testsuite/113502 + * gcc.target/aarch64/sve/vect-early-break-cbranch.c: Ignore exact branch. + * gcc.target/aarch64/vect-early-break-cbranch.c: Likewise. + +2024-01-31 Tamar Christina <tamar.christina@arm.com> + + PR sanitizer/112644 + * c-c++-common/hwasan/hwasan-thread-clears-stack.c: Update testcase. + +2024-01-31 Tamar Christina <tamar.christina@arm.com> + Matthew Malcomson <matthew.malcomson@arm.com> + + PR sanitizer/112644 + * c-c++-common/hwasan/builtin-special-handling.c: Update testcase. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR middle-end/110176 + * gcc.dg/torture/pr110176.c: New testcase. + +2024-01-31 Alex Coplan <alex.coplan@arm.com> + + PR target/111677 + * gcc.target/aarch64/torture/pr111677.c: New test. + +2024-01-31 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * gcc.target/i386/auto-init-5.c: Add + -fno-asynchronous-unwind-tables to dg-options. + * gcc.target/i386/auto-init-6.c: Likewise. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/111444 + * gcc.dg/torture/pr111444.c: New testcase. + +2024-01-31 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> + + * g++.dg/cpp0x/udlit-extended-id-1.C: Require ucn support. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113630 + * gcc.dg/torture/pr113630.c: New testcase. + +2024-01-31 Jakub Jelinek <jakub@redhat.com> + + PR rtl-optimization/113656 + * gcc.target/i386/pr113656.c: New test. + +2024-01-31 Jakub Jelinek <jakub@redhat.com> + + PR debug/113637 + * gcc.dg/bitint-80.c: New test. + +2024-01-31 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113639 + * gcc.dg/bitint-79.c: New test. + +2024-01-31 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113670 + * gcc.target/i386/pr113670.c: New testcase. + +2024-01-31 Alexandre Oliva <oliva@adacore.com> + + PR debug/113394 + * gcc.dg/strub-internal-pr113394.c: New. + +2024-01-31 Joseph Myers <josmyers@redhat.com> + + PR c/111059 + PR c/111911 + * gcc.c-torture/compile/pr111059-1.c, + gcc.c-torture/compile/pr111059-2.c, + gcc.c-torture/compile/pr111059-3.c, + gcc.c-torture/compile/pr111059-4.c, + gcc.c-torture/compile/pr111059-5.c, + gcc.c-torture/compile/pr111059-6.c, + gcc.c-torture/compile/pr111059-7.c, + gcc.c-torture/compile/pr111059-8.c, + gcc.c-torture/compile/pr111059-9.c, + gcc.c-torture/compile/pr111059-10.c, + gcc.c-torture/compile/pr111059-11.c, + gcc.c-torture/compile/pr111059-12.c, + gcc.c-torture/compile/pr111911-1.c, + gcc.c-torture/compile/pr111911-2.c: New tests. + +2024-01-31 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/113509 + * c-c++-common/analyzer/stdarg-pr113509.c: New test. + +2024-01-30 Fangrui Song <maskray@google.com> + + PR target/105576 + * gcc.target/i386/asm-raw-symbol.c: New testcase. + +2024-01-30 Marek Polacek <polacek@redhat.com> + + PR c++/110358 + PR c++/109640 + * g++.dg/warn/Wdangling-reference18.C: New test. + * g++.dg/warn/Wdangling-reference19.C: New test. + * g++.dg/warn/Wdangling-reference20.C: New test. + +2024-01-30 Patrick Palka <ppalka@redhat.com> + + PR c++/67898 + * g++.dg/cpp0x/temp_default8.C: New test. + +2024-01-30 Jason Merrill <jason@redhat.com> + + PR c++/112846 + * g++.dg/abi/anon6.C: Specify ABI v18. + * g++.dg/abi/anon6a.C: New test for ABI v19. + +2024-01-30 Jason Merrill <jason@redhat.com> + + PR c++/113451 + * g++.dg/abi/mangle-regparm1a.C: Use -Wabi=0. + +2024-01-30 Patrick Palka <ppalka@redhat.com> + + PR c++/113640 + * g++.dg/cpp23/explicit-obj-lambda14.C: New test. + +2024-01-30 Patrick Palka <ppalka@redhat.com> + + PR c++/113644 + * g++.dg/template/nontype30.C: New test. + +2024-01-30 Pan Li <pan2.li@intel.com> + + * gcc.target/riscv/rvv/autovec/vls/def.h: Add new helper macro. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c: New test. + * gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c: New test. + +2024-01-30 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/113654 + * c-c++-common/analyzer/allocation-size-pr113654-1.c: New test. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/builtin_macros1.rs: Fix output pattern. + * rust/execute/torture/coercion3.rs: Likewise. + * rust/execute/torture/issue-2080.rs: Likewise. + * rust/execute/torture/issue-2179.rs: Likewise. + * rust/execute/torture/issue-2180.rs: Likewise. + * rust/execute/torture/iter1.rs: Likewise. + +2024-01-30 Robert Goss <goss.robert@gmail.com> + + * rust/compile/missing_constructor_fields.rs: Added case with no initializers + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * rust/compile/for_lifetimes.rs: New test. + +2024-01-30 Jakub Dupak <dev@jakubdupak.com> + + * rust/compile/torture/utf8_identifiers.rs: add mising lifetime + +2024-01-30 Robert Goss <goss.robert@gmail.com> + + * rust/compile/repeated_constructor_fields.rs: Added case with constructor field repeated + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * rust/compile/issue-2788.rs: New test. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * rust/compile/const_trait_fn.rs: + Enclose const in single quotes. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * rust/compile/issue-2785.rs: New test. + +2024-01-30 Nirmal Patel <nirmal@nirmal.dev> + + * rust/compile/issue-2187.rs: New file. + * rust/execute/torture/issue-2187.rs: New file. + +2024-01-30 Kushal Pal <kushalpal109@gmail.com> + + * rust/compile/issue-2767.rs: New test. + +2024-01-30 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/torture/intrinsics-4.rs: Adjust. + * rust/compile/torture/intrinsics-math.rs: Adjust. + * rust/execute/torture/atomic_load.rs: Adjust. + * rust/execute/torture/atomic_store.rs: Adjust. + * rust/compile/torture/intrinsics-1.rs: Removed. + * rust/compile/torture/builtin_abort.rs: New test. + * rust/execute/torture/builtin_abort.rs: New test. + +2024-01-30 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/sized-stub.rs: New test. + +2024-01-30 Nobel Singh <nobel2073@gmail.com> + + * rust/compile/issue-2040.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/functions_without_body.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/execute/torture/name_resolution.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/name_resolution11.rs: New test. + * rust/compile/name_resolution12.rs: New test. + * rust/compile/name_resolution13.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/const_trait_fn.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/const_async_function.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/unsafe_module.rs: New test. + +2024-01-30 M V V S Manoj Kumar <mvvsmanojkumar@gmail.com> + + * rust/compile/issue-2650-1.rs: New test.(edition=2018) + * rust/compile/issue-2650-2.rs: New test.(edition=2015) + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/const_generics_8.rs: Fill the union with dummy values. + * rust/compile/empty_union.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/non_foreign_variadic_function.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/auto_trait_invalid.rs: Update old test with updated + error message. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/auto_trait_super_trait.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/generic_auto_trait.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/self_const_ptr.rs: New test. + * rust/compile/self_mut_ptr.rs: New test. + * rust/compile/self_ptr.rs: New test. + +2024-01-30 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/trait_pub_type.rs: New test. + +2024-01-30 Richard Biener <rguenther@suse.de> + + PR tree-optimization/113659 + * gcc.dg/pr113659.c: New testcase. + +2024-01-30 Iain Sandoe <iain@sandoe.co.uk> + + PR target/112861 + * lib/gdc.exp: Decide on whether to present -B or -L to reference + the paths to uninstalled libphobos and libstdc++ and use that to + generate the link flags. + +2024-01-30 Richard Sandiford <richard.sandiford@arm.com> + + PR target/113623 + * gcc.c-torture/compile/pr113623.c: New test. + +2024-01-30 Richard Sandiford <richard.sandiford@arm.com> + + PR target/113636 + * go.dg/pr113636.go: New test. + +2024-01-30 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/113603 + * gcc.c-torture/compile/pr113603.c: New test. + +2024-01-30 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/101195 + * gcc.dg/pr101195.c: New test. + +2024-01-30 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/113622 + * gcc.target/i386/pr113622-2.c: Use -msse2 instead of -msse in + dg-options. + * gcc.target/i386/pr113622-3.c: Likewise. + +2024-01-30 Alexandre Oliva <oliva@adacore.com> + + Revert: + 2023-12-26 David Edelsohn <dje.gcc@gmail.com> + + * c-c++-common/strub-unsupported-2.c: Require strub. + * c-c++-common/strub-unsupported-3.c: Same. + * c-c++-common/strub-unsupported.c: Same. + * lib/target-supports.exp (check_effective_target_strub): Return 0 + for AIX. + +2024-01-30 H.J. Lu <(no_default)> + + * gcc.target/i386/libcall-1.c: Limit to lp64 target. + * gcc.target/i386/pr107057.c: Likewise. + +2024-01-30 Juzhe-Zhong <juzhe.zhong@rivai.ai> + + * gcc.target/riscv/rvv/autovec/binop/shift-rv32gcv.c: Adapt test. + * gcc.target/riscv/rvv/autovec/binop/shift-rv64gcv.c: Ditto. + * gcc.target/riscv/rvv/autovec/vls/mod-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/vls/shift-1.c: Ditto. + * gcc.target/riscv/rvv/autovec/vls/shift-2.c: Ditto. + 2024-01-29 Alexandre Oliva <oliva@adacore.com> * lib/target-supports.exp (check_effective_target_shared): diff --git a/gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c b/gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c new file mode 100644 index 0000000..b7bfc5f --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/allocation-size-pr113654-1.c @@ -0,0 +1,52 @@ +/* Adapted from include/linux/math.h */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) + +/* Reduced from Linux kernel's drivers/gpu/drm/i915/display/intel_bios.c */ +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long __kernel_size_t; +typedef __kernel_size_t size_t; + +extern __attribute__((__alloc_size__(1))) __attribute__((__malloc__)) +void* kzalloc(size_t size); + +typedef struct +{ + u32 reg; +} i915_reg_t; +struct intel_uncore; +struct intel_uncore_funcs +{ + u32 (*mmio_readl)(struct intel_uncore* uncore, i915_reg_t r); +}; +struct intel_uncore +{ + void* regs; + struct intel_uncore_funcs funcs; +}; +static inline __attribute__((__gnu_inline__)) __attribute__((__unused__)) +__attribute__((no_instrument_function)) u32 +intel_uncore_read(struct intel_uncore* uncore, i915_reg_t reg) +{ + return uncore->funcs.mmio_readl(uncore, reg); +} +struct drm_i915_private +{ + struct intel_uncore uncore; +}; +struct vbt_header* +spi_oprom_get_vbt(struct drm_i915_private* i915) +{ + u16 vbt_size; + u32* vbt; + vbt_size = + intel_uncore_read(&i915->uncore, ((const i915_reg_t){ .reg = (0x102040) })); + vbt_size &= 0xffff; + vbt = (u32*)kzalloc(round_up (vbt_size, 4)); /* { dg-bogus "allocated buffer size is not a multiple of the pointee's size" "PR analyzer/113654" } */ + if (!vbt) + goto err_not_found; + return (struct vbt_header*)vbt; +err_not_found: + return ((struct vbt_header*)0); +} diff --git a/gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c b/gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c new file mode 100644 index 0000000..5534808 --- /dev/null +++ b/gcc/testsuite/c-c++-common/analyzer/stdarg-pr113509.c @@ -0,0 +1,8 @@ +/* Regression test for ICE with -fanalyzer-verbose-state-changes. */ + +/* { dg-additional-options " -fanalyzer-verbose-state-changes" } */ + +__builtin_va_list FOO_showfatal_ap; +void FOO_showfatal(char fmta, ...) { + __builtin_va_start(FOO_showfatal_ap, fmta); /* { dg-message "'va_start' called here" } */ +} /* { dg-warning "missing call to 'va_end'" } */ diff --git a/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c b/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c index a76c09e..e9a1c21 100644 --- a/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c +++ b/gcc/testsuite/c-c++-common/analyzer/uninit-pr108968-register.c @@ -4,6 +4,6 @@ struct cpu_info {}; struct cpu_info *get_cpu_info(void) { - register unsigned long sp asm("rsp"); + register __UINTPTR_TYPE__ sp asm("rsp"); return (struct cpu_info *)((sp | (STACK_SIZE - 1)) + 1) - 1; /* { dg-bogus "use of uninitialized value 'sp'" } */ } diff --git a/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c b/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c index a7a6d91..f975baa 100644 --- a/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c +++ b/gcc/testsuite/c-c++-common/hwasan/builtin-special-handling.c @@ -8,24 +8,24 @@ /* { dg-skip-if "" { *-*-* } { "-flto" } { "-flto-partition=none" } } */ typedef __SIZE_TYPE__ size_t; -/* Functions to observe that HWASAN instruments memory builtins in the expected - manner. */ +/* HWASAN used to instrument calls to memset, memcpy, and memmove. It no + longer does this. Many other string and memory builtins are intercepted by + the runtime (and hence the codegen need not do anything). */ void * __attribute__((noinline)) memset_builtin (void *dest, int value, size_t len) { return __builtin_memset (dest, value, len); } -/* HWASAN avoids strlen because it doesn't know the size of the memory access - until *after* the function call. */ size_t __attribute__ ((noinline)) strlen_builtin (char *element) { return __builtin_strlen (element); } -/* First test ensures that the HWASAN_CHECK was emitted before the - memset. Second test ensures there was only HWASAN_CHECK (which demonstrates - that strlen was not instrumented). */ -/* { dg-final { scan-tree-dump-times "HWASAN_CHECK.*memset" 1 "asan1" } } */ -/* { dg-final { scan-tree-dump-times "HWASAN_CHECK" 1 "asan1" } } */ +/* First check here ensures there is no inline instrumentation generated for + these builtins. Second checks that we end up calling memset (i.e. that it's + not optimised into an inline operation, which would happen without the + instrumentation). */ +/* { dg-final { scan-tree-dump-not "HWASAN_CHECK" "asan1" } } */ +/* { dg-final { scan-assembler-times "\tmemset\\M" 1 } } */ diff --git a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c index 09c72a5..6c70684 100644 --- a/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c +++ b/gcc/testsuite/c-c++-common/hwasan/hwasan-thread-clears-stack.c @@ -52,5 +52,4 @@ main (int argc, char **argv) /* { dg-output "HWAddressSanitizer: tag-mismatch on address 0x\[0-9a-f\]*.*" } */ /* { dg-output "READ of size 4 at 0x\[0-9a-f\]* tags: \[\[:xdigit:\]\]\[\[:xdigit:\]\]/00 \\(ptr/mem\\) in thread T0.*" } */ -/* { dg-output "HWAddressSanitizer can not describe address in more detail\..*" } */ /* { dg-output "SUMMARY: HWAddressSanitizer: tag-mismatch \[^\n\]*.*" } */ diff --git a/gcc/testsuite/g++.dg/abi/anon6.C b/gcc/testsuite/g++.dg/abi/anon6.C index 7be0b0b..fd76610 100644 --- a/gcc/testsuite/g++.dg/abi/anon6.C +++ b/gcc/testsuite/g++.dg/abi/anon6.C @@ -1,5 +1,6 @@ // PR c++/108566 // { dg-do compile { target c++20 } } +// { dg-additional-options "-fabi-version=18 -fabi-compat-version=18" } template<typename T> struct wrapper1 { diff --git a/gcc/testsuite/g++.dg/abi/anon6a.C b/gcc/testsuite/g++.dg/abi/anon6a.C new file mode 100644 index 0000000..69c9adb --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/anon6a.C @@ -0,0 +1,20 @@ +// PR c++/108566 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-fabi-compat-version=0" } + +template<typename T> +struct wrapper1 { + union { + union { + T RightName; + }; + }; +}; + +template<auto tparam> void dummy(){} + +void uses() { + dummy<wrapper1<double>{123.0}>(); +} + +// { dg-final { scan-assembler "_Z5dummyITnDaXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd405ec00000000000EEEEEEvv" } } diff --git a/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C b/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C index 60ac51e..885c760 100644 --- a/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C +++ b/gcc/testsuite/g++.dg/abi/mangle-regparm1a.C @@ -1,5 +1,5 @@ // { dg-do run { target { { i?86-*-* x86_64-*-* } && ia32 } } } -// { dg-options "-fabi-version=8 -fabi-compat-version=8 -Wabi -save-temps" } +// { dg-options "-fabi-version=8 -fabi-compat-version=8 -Wabi=0 -save-temps" } // { dg-final { scan-assembler "_Z18IndirectExternCallIPFviiEiEvT_T0_S3_" } } template <typename F, typename T> diff --git a/gcc/testsuite/g++.dg/asan/asan.exp b/gcc/testsuite/g++.dg/asan/asan.exp index 9297bb5..f078bc3 100644 --- a/gcc/testsuite/g++.dg/asan/asan.exp +++ b/gcc/testsuite/g++.dg/asan/asan.exp @@ -22,7 +22,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ but we assume that's added by the g++ impl. +asan_init 0 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/g++.dg/asan/initlist1.C b/gcc/testsuite/g++.dg/asan/initlist1.C new file mode 100644 index 0000000..6cd5b7d --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/initlist1.C @@ -0,0 +1,20 @@ +// PR c++/113531 +// { dg-do run { target c++11 } } +// { dg-additional-options "-fsanitize=address" } + +#include <initializer_list> + +void f(int) { } + +void g() +{ + for (auto i : { 1, 2, 3 }) + f (i); + f(42); +} + +int main() +{ + g(); + g(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/deleted17.C b/gcc/testsuite/g++.dg/cpp0x/deleted17.C new file mode 100644 index 0000000..3bebe88 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/deleted17.C @@ -0,0 +1,20 @@ +// PR c++/94231 +// { dg-do compile { target c++11 } } + +struct F {F(F&&)=delete;}; + +template<int=0> +struct M { + F f; + M(); + M(const M&); + M(M&&); +}; + +template<int I> +M<I>::M(M&&)=default; // { dg-error "use of deleted function" } + +M<> f() { + M<> m; + return m; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array22.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array22.C new file mode 100644 index 0000000..8629e4b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array22.C @@ -0,0 +1,12 @@ +// PR c++/111286 +// { dg-do compile { target c++11 } } +// { dg-additional-options -Wno-unused } + +struct A { + A() noexcept {} +}; + +void foo() { + using T = const A (&)[1]; + T{}; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default8.C b/gcc/testsuite/g++.dg/cpp0x/temp_default8.C new file mode 100644 index 0000000..505c67d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/temp_default8.C @@ -0,0 +1,14 @@ +// PR c++/67898 +// { dg-do compile { target c++11 } } + +void f(int); +void f(float); + +template<class T, T F, T G, bool b = F == G> struct X { }; + +template<class T> +void test() { + X<void(T), f, f>(); +} + +template void test<int>(); diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C b/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C index c7091e9..94c0cd4 100644 --- a/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-extended-id-1.C @@ -1,5 +1,6 @@ // { dg-do run { target c++11 } } // { dg-additional-options "-Wno-error=normalized" } +// { dg-require-effective-target ucn } #include <cstring> #include <cstddef> using namespace std; diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C b/gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C new file mode 100644 index 0000000..b0ff7e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/var-templ-array1.C @@ -0,0 +1,7 @@ +// PR c++/113638 +// { dg-do compile { target c++14 } } + +template<int ...Is> +constexpr int my_array[]{Is...}; +constexpr auto t1 = my_array<2>; +static_assert(sizeof(my_array<1>) == sizeof(int) * 1, ""); diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C new file mode 100644 index 0000000..5c1d566 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda14.C @@ -0,0 +1,27 @@ +// PR c++/113640 +// { dg-do run { target c++23 } } + +static int total; + +struct A { + A f(this auto self, int n) { + total += n; + return self; + } +}; + +int main() { + A a; + a.f(1).f(42).f(100); + if (total != 143) + __builtin_abort(); + + auto l = [](this auto self, int n) { + total += n; + return self; + }; + total = 0; + l(1)(42)(100); + if (total != 143) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C new file mode 100644 index 0000000..0bb11bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias18.C @@ -0,0 +1,13 @@ +// PR c++/112769 +// { dg-do compile { target c++20 } } + +template<int I, typename T> +struct type +{ + type(T) requires requires { T{0}; }; +}; + +template <typename T> +using alias = type<0, T>; + +alias foo{123}; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C new file mode 100644 index 0000000..18974ee --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend16.C @@ -0,0 +1,25 @@ +// PR c++/110006 +// { dg-do compile { target c++20 } } + +template<typename T> +class s; + +template<typename T> +void constraint(s<T> const&, int&); + +template<typename U, typename T2> +U function(s<T2> const x) + requires requires (U& u) { constraint(x, u); }; + +template<typename T> +class s +{ + template<typename U, typename T2> + friend U function(s<T2> const x) + requires requires (U& u) { constraint(x, u); }; +}; + +int f(s<int> q) +{ + return function<int>(q); // { dg-bogus "ambiguous" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C new file mode 100644 index 0000000..bc3e3b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-throw1.C @@ -0,0 +1,8 @@ +// PR c++/112437 +// { dg-do compile { target c++20 } } + +struct S {}; +template <class T> +concept Throwable = requires(T x) { throw x; }; + +bool a = Throwable<S>; diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C new file mode 100644 index 0000000..3e7cf08 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address15.C @@ -0,0 +1,19 @@ +// PR c++/112439 +// { dg-do compile { target c++14 } } + +struct Empty {}; + +class Foo { +public: + constexpr Foo(int x, Empty y, int z) : a(x), b(y) + { + c = z; + } + +private: + int a{}; + [[no_unique_address]] Empty b{}; + [[no_unique_address]] int c{}; +}; + +constexpr Foo r{1, {}, 3}; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C new file mode 100644 index 0000000..e5538ea --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq16.C @@ -0,0 +1,11 @@ +// PR c++/110084 +// { dg-do compile { target c++20 } } + +template <class T> +class BadTuple { + constexpr bool operator==(const BadTuple&) const; +}; +template<class T> +constexpr bool BadTuple<T>::operator==(const BadTuple<T>&) const = default; + +BadTuple<int> a; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C new file mode 100644 index 0000000..039bfac --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq17.C @@ -0,0 +1,5 @@ +// PR c++/107291 +// { dg-do compile { target c++20 } } + +struct S4; // { dg-message "declared here" } +bool operator==(S4 const &, S4 const &) = default; // { dg-error "not a friend" } diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C index a4d8b32..aaa0264 100644 --- a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg3.C @@ -5,7 +5,7 @@ template<auto V> struct A {}; struct B { - constexpr auto operator<=>(const B&) const = default; // { dg-error "" } + constexpr auto operator<=>(const B&) const = default; // { dg-error "strong_ordering" } int value; }; diff --git a/gcc/testsuite/g++.dg/eh/throw4.C b/gcc/testsuite/g++.dg/eh/throw4.C new file mode 100644 index 0000000..b474472 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/throw4.C @@ -0,0 +1,13 @@ +// PR c++/112437 +// { dg-do compile } + +struct S {}; + +S +foo (S s) +try { + throw s; +} +catch (...) { + throw s; +} diff --git a/gcc/testsuite/g++.dg/ext/attr-section2.C b/gcc/testsuite/g++.dg/ext/attr-section2.C index 7c9221b..81567c1 100644 --- a/gcc/testsuite/g++.dg/ext/attr-section2.C +++ b/gcc/testsuite/g++.dg/ext/attr-section2.C @@ -6,4 +6,4 @@ template<class T> template int var<int>; -// { dg-final { scan-assembler {.(section|csect)[ \t]+.foo} } } +// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.foo} } } diff --git a/gcc/testsuite/g++.dg/ext/attr-section2a.C b/gcc/testsuite/g++.dg/ext/attr-section2a.C index 4fa898c..97b3a10 100644 --- a/gcc/testsuite/g++.dg/ext/attr-section2a.C +++ b/gcc/testsuite/g++.dg/ext/attr-section2a.C @@ -11,4 +11,4 @@ int A<T>::var = 42; template struct A<int>; -// { dg-final { scan-assembler {.(section|csect)[ \t]+.foo} } } +// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.foo} } } diff --git a/gcc/testsuite/g++.dg/ext/attr-section2b.C b/gcc/testsuite/g++.dg/ext/attr-section2b.C index 9398773..bef0377 100644 --- a/gcc/testsuite/g++.dg/ext/attr-section2b.C +++ b/gcc/testsuite/g++.dg/ext/attr-section2b.C @@ -9,4 +9,4 @@ int* fun() { template int* fun<int>(); -// { dg-final { scan-assembler {.(section|csect)[ \t]+.foo} } } +// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.foo} } } diff --git a/gcc/testsuite/g++.dg/ext/frounding-math1.C b/gcc/testsuite/g++.dg/ext/frounding-math1.C new file mode 100644 index 0000000..ecc46fd --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/frounding-math1.C @@ -0,0 +1,8 @@ +// PR c++/109359 +// { dg-additional-options -frounding-math } + +// For a while we were emitting two doubles (4 .long directives) as the value +// of a float array; it should only be two .longs. + +// { dg-final { scan-assembler-times "long" 2 { target x86_64-*-* } } } +float xs[] = {0.001914, 0.630539}; diff --git a/gcc/testsuite/g++.dg/hwasan/hwasan.exp b/gcc/testsuite/g++.dg/hwasan/hwasan.exp index 597033e..12a7a35 100644 --- a/gcc/testsuite/g++.dg/hwasan/hwasan.exp +++ b/gcc/testsuite/g++.dg/hwasan/hwasan.exp @@ -22,7 +22,8 @@ load_lib hwasan-dg.exp # Initialize `dg'. dg-init -hwasan_init +# libhwasan uses libstdc++ but we assume that's added by the g++ impl. +hwasan_init 0 # Main loop. if [check_effective_target_fsanitize_hwaddress] { diff --git a/gcc/testsuite/g++.dg/opt/pr113705.C b/gcc/testsuite/g++.dg/opt/pr113705.C new file mode 100644 index 0000000..39fb047 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr113705.C @@ -0,0 +1,68 @@ +// PR middle-end/113705 +// { dg-do compile { target c++17 } } +// { dg-options "-O2 -w" } + +void foo (); +template <typename T> struct A : T { long bar () const; }; +int a; + +template <typename T> +long +A<T>::bar () const +{ + return this->baz ()[a]; +} + +struct B { + struct { long b[1]; long c; } u; + unsigned d; + int e; + B (const B &); + ~B (); + const long *baz () const; + unsigned qux () const; +}; + +B::B (const B &) +{ + if (__builtin_expect (e, 0)) + u.c = 0; +} + +B::~B () +{ + if (__builtin_expect (e, 0)) + foo (); +} + +const long * +B::baz () const +{ + return u.b; +} + +unsigned +B::qux () const +{ + return d; +} + +struct C { A<B> corge () const; A<B> *f; }; + +A<B> +C::corge () const +{ + return f[1]; +} + +void +test (C r, long *h, unsigned short *d) +{ + for (int j = 0; j < 8; ++j) + { + A g = r.corge (); + *d = g.qux (); + for (unsigned i = 0; i < *d; ++i) + *h++ = g.bar (); + } +} diff --git a/gcc/testsuite/g++.dg/parse/pr113788.C b/gcc/testsuite/g++.dg/parse/pr113788.C new file mode 100644 index 0000000..d255037 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/pr113788.C @@ -0,0 +1,20 @@ +// PR c++/113788 +// { dg-do compile { target c++11 } } + +struct S { int a, b; }; +struct U { + void foo () { this int g = 1; } // { dg-error "expected ';' before 'int'" } +}; +this auto h = 1; // { dg-error "expected unqualified-id before 'this'" } + +int +main () +{ + S s = { 1, 2 }; + short t[3] = { 3, 4, 5 }; + this auto &[a, b] = s; // { dg-error "invalid use of 'this' in non-member function" } + this auto &[c, d, e] = t; // { dg-error "invalid use of 'this' in non-member function" } + this int f = 1; // { dg-error "invalid use of 'this' in non-member function" } + for (this auto &i : t) // { dg-error "invalid use of 'this' in non-member function" } + ; // { dg-error "expected" } +} // { dg-error "expected" } diff --git a/gcc/testsuite/g++.dg/template/nontype30.C b/gcc/testsuite/g++.dg/template/nontype30.C new file mode 100644 index 0000000..926a772 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/nontype30.C @@ -0,0 +1,13 @@ +// PR c++/113644 + +template<int> struct A { }; + +template<class T> void f(A<42>); +template<class T> void f(A<T::value>); + +struct B { static const int value = 42; }; + +int main() { + A<42> a; + f<B>(a); // { dg-error "ambiguous" } +} diff --git a/gcc/testsuite/g++.dg/template/ttp42.C b/gcc/testsuite/g++.dg/template/ttp42.C new file mode 100644 index 0000000..da08e85 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp42.C @@ -0,0 +1,14 @@ +// PR c++/112737 +// { dg-do compile { target c++17 } } + +template<template<class> class TT> +decltype(TT{42}) f(); // #1 + +template<template<class> class TT> +decltype(TT{42}) f(); // redeclaration of #1 + +template<class T> struct A { A(T); }; + +int main() { + f<A>(); +} diff --git a/gcc/testsuite/g++.dg/template/ttp43.C b/gcc/testsuite/g++.dg/template/ttp43.C new file mode 100644 index 0000000..afafd32 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ttp43.C @@ -0,0 +1,17 @@ +// PR c++/112737 +// { dg-do compile { target c++11 } } + +template<template<class> class, class T> +void g(T); + +template<template<class> class TT, class T> +decltype(g<TT>(T{})) f(T); // #1 + +template<template<class> class TT, class T> +decltype(g<TT>(T{})) f(T); // redeclaration of #1 + +template<class T> struct A; + +int main() { + f<A>(0); +} diff --git a/gcc/testsuite/g++.dg/ubsan/ubsan.exp b/gcc/testsuite/g++.dg/ubsan/ubsan.exp index d719707..4bab1b8 100644 --- a/gcc/testsuite/g++.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/g++.dg/ubsan/ubsan.exp @@ -22,7 +22,8 @@ load_lib ubsan-dg.exp # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ but we assume that's added by the g++ impl. +ubsan_init 0 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C new file mode 100644 index 0000000..e088c17 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference18.C @@ -0,0 +1,24 @@ +// PR c++/110358 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Don't warn for std::span-like classes. + +template <typename T> +struct Span { + T* data_; + int len_; + + [[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& { return data_[n]; } + [[nodiscard]] constexpr auto front() const noexcept -> T& { return data_[0]; } + [[nodiscard]] constexpr auto back() const noexcept -> T& { return data_[len_ - 1]; } +}; + +auto get() -> Span<int>; + +auto f() -> int { + int const& a = get().front(); // { dg-bogus "dangling reference" } + int const& b = get().back(); // { dg-bogus "dangling reference" } + int const& c = get()[0]; // { dg-bogus "dangling reference" } + + return a + b + c; +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C new file mode 100644 index 0000000..053467d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference19.C @@ -0,0 +1,25 @@ +// PR c++/110358 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Like Wdangling-reference18.C but not actually a span-like class. + +template <typename T> +struct Span { + T* data_; + int len_; + ~Span (); + + [[nodiscard]] constexpr auto operator[](int n) const noexcept -> T& { return data_[n]; } + [[nodiscard]] constexpr auto front() const noexcept -> T& { return data_[0]; } + [[nodiscard]] constexpr auto back() const noexcept -> T& { return data_[len_ - 1]; } +}; + +auto get() -> Span<int>; + +auto f() -> int { + int const& a = get().front(); // { dg-warning "dangling reference" } + int const& b = get().back(); // { dg-warning "dangling reference" } + int const& c = get()[0]; // { dg-warning "dangling reference" } + + return a + b + c; +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C new file mode 100644 index 0000000..84138f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference20.C @@ -0,0 +1,44 @@ +// PR c++/109640 +// { dg-do compile { target c++20 } } +// { dg-options "-Wdangling-reference" } +// Don't warn for std::span-like classes. + +#include <iterator> +#include <span> + +template <typename T> +struct MySpan +{ + MySpan(T* data, std::size_t size) : + data_(data), + size_(size) + {} + + T& operator[](std::size_t idx) { return data_[idx]; } + +private: + T* data_; + std::size_t size_; +}; + +template <typename T, std::size_t n> +MySpan<T const> make_my_span(T const(&x)[n]) +{ + return MySpan(std::begin(x), n); +} + +template <typename T, std::size_t n> +std::span<T const> make_span(T const(&x)[n]) +{ + return std::span(std::begin(x), n); +} + +int main() +{ + int x[10]{}; + [[maybe_unused]] int const& y1{make_my_span(x)[0]}; + [[maybe_unused]] int const& y2{make_span(x)[0]}; + using T = int[10]; + [[maybe_unused]] int const& y3{make_my_span(T{})[0]}; // { dg-warning "dangling reference" } + [[maybe_unused]] int const& y4{make_span(T{})[0]}; // { dg-warning "dangling reference" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference21.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference21.C new file mode 100644 index 0000000..e1b6e3d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference21.C @@ -0,0 +1,44 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } +// Reduced from config/aarch64/aarch64-early-ra.cc. + +template <typename T> struct array_slice { + using iterator = T *; + iterator begin(); + iterator end(); + iterator m_base; +}; + +struct allocno_group_info { }; + +char recog_data_2; +int record_constraints_op; +struct early_ra { + using operand_mask = int; + struct allocno_info { + int is_earlyclobbered; + }; + struct allocno_subgroup { + array_slice<allocno_info> allocnos(); + allocno_group_info *group; + }; + allocno_subgroup get_allocno_subgroup(int); + void record_constraints(); +}; +void early_ra::record_constraints() { + operand_mask earlyclobber_operands, matched_operands, unmatched_operands, + matches_operands, op_mask = operand_mask(); + auto record_operand = [&](int, int) { + operand_mask overlaps; + matches_operands |= overlaps; + }; + for (int opno = 0; recog_data_2; ++opno) { + operand_mask op_mask = earlyclobber_operands |= op_mask; + if (0) + record_operand(1, 0); + } + if (op_mask || (matched_operands & unmatched_operands && 0)) + for (auto &allocno : get_allocno_subgroup(record_constraints_op).allocnos()) + allocno.is_earlyclobbered = true; +} + diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols1.C b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C new file mode 100644 index 0000000..53e0abc --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C @@ -0,0 +1,66 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +int foo () +{ + return 1; +} + +__attribute__((target_version("dotprod"))) +int foo () +{ + return 3; +} +__attribute__((target_version("sve+sve2"))) +int foo () +{ + return 5; +} + +__attribute__((target_version("sve+sve2"))) +int foo (int) +{ + return 6; +} + +__attribute__((target_version("dotprod"))) +int foo (int) +{ + return 4; +} + +int foo (int) +{ + return 2; +} + + +int bar() +{ + return foo (); +} + +int bar(int x) +{ + return foo (x); +} + +/* When updating any of the symbol names in these tests, make sure to also + update any tests for their absence in mv-symbolsN.C */ + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C new file mode 100644 index 0000000..f0c7967 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo () +{ + return 1; +} + +__attribute__((target_version("dotprod"))) +int foo () +{ + return 3; +} +__attribute__((target_version("sve+sve2"))) +int foo () +{ + return 5; +} + +__attribute__((target_version("sve+sve2"))) +int foo (int) +{ + return 6; +} + +__attribute__((target_version("dotprod"))) +int foo (int) +{ + return 4; +} + +__attribute__((target_version("default"))) +int foo (int) +{ + return 2; +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C new file mode 100644 index 0000000..3d30e27 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo (); + +__attribute__((target_version("dotprod"))) +int foo (); + +__attribute__((target_version("sve+sve2"))) +int foo (); + +__attribute__((target_version("default"))) +int foo (int); + +__attribute__((target_version("dotprod"))) +int foo (int); + +__attribute__((target_version("sve+sve2"))) +int foo (int); + +int bar() +{ + return foo (); +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C new file mode 100644 index 0000000..73e3279 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo () +{ + return 1; +} + +__attribute__((target_version("dotprod"))) +int foo (); + +__attribute__((target_version("sve+sve2"))) +int foo (); + +__attribute__((target_version("default"))) +int foo (int) +{ + return 2; +} + +__attribute__((target_version("dotprod"))) +int foo (int); + +__attribute__((target_version("sve+sve2"))) +int foo (int); + + +int bar() +{ + return foo (); +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C new file mode 100644 index 0000000..05d1379 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_version("default"))) +int foo (); + +__attribute__((target_version("dotprod"))) +int foo () +{ + return 3; +} +__attribute__((target_version("sve+sve2"))) +int foo () +{ + return 5; +} + +__attribute__((target_version("default"))) +int foo (int); + +__attribute__((target_version("dotprod"))) +int foo (int) +{ + return 4; +} + +__attribute__((target_version("sve+sve2"))) +int foo (int) +{ + return 6; +} + + +int bar() +{ + return foo (); +} + +/* When updating any of the symbol names in these tests, make sure to also + update any tests for their absence in mvc-symbolsN.C */ + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C new file mode 100644 index 0000000..2dd7c79 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo () +{ + return 1; +} + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int) +{ + return 2; +} + +int bar() +{ + return foo (); +} + +int bar(int x) +{ + return foo (x); +} + +/* When updating any of the symbol names in these tests, make sure to also + update any tests for their absence in mvc-symbolsN.C */ + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C new file mode 100644 index 0000000..75b9c12 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo () +{ + return 1; +} + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int) +{ + return 2; +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C new file mode 100644 index 0000000..82e777c --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo (); + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int); + +int bar() +{ + return foo (); +} + +int bar(int x) +{ + return foo (x); +} + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */ diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C new file mode 100644 index 0000000..6c86ae6 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ + +__attribute__((target_clones("default", "dotprod", "sve+sve2"))) +int foo (); + +__attribute__((target_clones("sve+sve2", "dotprod", "default"))) +int foo (int); + +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */ + +/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */ +/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */ diff --git a/gcc/testsuite/g++.target/arm/bti_thunk.C b/gcc/testsuite/g++.target/arm/bti_thunk.C new file mode 100644 index 0000000..23c1acc --- /dev/null +++ b/gcc/testsuite/g++.target/arm/bti_thunk.C @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target arm_arch_v8_1m_main_pacbti_ok } */ +/* { dg-add-options arm_arch_v8_1m_main_pacbti } */ +/* { dg-additional-options "-mbranch-protection=bti" }*/ + +#include <stdio.h> + +struct C18 { + virtual void f7(); +}; + +struct C19 : virtual C18 { + virtual void f7(); +}; + +void C19::f7() { + printf("foo\n"); +} + +/* { dg-final { scan-assembler-times "\tbti" 2 } } */ diff --git a/gcc/testsuite/g++.target/i386/pr113560.C b/gcc/testsuite/g++.target/i386/pr113560.C new file mode 100644 index 0000000..179b68f --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr113560.C @@ -0,0 +1,19 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-Ofast -std=c++23 -march=znver4" } */ + +#include <immintrin.h> +auto f(char *buf, unsigned long long in) noexcept +{ + unsigned long long hi{}; + auto lo{_mulx_u64(in, 0x2af31dc462ull, &hi)}; + lo = _mulx_u64(lo, 100, &hi); + __builtin_memcpy(buf + 2, &hi, 2); + return buf + 10; +} + +/* { dg-final { scan-assembler-times "mulx" 1 } } */ +/* { dg-final { scan-assembler-times "mulq" 1 } } */ +/* { dg-final { scan-assembler-not "addq" } } */ +/* { dg-final { scan-assembler-not "adcq" } } */ +/* { dg-final { scan-assembler-not "salq" } } */ +/* { dg-final { scan-assembler-not "shldq" } } */ diff --git a/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C new file mode 100644 index 0000000..ff1f7c1 --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-1.C @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-inline -march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=always -mdirect-extern-access" } */ + +struct A { + virtual ~A(); +}; + +struct B : virtual A {}; +void var() { B(); } + +/* { dg-final { scan-assembler "pcalau12i\t\[^\n\]*%pc_hi20\\(\\.LTHUNK0\\)\n\taddi\\.d\t\[^\n\]*%pc_lo12\\(\\\.LTHUNK0\\)\n\tlu32i\\.d\t\[^\n\]*%pc64_lo20\\(\\.LTHUNK0\\)\n\tlu52i\\.d\t\[^\n\]*%pc64_hi12\\(\\.LTHUNK0\\)" } } */ diff --git a/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C new file mode 100644 index 0000000..c9aa16b --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-2.C @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-inline -march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=auto -mdirect-extern-access" } */ + +#include "cmodel-extreme-mi-thunk-1.C" + +/* { dg-final { scan-assembler "pcalau12i\t\[^\n\]*%pc_hi20\\(\\.LTHUNK0\\)\n\taddi\\.d\t\[^\n\]*%pc_lo12\\(\\\.LTHUNK0\\)\n\tlu32i\\.d\t\[^\n\]*%pc64_lo20\\(\\.LTHUNK0\\)\n\tlu52i\\.d\t\[^\n\]*%pc64_hi12\\(\\.LTHUNK0\\)" } } */ diff --git a/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C new file mode 100644 index 0000000..afb86c8 --- /dev/null +++ b/gcc/testsuite/g++.target/loongarch/cmodel-extreme-mi-thunk-3.C @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-inline -march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=none -mdirect-extern-access" } */ + +#include "cmodel-extreme-mi-thunk-1.C" + +/* { dg-final { scan-assembler "la.local\t\[^\n\]*\\.LTHUNK0" } } */ diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-1.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-1.c new file mode 100644 index 0000000..5788cb4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-1.c @@ -0,0 +1,5 @@ +void +f () +{ + (_Bool) (1 << -1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-10.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-10.c new file mode 100644 index 0000000..fdd9a29 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-10.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-div-by-zero" } */ + +enum e : bool { X }; + +enum e +f () +{ + return 0 / 0; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-11.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-11.c new file mode 100644 index 0000000..8126034 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-11.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-overflow" } */ + +enum e : bool { X }; + +void +f () +{ + (enum e) (__INT_MAX__ + 1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-12.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-12.c new file mode 100644 index 0000000..d11fcf6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-12.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-overflow" } */ + +enum e : bool { X }; + +enum e +f () +{ + return __INT_MAX__ + 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-2.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-2.c new file mode 100644 index 0000000..785e291 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-2.c @@ -0,0 +1,5 @@ +void +f () +{ + (_Bool) (0 / 0); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-3.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-3.c new file mode 100644 index 0000000..21099bc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-3.c @@ -0,0 +1,5 @@ +_Bool +f () +{ + return 1 << -1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-4.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-4.c new file mode 100644 index 0000000..95c68e5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-4.c @@ -0,0 +1,5 @@ +_Bool +f () +{ + return 0 / 0; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-5.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-5.c new file mode 100644 index 0000000..1047355 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-5.c @@ -0,0 +1,5 @@ +void +f () +{ + (_Bool) (__INT_MAX__ + 1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-6.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-6.c new file mode 100644 index 0000000..213f79b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-6.c @@ -0,0 +1,5 @@ +_Bool +f () +{ + return __INT_MAX__ + 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-7.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-7.c new file mode 100644 index 0000000..466f45f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-7.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-shift-count-negative" } */ + +enum e : bool { X }; + +void +f () +{ + (enum e) (1 << -1); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-8.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-8.c new file mode 100644 index 0000000..67f3395 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-8.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-div-by-zero" } */ + +enum e : bool { X }; + +void +f () +{ + (enum e) (0 / 0); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111059-9.c b/gcc/testsuite/gcc.c-torture/compile/pr111059-9.c new file mode 100644 index 0000000..f88096d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111059-9.c @@ -0,0 +1,9 @@ +/* { dg-options "-std=gnu23 -Wno-shift-count-negative" } */ + +enum e : bool { X }; + +enum e +f () +{ + return 1 << -1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111911-1.c b/gcc/testsuite/gcc.c-torture/compile/pr111911-1.c new file mode 100644 index 0000000..350f4cc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111911-1.c @@ -0,0 +1,7 @@ +int +main (void) +{ + if (!(_Bool)(__INT_MAX__ + 1) / !(_Bool)(__INT_MAX__ + 1)) + ; + return 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr111911-2.c b/gcc/testsuite/gcc.c-torture/compile/pr111911-2.c new file mode 100644 index 0000000..28b69c4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr111911-2.c @@ -0,0 +1,11 @@ +/* { dg-options "-std=gnu23 -Wno-overflow -Wno-div-by-zero" } */ + +enum e : bool { X }; + +int +main (void) +{ + if (!(enum e)(__INT_MAX__ + 1) / !(enum e)(__INT_MAX__ + 1)) + ; + return 1; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr113759.c b/gcc/testsuite/gcc.c-torture/compile/pr113759.c new file mode 100644 index 0000000..742c1b2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr113759.c @@ -0,0 +1,20 @@ +/* PR tree-optimization/113759 */ + +extern short t[]; + +int +foo (int c, int b) +{ + if (b < 0) + __builtin_unreachable (); + if (c <= 0) + __builtin_unreachable (); + int d; + for (; c >= 0; c--) + { + int a = b + c; + d = t[a]; + t[a] = 0; + } + return d; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c b/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c new file mode 100644 index 0000000..d9015ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/deref-before-check-pr113253.c @@ -0,0 +1,154 @@ +/* Regression test for PR analyzer/113253 which was showing analyzer + differences with and without -g. + + C only: reduced reproducer doesn't easily work with C++. */ + +/* { dg-additional-options "-O2 -g" } */ + +typedef long int ptrdiff_t; +typedef unsigned long int uintptr_t; +typedef long int EMACS_INT; +enum +{ + EMACS_INT_WIDTH = 64, + VALBITS = EMACS_INT_WIDTH - 3, +}; +typedef struct Lisp_X* Lisp_Word; +enum Lisp_Type +{ + Lisp_Symbol = 0, + Lisp_Vectorlike = 5, +}; +typedef Lisp_Word Lisp_Object; +static inline EMACS_INT(XLI)(Lisp_Object o) +{ + return ((EMACS_INT)(o)); +} +static inline void*(XLP)(Lisp_Object o) +{ + return ((void*)(o)); +} +struct Lisp_Symbol +{}; +typedef uintptr_t Lisp_Word_tag; +extern struct Lisp_Symbol lispsym[1608]; +union vectorlike_header +{ + ptrdiff_t size; +}; +enum pvec_type +{ + PVEC_MARKER, +}; +enum More_Lisp_Bits +{ + PSEUDOVECTOR_SIZE_BITS = 12, + PSEUDOVECTOR_REST_BITS = 12, + PSEUDOVECTOR_AREA_BITS = PSEUDOVECTOR_SIZE_BITS + PSEUDOVECTOR_REST_BITS, + PVEC_TYPE_MASK = 0x3f << PSEUDOVECTOR_AREA_BITS +}; +static inline _Bool +PSEUDOVECTORP(Lisp_Object a, int code) +{ + return ( + ((((union vectorlike_header*)((uintptr_t)XLP((a)) - + (uintptr_t)( + (Lisp_Word_tag)(Lisp_Vectorlike) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < + (9223372036854775807L)) + ? 0 + : VALBITS)))) + ->size & + (((9223372036854775807L) - (9223372036854775807L) / 2) | + PVEC_TYPE_MASK)) == + (((9223372036854775807L) - (9223372036854775807L) / 2) | + ((code) << PSEUDOVECTOR_AREA_BITS)))); +} +static inline Lisp_Object +make_lisp_symbol(struct Lisp_Symbol* sym) +{ + Lisp_Object a = ((Lisp_Word)( + ((Lisp_Word_tag)(Lisp_Symbol) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < (9223372036854775807L)) + ? 0 + : VALBITS)))); + return a; +} +static inline Lisp_Object +builtin_lisp_symbol(int index) +{ + return make_lisp_symbol(&lispsym[index]); +} +static inline _Bool(BASE_EQ)(Lisp_Object x, Lisp_Object y) +{ + return (XLI(x) == XLI(y)); +} +static inline _Bool(NILP)(Lisp_Object x) +{ + return BASE_EQ(x, builtin_lisp_symbol(0)); +} +struct thread_state +{ + struct buffer* m_current_buffer; +}; +extern struct thread_state* current_thread; +struct Lisp_Marker +{ + struct buffer* buffer; +}; +static inline _Bool +MARKERP(Lisp_Object x) +{ + return PSEUDOVECTORP(x, PVEC_MARKER); +} +static inline struct Lisp_Marker* +XMARKER(Lisp_Object a) +{ + return (( + struct Lisp_Marker*)((uintptr_t)XLP(a) - + (uintptr_t)((Lisp_Word_tag)(Lisp_Vectorlike) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < + (9223372036854775807L)) + ? 0 + : VALBITS)))); +} +extern void +unchain_marker(); +struct buffer +{ + Lisp_Object name_; +}; +static inline struct buffer* +XBUFFER(Lisp_Object a) +{ + return ( + (struct buffer*)((uintptr_t)XLP(a) - + (uintptr_t)((Lisp_Word_tag)(Lisp_Vectorlike) + << (((0x7fffffffffffffffL >> (3 - 1)) / 2 < + (9223372036854775807L)) + ? 0 + : VALBITS)))); +} +static inline _Bool +BUFFER_LIVE_P(struct buffer* b) +{ + return !NILP(((b)->name_)); +} +static inline struct buffer* +decode_buffer(Lisp_Object b) +{ + return NILP(b) ? (current_thread->m_current_buffer) : (XBUFFER(b)); +} +static struct buffer* +live_buffer(Lisp_Object buffer) +{ + struct buffer* b = decode_buffer(buffer); + return BUFFER_LIVE_P(b) ? b : ((void*)0); +} +Lisp_Object +set_marker_internal(Lisp_Object position, Lisp_Object buffer) +{ + struct buffer* b = live_buffer(buffer); + if (NILP(position) || (MARKERP(position) && !XMARKER(position)->buffer) || !b) /* { dg-bogus "Wanalyzer-deref-before-check" } */ + unchain_marker(); +} diff --git a/gcc/testsuite/gcc.dg/asan/asan.exp b/gcc/testsuite/gcc.dg/asan/asan.exp index 10c6973..6b8ebf0 100644 --- a/gcc/testsuite/gcc.dg/asan/asan.exp +++ b/gcc/testsuite/gcc.dg/asan/asan.exp @@ -24,7 +24,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ so make sure we provide paths for it. +asan_init 1 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/gcc.dg/asan/pr110676.c b/gcc/testsuite/gcc.dg/asan/pr110676.c new file mode 100644 index 0000000..0ae6fdd --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/pr110676.c @@ -0,0 +1,14 @@ +/* PR sanitizer/110676 */ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ +/* { dg-shouldfail "asan" } */ + +int +main () +{ + char s[1] = "A"; + return __builtin_strlen (s); +} + +/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow on address.*(\n|\r\n|\r)" } */ +/* { dg-output "READ of size.*" } */ diff --git a/gcc/testsuite/gcc.dg/bitint-79.c b/gcc/testsuite/gcc.dg/bitint-79.c new file mode 100644 index 0000000..e7422c0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-79.c @@ -0,0 +1,16 @@ +/* PR tree-optimization/113639 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +int j, k; +#if __BITINT_MAXWIDTH__ >= 162 +struct S { _BitInt(162) n; }; +void bar (_BitInt(162) x); + +void +foo (struct S s) +{ + bar (s.n * j); + (void) (s.n * k); +} +#endif diff --git a/gcc/testsuite/gcc.dg/bitint-80.c b/gcc/testsuite/gcc.dg/bitint-80.c new file mode 100644 index 0000000..0ad0935 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-80.c @@ -0,0 +1,15 @@ +/* PR debug/113637 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-g -std=c23" } */ + +#if __BITINT_MAXWIDTH__ >= 639 +typedef _BitInt(639) B; +#else +typedef _BitInt(63) B; +#endif + +void +foo (B n) +{ + extern void bar (int [][n]); +} diff --git a/gcc/testsuite/gcc.dg/bitint-81.c b/gcc/testsuite/gcc.dg/bitint-81.c new file mode 100644 index 0000000..33162fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-81.c @@ -0,0 +1,12 @@ +/* PR middle-end/113699 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +void +foo (void) +{ +#if __BITINT_MAXWIDTH__ >= 129 + _BitInt(129) i; + __asm__ ("" : : "rm" (i)); +#endif +} diff --git a/gcc/testsuite/gcc.dg/bitint-82.c b/gcc/testsuite/gcc.dg/bitint-82.c new file mode 100644 index 0000000..4ea86f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-82.c @@ -0,0 +1,18 @@ +/* PR tree-optimization/113692 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +#if __BITINT_MAXWIDTH__ >= 135 +_BitInt(135) i; +#else +_BitInt(63) i; +#endif + +void * +foo (void) +{ + void *ret = 0; + if (i & 1) + ret = (void *) 1; + return ret; +} diff --git a/gcc/testsuite/gcc.dg/bitint-83.c b/gcc/testsuite/gcc.dg/bitint-83.c new file mode 100644 index 0000000..96d3f71 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-83.c @@ -0,0 +1,23 @@ +/* PR tree-optimization/113691 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=gnu11 -w" } */ + +#if __BITINT_MAXWIDTH__ >= 944 +_BitInt (944) i; +#else +_BitInt (63) i; +#endif + +void foo (); + +void +bar () +{ + foo (i); +} + +void +foo (int *p) +{ + *p = 0; +} diff --git a/gcc/testsuite/gcc.dg/bitint-84.c b/gcc/testsuite/gcc.dg/bitint-84.c new file mode 100644 index 0000000..dffdf16 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-84.c @@ -0,0 +1,32 @@ +/* PR tree-optimization/113737 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=c23" } */ + +#if __BITINT_MAXWIDTH__ >= 129 +_BitInt(129) a; +#else +_BitInt(63) a; +#endif + +int b[1], c; + +int +foo (void) +{ + switch (a) + case 0: + case 2: + return 1; + return 0; +} + +void +bar (int i) +{ + for (;; ++i) + { + c = b[i]; + if (!foo ()) + __asm__ (""); + } +} diff --git a/gcc/testsuite/gcc.dg/bitint-85.c b/gcc/testsuite/gcc.dg/bitint-85.c new file mode 100644 index 0000000..f2301cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-85.c @@ -0,0 +1,5 @@ +/* PR c/113740 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-std=c23" } */ + +struct S { unsigned _BitInt(32) : 0; }; diff --git a/gcc/testsuite/gcc.dg/bitint-86.c b/gcc/testsuite/gcc.dg/bitint-86.c new file mode 100644 index 0000000..4e5761a --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-86.c @@ -0,0 +1,40 @@ +/* PR tree-optimization/113736 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -std=gnu23 -w" } */ + +#if __BITINT_MAXWIDTH__ >= 710 +struct S { _BitInt(710) a; }; +struct T { struct S b[4]; }; + +#ifdef __x86_64__ +#define SEG __seg_gs +#elif defined __i386__ +#define SEG __seg_fs +#else +#define SEG +#endif + +void +foo (__seg_gs struct T *p) +{ + struct S s; + p->b[0] = s; +} + +void +bar (__seg_gs struct T *p, _BitInt(710) x, int y, double z) +{ + p->b[0].a = x + 42; + p->b[1].a = x << y; + p->b[2].a = x >> y; + p->b[3].a = z; +} + +int +baz (__seg_gs struct T *p, _BitInt(710) x, _BitInt(710) y) +{ + return __builtin_add_overflow (x, y, &p->b[1].a); +} +#else +int i; +#endif diff --git a/gcc/testsuite/gcc.dg/bitint-87.c b/gcc/testsuite/gcc.dg/bitint-87.c new file mode 100644 index 0000000..4dbd7ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-87.c @@ -0,0 +1,24 @@ +/* PR tree-optimization/113753 */ +/* { dg-do compile { target bitint575 } } */ +/* { dg-options "-std=gnu23" } */ + +_BitInt(161) a = 1461501637330902918203684832716283019655932542975wb / 2wb * 2wb; +_BitInt(160) b = 730750818665451459101842416358141509827966271487wb / 2wb * 2wb; +_BitInt(159) c = 365375409332725729550921208179070754913983135743wb / 2wb * 2wb; +_BitInt(129) d = 340282366920938463463374607431768211455wb / 2wb * 2wb; +_BitInt(128) e = 170141183460469231731687303715884105727wb / 2wb * 2wb; +_BitInt(161) f = (-1461501637330902918203684832716283019655932542975wb - 1wb) / 2wb * 2wb; +_BitInt(160) g = (-730750818665451459101842416358141509827966271487wb - 1wb) / 2wb * 2wb; +_BitInt(159) h = (-365375409332725729550921208179070754913983135743wb - 1wb) / 2wb * 2wb; +_BitInt(129) i = (-340282366920938463463374607431768211455wb - 1wb) / 2wb * 2wb; +_BitInt(128) j = (-170141183460469231731687303715884105727wb - 1wb) / 2wb * 2wb; +_BitInt(161) k = 1461501637330902918203684832716283019655932542975wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(161\\\)' results in" } */ +_BitInt(160) l = 730750818665451459101842416358141509827966271487wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(160\\\)' results in" } */ +_BitInt(159) m = 365375409332725729550921208179070754913983135743wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(159\\\)' results in" } */ +_BitInt(129) n = 340282366920938463463374607431768211455wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(129\\\)' results in" } */ +_BitInt(128) o = 170141183460469231731687303715884105727wb / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(128\\\)' results in" } */ +_BitInt(161) p = (-1461501637330902918203684832716283019655932542975wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(161\\\)' results in" } */ +_BitInt(160) q = (-730750818665451459101842416358141509827966271487wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(160\\\)' results in" } */ +_BitInt(159) r = (-365375409332725729550921208179070754913983135743wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(159\\\)' results in" } */ +_BitInt(129) s = (-340282366920938463463374607431768211455wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(129\\\)' results in" } */ +_BitInt(128) t = (-170141183460469231731687303715884105727wb - 1wb) / 2wb * 3wb; /* { dg-warning "integer overflow in expression of type '_BitInt\\\(128\\\)' results in" } */ diff --git a/gcc/testsuite/gcc.dg/c23-enum-10.c b/gcc/testsuite/gcc.dg/c23-enum-10.c new file mode 100644 index 0000000..dd5f345 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-enum-10.c @@ -0,0 +1,6 @@ +/* PR c/112571. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +enum X : typeof (enum X { A }); /* { dg-error "declared with but defined without fixed underlying type" } */ +/* { dg-error "invalid 'enum' underlying type" "invalid" { target *-*-* } .-1 } */ diff --git a/gcc/testsuite/gcc.dg/c23-enum-9.c b/gcc/testsuite/gcc.dg/c23-enum-9.c new file mode 100644 index 0000000..10bb493 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-enum-9.c @@ -0,0 +1,8 @@ +/* PR c/112571. */ +/* { dg-do compile } */ +/* { dg-options "-std=c23" } */ + +enum h : typeof (enum h { D }) { D }; /* { dg-error "declared with but defined without fixed underlying type" } */ +/* { dg-error "invalid 'enum' underlying type" "invalid" { target *-*-* } .-1 } */ +/* { dg-error "nested redefinition" "nested" { target *-*-* } .-2 } */ +/* { dg-error "conflicting redefinition" "conflicting" { target *-*-* } .-3 } */ diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c b/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c index 3b50e9f..7dd1148 100644 --- a/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/inline5.c @@ -9,7 +9,7 @@ /* We do not know which is output first so look for both invalid abstract origins on the lexical blocks (knowing that the abstract instance has no attribute following the DW_TAG_lexical_block. */ -/* { dg-final { scan-assembler-not "\\(DIE \\(0x(\[0-9a-f\]*)\\) DW_TAG_lexical_block\\)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT.*DW_TAG_lexical_block\\)\[^#/!@;\\|x\]*x\\1\[^#/!@;\\|\]*\[#/!@;\\|\] +DW_AT_abstract_origin" { xfail { { *-*-aix* || *-*-solaris2.* } && { ! gas } } } } } */ +/* { dg-final { scan-assembler-not "\\(DIE \\(0x(\[0-9a-f\]*)\\) DW_TAG_lexical_block\\)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT.*DW_TAG_lexical_block\\)\[^#/!@;\\|x\]*x\\1\[^#/!@;\\|\]*\[#/!@;\\|\] +DW_AT_abstract_origin" } } */ /* { dg-final { scan-assembler-not "DW_TAG_lexical_block\\)\[^#/!@;\\|x\]*x(\[0-9a-f\]*)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT_abstract_origin.*\\(DIE \\(0x\\1\\) DW_TAG_lexical_block\\)\[^#/!@;\\|\]*\[#/!@;\\|\]+ +DW_AT" } } */ int foo (int i) diff --git a/gcc/testsuite/gcc.dg/hwasan/hwasan.exp b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp index 802f171..88327d3 100644 --- a/gcc/testsuite/gcc.dg/hwasan/hwasan.exp +++ b/gcc/testsuite/gcc.dg/hwasan/hwasan.exp @@ -24,7 +24,8 @@ load_lib hwasan-dg.exp # Initialize `dg'. dg-init -hwasan_init +# libhwasan uses libstdc++ so make sure we provide paths for it. +hwasan_init 1 # Main loop. if [check_effective_target_fsanitize_hwaddress] { diff --git a/gcc/testsuite/gcc.dg/pr113438.c b/gcc/testsuite/gcc.dg/pr113438.c new file mode 100644 index 0000000..5612ee4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113438.c @@ -0,0 +1,7 @@ +/* PR113438 + * { dg-do compile } + * { dg-options "-std=c23 -g" } */ + +void g(struct foo { int x; } a); +void g(struct foo { int x; } a); + diff --git a/gcc/testsuite/gcc.dg/pr113693.c b/gcc/testsuite/gcc.dg/pr113693.c new file mode 100644 index 0000000..a6f5519 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113693.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -fdbg-cnt=vect_loop:1" } */ + +_BitInt(837) g, h; + +void +fn1(void) +{ + for (; g; g++) + for (; h; h++) + ; +} +/* { dg-message "dbgcnt" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/pr113722.c b/gcc/testsuite/gcc.dg/pr113722.c new file mode 100644 index 0000000..74b9e49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113722.c @@ -0,0 +1,22 @@ +/* PR middle-end/113722 */ +/* { dg-do run { target int128 } } */ +/* { dg-options "-O2" } */ + +int +main () +{ + unsigned __int128 a = __builtin_bswap128 ((unsigned __int128) 2); + if (a != ((unsigned __int128) 2) << 120) + __builtin_abort (); + a = __builtin_bswap128 ((unsigned __int128) 0xdeadbeefULL); + if (a != ((unsigned __int128) 0xefbeaddeULL) << 96) + __builtin_abort (); + a = __builtin_bswap128 (((unsigned __int128) 0xdeadbeefULL) << 64); + if (a != ((unsigned __int128) 0xefbeaddeULL) << 32) + __builtin_abort (); + a = __builtin_bswap128 ((((unsigned __int128) 0xdeadbeefULL) << 64) + | 0xcafed00dfeedbac1ULL); + if (a != ((((unsigned __int128) 0xc1baedfe0dd0fecaULL) << 64) + | (((unsigned __int128) 0xefbeaddeULL) << 32))) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.dg/pr113756.c b/gcc/testsuite/gcc.dg/pr113756.c new file mode 100644 index 0000000..1444220 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr113756.c @@ -0,0 +1,36 @@ +/* PR tree-optimization/113756 */ +/* { dg-do run { target int32plus } } */ +/* { dg-options "-O2" } */ + +int d, e, i, k, l = -8; +signed char h, j; + +int +bar (int n, int o, int p3) +{ + int a = o - p3, b = n - p3, c = a + b, f = -b, g = c < 0 ? -c : c; + return a <= f && a <= g ? o : p3; +} + +void +foo (int *n, unsigned short o) +{ + unsigned p = 8896; + for (; e >= 0; e--) + p = 5377; + for (; h <= 0; h++) + for (; j <= 0; j++) + { + *n = 1611581749; + i = bar (34, p - 5294, *n - 1611581687); + k = i + p + 65535 + o + *n - 1611718251; + if (k != 0) + __builtin_abort (); + } +} + +int +main () +{ + foo (&l, l); +} diff --git a/gcc/testsuite/gcc.dg/pr84877.c b/gcc/testsuite/gcc.dg/pr84877.c index 6868120..e82991f 100644 --- a/gcc/testsuite/gcc.dg/pr84877.c +++ b/gcc/testsuite/gcc.dg/pr84877.c @@ -1,4 +1,4 @@ -/* { dg-do run { xfail { cris-*-* sparc*-*-* } || { { ! lp64 } && hppa*-*-* } } } */ +/* { dg-do run { xfail { { cris-*-* sparc*-*-* } || { { ! lp64 } && hppa*-*-* } } } } */ /* { dg-options "-O2" } */ #include <inttypes.h> diff --git a/gcc/testsuite/gcc.dg/pr87954.c b/gcc/testsuite/gcc.dg/pr87954.c index 620657c..80d0543 100644 --- a/gcc/testsuite/gcc.dg/pr87954.c +++ b/gcc/testsuite/gcc.dg/pr87954.c @@ -18,4 +18,4 @@ imul(unsigned int flags) return type_dma + (is_rec * !is_dma) * KMALLOC_RECLAIM; } -/* { dg-final { scan-tree-dump-times { \* } 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times { \*w? |WIDEN_MULT_PLUS_EXPR} 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strub-internal-pr113394.c b/gcc/testsuite/gcc.dg/strub-internal-pr113394.c new file mode 100644 index 0000000..d21c209 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strub-internal-pr113394.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=internal -g" } */ + +/* gcc.c-torture/compile/20020210-1.c */ +/* PR c/5615 */ +void f(int a, struct {int b[a];} c) {} /* { dg-warning "anonymous struct" } */ diff --git a/gcc/testsuite/gcc.dg/torture/bitint-53.c b/gcc/testsuite/gcc.dg/torture/bitint-53.c new file mode 100644 index 0000000..8ead40e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-53.c @@ -0,0 +1,26 @@ +/* PR libgcc/113604 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 256 +unsigned _BitInt (256) x; + +void +foo (unsigned _BitInt (256) a, unsigned _BitInt (128) b) +{ + x = a / b; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 256 + foo (0xfffffffffffffffffffffc0000000000000000000004uwb, 0x7ffffffffffffffffffffffffffuwb); + if (x != 0x1fffffffffffffffffuwb) + __builtin_abort (); +#endif + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/bitint-55.c b/gcc/testsuite/gcc.dg/torture/bitint-55.c new file mode 100644 index 0000000..7d4bff3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-55.c @@ -0,0 +1,66 @@ +/* PR libgcc/113604 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 513 +signed _BitInt(513) +foo (signed _BitInt(513) x, signed _BitInt(513) y) +{ + return x % y; +} +#endif + +#if __BITINT_MAXWIDTH__ >= 512 +unsigned _BitInt(512) +bar (unsigned _BitInt(512) x, unsigned _BitInt(512) y) +{ + return x % y; +} +#endif + +#if __BITINT_MAXWIDTH__ >= 256 +unsigned _BitInt(256) +baz (unsigned _BitInt(256) x, unsigned _BitInt(256) y) +{ + return x % y; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 513 + if (foo (11155754932722990178552651944728825929130437979239421228991532051555943675wb, + 32783817256434357484609367438786815wb) != 0wb) + __builtin_abort (); + if (foo (542904728531209767665756029992981529373473101602268731408384wb, + 235447394450476261134537147263765988105wb) + != 235447394450476261116090403190056436489wb) + __builtin_abort (); + if (foo (542904728531209767665690117878483036079552477922114364506112wb, + 235447394450476261134537147263765988105wb) + != 169535279951982967195466723035689534217wb) + __builtin_abort (); + if (foo (542904728531209767665690117878483036079534031178040654954496wb, + 235447394450476261134537147263765988105wb) + != 169535279951982967177019978961979982601wb) + __builtin_abort (); + if (foo (542904728531209767665454670484032559818581851459155356811264wb, + 235447394450476261134537147263765988105wb) + != 169535279951982967359377407340447827474wb) + __builtin_abort (); +#endif +#if __BITINT_MAXWIDTH__ >= 512 + if (bar (6703903964971298549787012499102923063739682910296196688861780721860882015036773488400937149083451713845015929093243025426876941405973284973216824503042048uwb, + 170141183460469231731687303715884105735uwb) != 19208uwb) + __builtin_abort (); +#endif +#if __BITINT_MAXWIDTH__ >= 256 + if (baz (115792089237316195423570985008687907853269984665640564039457584007913129639926uwb, + 68056473384187692692674921486353642292uwb) != 6uwb) + __builtin_abort (); +#endif + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/bitint-56.c b/gcc/testsuite/gcc.dg/torture/bitint-56.c new file mode 100644 index 0000000..6a76a81 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-56.c @@ -0,0 +1,25 @@ +/* PR tree-optimization/113753 */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 129 +unsigned _BitInt(128) +foo (unsigned u, unsigned _BitInt(128) a, unsigned _BitInt(128) b) +{ + unsigned _BitInt(129) m = a % b; + return u * m / u; +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 129 + if (foo (0xfa637c33, 0x37af7fe8b0000000000000000wb, + 0xfffffffff0000000000000000wb) + != 0x16f7e93f6d726b38b38d0b753wb) + __builtin_abort (); +#endif +} diff --git a/gcc/testsuite/gcc.dg/torture/pr110176.c b/gcc/testsuite/gcc.dg/torture/pr110176.c new file mode 100644 index 0000000..e41e3a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr110176.c @@ -0,0 +1,46 @@ +/* { dg-do run } */ + +int f(_Bool t) +{ + int tt = t; + unsigned x = -1; + int xx = x; + return xx <= tt; +} + +int a, b; +void c() {} +__attribute__((noipa)) +void h() {__builtin_abort();} +int d() { + unsigned f[1]; + int i; + if (a) + goto h; + f[0] = -1; + while (1) { + c(); + for (; a < 1; a++) { + if (0) { + j: + continue; + } + i = f[0]; + if (a) + break; + b = i >= (b == 0); + } + if (!b) { + if (0) { + h: + goto j; + } + return 0; + } + h(); + } +} +int main() { + d(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr111444.c b/gcc/testsuite/gcc.dg/torture/pr111444.c new file mode 100644 index 0000000..e613f25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr111444.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ + +int a = 3, d, e; +int *b = &a; +char c; +short f; +const int **g; +static long h(int **i, int **j) +{ + const int *k[46]; + const int **l = &k[5]; + *j = &e; + g = l; + for (; d; d = d + 1) + ; + **i = 0; + return f; +} +int main() +{ + int *m = &a; + h(&m, &m); + c = *b; + if (c != 3) + __builtin_abort (); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr113630.c b/gcc/testsuite/gcc.dg/torture/pr113630.c new file mode 100644 index 0000000..72ebdef --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr113630.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { { *-*-linux* *-*-gnu* *-*-uclinux* } && mmap } } } */ +/* { dg-additional-options "-fno-strict-aliasing" } */ + +#include "pr110799.c" diff --git a/gcc/testsuite/gcc.dg/torture/pr113707-1.c b/gcc/testsuite/gcc.dg/torture/pr113707-1.c new file mode 100644 index 0000000..c1a50b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr113707-1.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ + +int printf(const char *, ...); +struct a { + int b; +} n; +int a, c, d, e, f = 1, g, h, j = 1, k, l, m, o; +int main() { + struct a p; + int i; + p.b = 1; + if (!j) + goto q; + p.b = i = 0; + for (; i < 1; i++) + if (k) + while (m) + r: + q: + if (p.b) + g = 1; + while (1) { + i = 0; + for (; i < 5; i++) + ; + if (l) { + while (h) + ; + if (o) { + d = 0; + for (; d < 8; d++) + ; + } + } + for (; e; e--) + while (a) + p = n; + if (c) + goto r; + printf("0"); + if (f) + break; + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr113707-2.c b/gcc/testsuite/gcc.dg/torture/pr113707-2.c new file mode 100644 index 0000000..957e6f1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr113707-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ + +int a, b, c, d, e, f, g, h, j, k, l; +void n() { + while (c) + if (1) { + for (h = 5; h; h--) { + int m = e % 2; + d = ~g || h ^ m / -1; + if (h > 5) + e = k; + } + return; + } +} +int main() { + if (a) + for (int i = 0; i < 2; i++) { + for (f = 1; f < 6; f++) + for (c = 7; c >= 0; c--) + if (l) + b = 0; + n(); + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/ubsan/ubsan.exp b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp index 8417049..560e584 100644 --- a/gcc/testsuite/gcc.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/gcc.dg/ubsan/ubsan.exp @@ -24,7 +24,8 @@ load_lib ubsan-dg.exp # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ so make sure we provide paths for it. +ubsan_init 1 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-1.c b/gcc/testsuite/gcc.dg/vect/vect-avg-1.c index 4a752cd..0529037 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-1.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-1.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #include "tree-vect.h" @@ -44,5 +45,5 @@ main (void) /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-11.c b/gcc/testsuite/gcc.dg/vect/vect-avg-11.c index 0046f8c..e91be11 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-11.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-11.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #include "tree-vect.h" @@ -54,5 +55,5 @@ main (void) /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-12.c b/gcc/testsuite/gcc.dg/vect/vect-avg-12.c index f40331e..cc64c58 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-12.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-12.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed @@ -6,5 +7,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-13.c b/gcc/testsuite/gcc.dg/vect/vect-avg-13.c index 7957c0e..ff55c01 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-13.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-13.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS unsigned #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-14.c b/gcc/testsuite/gcc.dg/vect/vect-avg-14.c index 8ab11f7..4161a08 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-14.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-14.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-2.c b/gcc/testsuite/gcc.dg/vect/vect-avg-2.c index b5586b5..a58122c 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-2.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-2.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed @@ -6,5 +7,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-3.c b/gcc/testsuite/gcc.dg/vect/vect-avg-3.c index 104fe96..1ae6894 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-3.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-3.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS unsigned #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-4.c b/gcc/testsuite/gcc.dg/vect/vect-avg-4.c index 92181d7..87fb826 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-4.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-4.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-5.c b/gcc/testsuite/gcc.dg/vect/vect-avg-5.c index 6bdaeff..73dcb36 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-5.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-5.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #include "tree-vect.h" @@ -48,5 +49,5 @@ main (void) /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-6.c b/gcc/testsuite/gcc.dg/vect/vect-avg-6.c index efe97b8..2cf48a4 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-6.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-6.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed @@ -6,5 +7,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_FLOOR} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-7.c b/gcc/testsuite/gcc.dg/vect/vect-avg-7.c index 62a8474..365ce7a 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-7.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-7.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS unsigned #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-avg-8.c b/gcc/testsuite/gcc.dg/vect/vect-avg-8.c index cc7c4cd..b8e4c04 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-avg-8.c +++ b/gcc/testsuite/gcc.dg/vect/vect-avg-8.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-additional-options "-fdump-tree-optimized" } */ #define SIGNEDNESS signed #define BIAS 1 @@ -7,5 +8,5 @@ /* { dg-final { scan-tree-dump "vect_recog_average_pattern: detected" "vect" } } */ /* { dg-final { scan-tree-dump {\.AVG_CEIL} "vect" { target vect_avg_qi } } } */ -/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "vect" { target vect_avg_qi } } } */ +/* { dg-final { scan-tree-dump-not {vector\([^\n]*short} "optimized" { target vect_avg_qi } } } */ /* { dg-final { scan-tree-dump-times "vectorized 1 loop" 1 "vect" { target vect_avg_qi } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c new file mode 100644 index 0000000..e488619 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_108-pr113588.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ + +int foo (const char *s, unsigned long n) +{ + unsigned long len = 0; + while (*s++ && n--) + ++len; + return len; +} + diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c new file mode 100644 index 0000000..488c19d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_109-pr113588.c @@ -0,0 +1,44 @@ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target mmap } */ + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ + +#include <sys/mman.h> +#include <unistd.h> + +#include "tree-vect.h" + +__attribute__((noipa)) +int foo (const char *s, unsigned long n) +{ + unsigned long len = 0; + while (*s++ && n--) + ++len; + return len; +} + +int main() +{ + + check_vect (); + + long pgsz = sysconf (_SC_PAGESIZE); + void *p = mmap (NULL, pgsz * 3, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); + if (p == MAP_FAILED) + return 0; + mprotect (p, pgsz, PROT_NONE); + mprotect (p+2*pgsz, pgsz, PROT_NONE); + char *p1 = p + pgsz; + p1[0] = 1; + p1[1] = 0; + foo (p1, 1000); + p1 = p + 2*pgsz - 2; + p1[0] = 1; + p1[1] = 0; + foo (p1, 1000); + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c new file mode 100644 index 0000000..1e2c47b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_110-pr113467.c @@ -0,0 +1,52 @@ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_long_long } */ + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ + +#include "tree-vect.h" +#include <stdint.h> + +typedef struct gcry_mpi *gcry_mpi_t; +struct gcry_mpi { + int nlimbs; + unsigned long *d; +}; + +long gcry_mpi_add_ui_up; +void gcry_mpi_add_ui(gcry_mpi_t w, gcry_mpi_t u, unsigned v) { + gcry_mpi_add_ui_up = *w->d; + if (u) { + uint64_t *res_ptr = w->d, *s1_ptr = w->d; + int s1_size = u->nlimbs; + unsigned s2_limb = v, x = *s1_ptr++; + s2_limb += x; + *res_ptr++ = s2_limb; + if (x) + while (--s1_size) { + x = *s1_ptr++ + 1; + *res_ptr++ = x; + if (x) { + break; + } + } + } +} + +int main() +{ + check_vect (); + + static struct gcry_mpi sv; + static uint64_t vals[] = {4294967288ULL, 191ULL, 4160749568ULL, 4294963263ULL, + 127ULL, 4294950912ULL, 255ULL, 4294901760ULL, + 534781951ULL, 33546240ULL, 4294967292ULL, 4294960127ULL, + 4292872191ULL, 4294967295ULL, 4294443007ULL, 3ULL}; + gcry_mpi_t v = &sv; + v->nlimbs = 16; + v->d = vals; + + gcry_mpi_add_ui(v, v, 8); + if (v->d[1] != 192) + __builtin_abort(); +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c new file mode 100644 index 0000000..b205f47 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_111-pr113731.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_long } */ +/* { dg-additional-options "-msse4.2" { target i?86-*-* x86_64-*-* } } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +char* inet_net_pton_ipv4_bits; +char inet_net_pton_ipv4_odst; +void __errno_location(); +void inet_net_pton_ipv4(); +void inet_net_pton() { inet_net_pton_ipv4(); } +void inet_net_pton_ipv4(char *dst, int size) { + while ((inet_net_pton_ipv4_bits > dst) & inet_net_pton_ipv4_odst) { + if (size-- <= 0) + goto emsgsize; + *dst++ = '\0'; + } +emsgsize: + __errno_location(); +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c new file mode 100644 index 0000000..559ebd8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_112-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) + break; +foo: + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c new file mode 100644 index 0000000..ba85780 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_113-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) + break; + vect_a[i] = x; +foo: + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c new file mode 100644 index 0000000..37af299 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_114-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; +foo: + if (vect_a[i] != x) + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c new file mode 100644 index 0000000..502686d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_115-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { +foo: + vect_b[i] = x + i; + if (vect_a[i] != x) + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c new file mode 100644 index 0000000..4e02158 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_116-pr113750.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ + +#ifndef N +#define N 800 +#endif +unsigned vect_a[N]; +unsigned vect_b[N]; + +unsigned test4(unsigned x) +{ + unsigned ret = 0; + for (int i = 0; i < N; i++) + { + vect_b[i] = x + i; + if (vect_a[i] != x) +foo: + break; + vect_a[i] = x; + } + return ret; +} diff --git a/gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c b/gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c new file mode 100644 index 0000000..bf49ac7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/acle/ls64_strict_align.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mstrict-align" } */ +/* PR target/113657 */ + +#pragma GCC target "+ls64" +#pragma GCC aarch64 "arm_acle.h" +__arm_data512_t foo(__arm_data512_t* ptr) { return *ptr; } diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c b/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c index b51d0f2..e4f754d 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pre_cond_share_1.c @@ -129,4 +129,4 @@ fasten_main(size_t group, size_t ntypes, size_t nposes, size_t natlig, size_t na } /* { dg-final { scan-tree-dump-times {\.COND_MUL} 1 "optimized" } } */ -/* { dg-final { scan-tree-dump-times {\.VCOND} 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times {\.VCOND} 1 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c index d150535..d7cef11 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch.c @@ -9,7 +9,7 @@ int b[N] = {0}; ** ... ** cmpgt p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f1 () @@ -26,7 +26,7 @@ void f1 () ** ... ** cmpge p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f2 () @@ -43,7 +43,7 @@ void f2 () ** ... ** cmpeq p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f3 () @@ -60,7 +60,7 @@ void f3 () ** ... ** cmpne p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f4 () @@ -77,7 +77,7 @@ void f4 () ** ... ** cmplt p[0-9]+.s, p7/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any .L[0-9]+ +** b.(any|none) .L[0-9]+ ** ... */ void f5 () @@ -94,7 +94,7 @@ void f5 () ** ... ** cmple p[0-9]+.s, p[0-9]+/z, z[0-9]+.s, #0 ** ptest p[0-9]+, p[0-9]+.b -** b.any \.L[0-9]+ +** b.(any|none) \.L[0-9]+ ** ... */ void f6 () diff --git a/gcc/testsuite/gcc.target/aarch64/torture/pr111677.c b/gcc/testsuite/gcc.target/aarch64/torture/pr111677.c new file mode 100644 index 0000000..6bb640c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/torture/pr111677.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target fopenmp } */ +/* { dg-options "-ffast-math -fstack-protector-strong -fopenmp" } */ +typedef struct { + long size_z; + int width; +} dt_bilateral_t; +typedef float dt_aligned_pixel_t[4]; +#pragma omp declare simd +void dt_bilateral_splat(dt_bilateral_t *b) { + float *buf; + long offsets[8]; + for (; b;) { + int firstrow; + for (int j = firstrow; j; j++) + for (int i; i < b->width; i++) { + dt_aligned_pixel_t contrib; + for (int k = 0; k < 4; k++) + buf[offsets[k]] += contrib[k]; + } + float *dest; + for (int j = (long)b; j; j++) { + float *src = (float *)b->size_z; + for (int i = 0; i < (long)b; i++) + dest[i] += src[i]; + } + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c index a5e7b94..673b781 100644 --- a/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c +++ b/gcc/testsuite/gcc.target/aarch64/vect-early-break-cbranch.c @@ -15,7 +15,7 @@ int b[N] = {0}; ** cmgt v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f1 () @@ -34,7 +34,7 @@ void f1 () ** cmge v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f2 () @@ -53,7 +53,7 @@ void f2 () ** cmeq v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f3 () @@ -72,7 +72,7 @@ void f3 () ** cmtst v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f4 () @@ -91,7 +91,7 @@ void f4 () ** cmlt v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f5 () @@ -110,7 +110,7 @@ void f5 () ** cmle v[0-9]+.4s, v[0-9]+.4s, #0 ** umaxp v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s ** fmov x[0-9]+, d[0-9]+ -** cbnz x[0-9]+, \.L[0-9]+ +** cbn?z x[0-9]+, \.L[0-9]+ ** ... */ void f6 () diff --git a/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c b/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c index 459dc96..1406db5 100644 --- a/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c +++ b/gcc/testsuite/gcc.target/i386/apx-ndd-cmov.c @@ -1,7 +1,7 @@ /* { dg-do compile { target { ! ia32 } } } */ /* { dg-options "-O2 -m64 -mapxf" } */ -/* { dg-final { scan-assembler-times "cmove\[^\n\r]*, %eax" 1 } } */ -/* { dg-final { scan-assembler-times "cmovge\[^\n\r]*, %eax" 1 } } */ +/* { dg-final { scan-assembler-times "cmov(l\.)?e\[^\n\r]*, %eax" 1 } } */ +/* { dg-final { scan-assembler-times "cmov(l\.)?ge\[^\n\r]*, %eax" 1 } } */ unsigned int c[4]; diff --git a/gcc/testsuite/gcc.target/i386/apx-ndd.c b/gcc/testsuite/gcc.target/i386/apx-ndd.c index b215f66..0eb751ad 100644 --- a/gcc/testsuite/gcc.target/i386/apx-ndd.c +++ b/gcc/testsuite/gcc.target/i386/apx-ndd.c @@ -75,9 +75,9 @@ FOO2 (short, add, +) FOO (int, add, +) FOO1 (int, add, +) FOO2 (int, add, +) -FOO (long, add, +) -FOO1 (long, add, +) -FOO2 (long, add, +) +FOO (int64_t, add, +) +FOO1 (int64_t, add, +) +FOO2 (int64_t, add, +) FOO (char, sub, -) FOO1 (char, sub, -) @@ -85,8 +85,8 @@ FOO (short, sub, -) FOO1 (short, sub, -) FOO (int, sub, -) FOO1 (int, sub, -) -FOO (long, sub, -) -FOO1 (long, sub, -) +FOO (int64_t, sub, -) +FOO1 (int64_t, sub, -) F (char, neg, -) F1 (char, neg, -) @@ -94,8 +94,8 @@ F (short, neg, -) F1 (short, neg, -) F (int, neg, -) F1 (int, neg, -) -F (long, neg, -) -F1 (long, neg, -) +F (int64_t, neg, -) +F1 (int64_t, neg, -) F (char, not, ~) F1 (char, not, ~) @@ -103,8 +103,8 @@ F (short, not, ~) F1 (short, not, ~) F (int, not, ~) F1 (int, not, ~) -F (long, not, ~) -F1 (long, not, ~) +F (int64_t, not, ~) +F1 (int64_t, not, ~) FOO (char, and, &) FOO1 (char, and, &) @@ -112,8 +112,8 @@ FOO (short, and, &) FOO1 (short, and, &) FOO (int, and, &) FOO1 (int, and, &) -FOO (long, and, &) -FOO1 (long, and, &) +FOO (int64_t, and, &) +FOO1 (int64_t, and, &) FOO (char, or, |) FOO1 (char, or, |) @@ -121,8 +121,8 @@ FOO (short, or, |) FOO1 (short, or, |) FOO (int, or, |) FOO1 (int, or, |) -FOO (long, or, |) -FOO1 (long, or, |) +FOO (int64_t, or, |) +FOO1 (int64_t, or, |) FOO (char, xor, ^) FOO1 (char, xor, ^) @@ -130,8 +130,8 @@ FOO (short, xor, ^) FOO1 (short, xor, ^) FOO (int, xor, ^) FOO1 (int, xor, ^) -FOO (long, xor, ^) -FOO1 (long, xor, ^) +FOO (int64_t, xor, ^) +FOO1 (int64_t, xor, ^) FOO (char, shl, <<) FOO3 (char, shl, <<, 7) @@ -139,8 +139,8 @@ FOO (short, shl, <<) FOO3 (short, shl, <<, 7) FOO (int, shl, <<) FOO3 (int, shl, <<, 7) -FOO (long, shl, <<) -FOO3 (long, shl, <<, 7) +FOO (int64_t, shl, <<) +FOO3 (int64_t, shl, <<, 7) FOO (char, sar, >>) FOO3 (char, sar, >>, 7) @@ -148,8 +148,8 @@ FOO (short, sar, >>) FOO3 (short, sar, >>, 7) FOO (int, sar, >>) FOO3 (int, sar, >>, 7) -FOO (long, sar, >>) -FOO3 (long, sar, >>, 7) +FOO (int64_t, sar, >>) +FOO3 (int64_t, sar, >>, 7) FOO (uint8_t, shr, >>) FOO3 (uint8_t, shr, >>, 7) @@ -170,33 +170,33 @@ FOO4 (uint16_t, rol, <<, >>, 1) FOO4 (uint32_t, rol, <<, >>, 1) FOO4 (uint64_t, rol, <<, >>, 1) -/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "lea(?:l|q)\[^\n\r]\\(%r(?:d|s)i,%r(?:d|s)i\\), %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]%(?:|r|e)si(?:|l), \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ -/* { dg-final { scan-assembler-times "sub(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "add(?:b|l|w|q)\[^\n\r]%(?:|r|e)si(?:|l), \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "sub(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "sub(?:b|l|w|q)\[^\n\r]%(?:|r|e)si(?:|l), %(?:|r|e)di, %(?:|r|e)a(?:x|l)" 4 } } */ -/* { dg-final { scan-assembler-times "negb\[^\n\r]\\(%rdi\\), %(?:|r|e)al" 1 } } */ -/* { dg-final { scan-assembler-times "neg(?:l|w|q)\[^\n\r]\\(%rdi\\), %(?:|r|e)ax" 3 } } */ +/* { dg-final { scan-assembler-times "negb\[^\n\r]\\(%(?:r|e)di\\), %al" 1 } } */ +/* { dg-final { scan-assembler-times "neg(?:l|w|q)\[^\n\r]\\(%(?:r|e)di\\), %(?:|r|e)ax" 3 } } */ /* { dg-final { scan-assembler-times "neg(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "not(?:b|l|w|q)\[^\n\r]\\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "not(?:b|l|w|q)\[^\n\r]\\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "not(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "andb\[^\n\r]*1, \\(%rdi\\), %al" 1 } } */ -/* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)ax" 3 } } */ +/* { dg-final { scan-assembler-times "andb\[^\n\r]*1, \\(%(?:r|e)di\\), %al" 1 } } */ +/* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)ax" 3 } } */ /* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)si, %(?:|r|e)ax" 2 } } */ /* { dg-final { scan-assembler-times "and(?:l|w|q)\[^\n\r]%(?:|r|e)si, %(?:|r|e)di, %(?:|r|e)ax" 2 } } */ -/* { dg-final { scan-assembler-times "orb\[^\n\r]*1, \\(%rdi\\), %al" 2} } */ -/* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)ax" 6 } } */ +/* { dg-final { scan-assembler-times "orb\[^\n\r]*1, \\(%(?:r|e)di\\), %al" 2} } */ +/* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)ax" 6 } } */ /* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)si, %(?:|r|e)ax" 4 } } */ /* { dg-final { scan-assembler-times "or(?:l|w|q)\[^\n\r]%(?:|r|e)si, %(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "xorb\[^\n\r]*1, \\(%rdi\\), %al" 1 } } */ -/* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)ax" 3 } } */ +/* { dg-final { scan-assembler-times "xorb\[^\n\r]*1, \\(%(?:r|e)di\\), %al" 1 } } */ +/* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)ax" 3 } } */ /* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]%(?:|r|e)di, %(?:|r|e)si, %(?:|r|e)ax" 2 } } */ /* { dg-final { scan-assembler-times "xor(?:l|w|q)\[^\n\r]%(?:|r|e)si, %(?:|r|e)di, %(?:|r|e)ax" 2 } } */ -/* { dg-final { scan-assembler-times "sal(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "sal(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "sal(?:l|w|q)\[^\n\r]*7, %(?:|r|e)di, %(?:|r|e)ax" 4 } } */ -/* { dg-final { scan-assembler-times "sar(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "sar(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "sar(?:b|l|w|q)\[^\n\r]*7, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ -/* { dg-final { scan-assembler-times "shr(?:b|l|w|q)\[^\n\r]*1, \\(%rdi\\), %(?:|r|e)a(?:x|l)" 4 } } */ +/* { dg-final { scan-assembler-times "shr(?:b|l|w|q)\[^\n\r]*1, \\(%(?:r|e)di\\), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "shr(?:b|l|w|q)\[^\n\r]*7, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "ror(?:b|l|w|q)\[^\n\r]*1, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ /* { dg-final { scan-assembler-times "rol(?:b|l|w|q)\[^\n\r]*1, %(?:|r|e)di(?:|l), %(?:|r|e)a(?:x|l)" 4 } } */ diff --git a/gcc/testsuite/gcc.target/i386/asm-raw-symbol.c b/gcc/testsuite/gcc.target/i386/asm-raw-symbol.c new file mode 100644 index 0000000..b785456 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/asm-raw-symbol.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +extern int var; + +void +func (void) +{ + __asm__ ("@ %p0" : : "Ws" (func)); + __asm__ ("@ %p0" : : "Ws" (&var + 1)); +} + +/* { dg-final { scan-assembler "@ func" } } */ +/* { dg-final { scan-assembler "@ var\\+4" } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-5.c b/gcc/testsuite/gcc.target/i386/auto-init-5.c index 0e9d74f..fdccd40 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-5.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-5.c @@ -1,6 +1,6 @@ /* Verify zero initialization for complex type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fno-asynchronous-unwind-tables" } */ _Complex long double result; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-6.c b/gcc/testsuite/gcc.target/i386/auto-init-6.c index e53385f..4b0ce39 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-6.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-6.c @@ -2,7 +2,7 @@ /* Note, _Complex long double is initialized to zeroes due to the current implemenation limitation. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -march=x86-64 -mtune=generic -msse" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -march=x86-64 -mtune=generic -msse -fno-asynchronous-unwind-tables" } */ _Complex long double result; diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c index 2f0ead8..d3b85a1 100644 --- a/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c +++ b/gcc/testsuite/gcc.target/i386/avx512vl-stv-rotatedi-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target ia32 } } */ -/* { dg-options "-O2 -mavx512vl" } */ +/* { dg-options "-O2 -mavx512vl -mstv -mno-stackrealign" } */ unsigned long long rot1(unsigned long long x) { return (x>>1) | (x<<63); } unsigned long long rot2(unsigned long long x) { return (x>>2) | (x<<62); } diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c index 8fe36eb..599c2a3 100644 --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ extern int bar (int) #ifndef __x86_64__ diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c index ce4ab3b..98e2701 100644 --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ extern int bar (int) __attribute__ ((no_caller_saved_registers)) #ifndef __x86_64__ diff --git a/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c b/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c index 64fd8b4..8efa1d4 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memcpy-7.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx -msse2 -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ void foo (int a1, int a2, int a3, int a4, int a5, int a6, char *dst, char *src) diff --git a/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c b/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c index fc60c46..3c86c49 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memcpy-8.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx2 -mavx -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ void foo (int a1, int a2, int a3, int a4, int a5, int a6, char *dst, char *src) diff --git a/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c b/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c index 62fcb6f..a332d5a 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memcpy-9.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mavx512f -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ void foo (int a1, int a2, int a3, int a4, int a5, int a6, char *dst, char *src) diff --git a/gcc/testsuite/gcc.target/i386/pieces-memset-36.c b/gcc/testsuite/gcc.target/i386/pieces-memset-36.c index d1bbfa2..18b2dcc 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memset-36.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memset-36.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx512f -mavx2 -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ extern char *dst; diff --git a/gcc/testsuite/gcc.target/i386/pieces-memset-40.c b/gcc/testsuite/gcc.target/i386/pieces-memset-40.c index 37a9dcc..86358c9 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memset-40.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memset-40.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-avx512f -mavx2 -mtune=sandybridge" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ extern char *dst; diff --git a/gcc/testsuite/gcc.target/i386/pieces-memset-9.c b/gcc/testsuite/gcc.target/i386/pieces-memset-9.c index d64cf6b..8a6f095 100644 --- a/gcc/testsuite/gcc.target/i386/pieces-memset-9.c +++ b/gcc/testsuite/gcc.target/i386/pieces-memset-9.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O2 -march=x86-64 -mavx512f -mtune=generic" } */ -/* Cope with --enable-frame-pointer. */ -/* { dg-additional-options "-fomit-frame-pointer" } */ +/* Cope with --enable-frame-pointer, Solaris/x86 -mstackrealign default. */ +/* { dg-additional-options "-fomit-frame-pointer -mno-stackrealign" } */ extern char *dst; diff --git a/gcc/testsuite/gcc.target/i386/pr113560.c b/gcc/testsuite/gcc.target/i386/pr113560.c new file mode 100644 index 0000000..ac2e01a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113560.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +unsigned __int128 foo(unsigned __int128 x, unsigned __int128 y) +{ + return (x & 1000) * (y & 1000); +} + +__int128 bar(__int128 x, __int128 y) +{ + return (x & 1000) * (y & 1000); +} + +/* { dg-final { scan-assembler-times "\tmulq" 1 } } */ +/* { dg-final { scan-assembler-times "\timulq" 1 } } */ +/* { dg-final { scan-assembler-not "addq" } } */ +/* { dg-final { scan-assembler-not "xorl" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr113656.c b/gcc/testsuite/gcc.target/i386/pr113656.c new file mode 100644 index 0000000..fa57a56 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113656.c @@ -0,0 +1,12 @@ +/* PR rtl-optimization/113656 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -frounding-math -funsafe-math-optimizations -mavx512fp16 -mavx512vl" } */ + +_Float16 a[8]; + +void +foo () +{ + for (int i = 0; i < 8; i++) + a[i] = i - 8.4; +} diff --git a/gcc/testsuite/gcc.target/i386/pr113670.c b/gcc/testsuite/gcc.target/i386/pr113670.c new file mode 100644 index 0000000..8b9d374 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113670.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2 -fno-vect-cost-model" } */ + +typedef float __attribute__ ((vector_size (16))) vec; +typedef int __attribute__ ((vector_size (16))) ivec; +ivec x; + +void +test (void) +{ + register vec a asm("xmm3"), b asm("xmm4"); + register ivec c asm("xmm5"); + for (int i = 0; i < 4; i++) + c[i] = a[i] < b[i] ? -1 : 1; + x = c; +} diff --git a/gcc/testsuite/gcc.target/i386/pr113689-1.c b/gcc/testsuite/gcc.target/i386/pr113689-1.c new file mode 100644 index 0000000..8285c0a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113689-1.c @@ -0,0 +1,49 @@ +/* { dg-do run { target { lp64 && fpic } } } */ +/* { dg-options "-O2 -fno-pic -fprofile -mcmodel=large" } */ + +#include <stdarg.h> + +__attribute__((noipa)) +void +bar (int a1, int a2, int a3, int a4, int a5, int a6, + char *x, char *y, int *z) +{ + if (a1 != 1) + __builtin_abort (); + if (a2 != 2) + __builtin_abort (); + if (a3 != 3) + __builtin_abort (); + if (a4 != 4) + __builtin_abort (); + if (a5 != 5) + __builtin_abort (); + if (a6 != 6) + __builtin_abort (); + x[0] = 42; + y[0] = 42; + if (z[0] != 16) + __builtin_abort (); +} + +__attribute__((noipa)) +void +foo (int c, int d, int e, int f, int g, int h, int z, ...) +{ + typedef char B[32]; + B b __attribute__((aligned (32))); + va_list ap; + va_start (ap, z); + double x = va_arg (ap, double); + if (x > 40.0) + __builtin_abort (); + bar (c, d, e, f, g, h, &b[0], __builtin_alloca (z), &z); + va_end (ap); +} + +int +main () +{ + foo (1, 2, 3, 4, 5, 6, 16, 38.0); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr113689-2.c b/gcc/testsuite/gcc.target/i386/pr113689-2.c new file mode 100644 index 0000000..2e5579a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113689-2.c @@ -0,0 +1,41 @@ +/* { dg-do run { target { lp64 && fpic } } } */ +/* { dg-options "-O2 -fpic -fprofile -mcmodel=large" } */ + +__attribute__((noipa)) +void +bar (int a1, int a2, int a3, int a4, int a5, int a6, + char *x, char *y, int *z) +{ + if (a1 != 1) + __builtin_abort (); + if (a2 != 2) + __builtin_abort (); + if (a3 != 3) + __builtin_abort (); + if (a4 != 4) + __builtin_abort (); + if (a5 != 5) + __builtin_abort (); + if (a6 != 6) + __builtin_abort (); + x[0] = 42; + y[0] = 42; + if (z[0] != 16) + __builtin_abort (); +} + +__attribute__((noipa)) +void +foo (int c, int d, int e, int f, int g, int h, int z) +{ + typedef char B[32]; + B b __attribute__((aligned (32))); + bar (c, d, e, f, g, h, &b[0], __builtin_alloca (z), &z); +} + +int +main () +{ + foo (1, 2, 3, 4, 5, 6, 16); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr113689-3.c b/gcc/testsuite/gcc.target/i386/pr113689-3.c new file mode 100644 index 0000000..dab7519 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr113689-3.c @@ -0,0 +1,48 @@ +/* { dg-do run { target { lp64 && fpic } } } */ +/* { dg-options "-O2 -fpic -fprofile -mcmodel=large" } */ + +#include <stdarg.h> + +__attribute__((noipa)) +void +bar (char *x, char *y, int *z) +{ + x[0] = 42; + y[0] = 42; + if (z[0] != 16) + __builtin_abort (); +} + +__attribute__((noipa)) +void +foo (int a1, int a2, int a3, int a4, int a5, int a6, int z, ...) +{ + typedef char B[32]; + B b __attribute__((aligned (32))); + va_list ap; + va_start (ap, z); + double x = va_arg (ap, double); + if (x > 40.0) + __builtin_abort (); + if (a1 != 1) + __builtin_abort (); + if (a2 != 2) + __builtin_abort (); + if (a3 != 3) + __builtin_abort (); + if (a4 != 4) + __builtin_abort (); + if (a5 != 5) + __builtin_abort (); + if (a6 != 6) + __builtin_abort (); + bar (&b[0], __builtin_alloca (z), &z); + va_end (ap); +} + +int +main () +{ + foo (1, 2, 3, 4, 5, 6, 16, 38.0); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr38534-1.c b/gcc/testsuite/gcc.target/i386/pr38534-1.c index 9297959..280f3b4 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-1.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ #define ARRAY_SIZE 256 diff --git a/gcc/testsuite/gcc.target/i386/pr38534-2.c b/gcc/testsuite/gcc.target/i386/pr38534-2.c index 1fb0136..2e19989 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-2.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ extern void bar (void) __attribute__ ((no_callee_saved_registers)); extern void fn (void) __attribute__ ((noreturn)); diff --git a/gcc/testsuite/gcc.target/i386/pr38534-3.c b/gcc/testsuite/gcc.target/i386/pr38534-3.c index 87fc35f..af6e195 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-3.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ typedef void (*fn_t) (void) __attribute__ ((no_callee_saved_registers)); extern fn_t bar; diff --git a/gcc/testsuite/gcc.target/i386/pr38534-4.c b/gcc/testsuite/gcc.target/i386/pr38534-4.c index 561ebee..b204789 100644 --- a/gcc/testsuite/gcc.target/i386/pr38534-4.c +++ b/gcc/testsuite/gcc.target/i386/pr38534-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ typedef void (*fn_t) (void) __attribute__ ((no_callee_saved_registers)); extern void fn (void) __attribute__ ((noreturn)); diff --git a/gcc/testsuite/gcc.target/i386/pr70321.c b/gcc/testsuite/gcc.target/i386/pr70321.c index 57552ef..58f5f56 100644 --- a/gcc/testsuite/gcc.target/i386/pr70321.c +++ b/gcc/testsuite/gcc.target/i386/pr70321.c @@ -1,5 +1,5 @@ /* { dg-do compile { target ia32 } } */ -/* { dg-options "-O2" } */ +/* { dg-options "-O2 -fomit-frame-pointer" } */ void foo (long long ixi) { diff --git a/gcc/testsuite/gcc.target/i386/pr71321.c b/gcc/testsuite/gcc.target/i386/pr71321.c index 24d144b..7a006d1 100644 --- a/gcc/testsuite/gcc.target/i386/pr71321.c +++ b/gcc/testsuite/gcc.target/i386/pr71321.c @@ -12,4 +12,4 @@ unsigned cvt_to_2digit_ascii(uint8_t i) { return cvt_to_2digit(i, 10) + 0x0a3030; } -/* { dg-final { scan-assembler-not "lea.*0" } } */ +/* { dg-final { scan-assembler-not "lea\[^\n\r]*0" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr80569.c b/gcc/testsuite/gcc.target/i386/pr80569.c index 8e11c40..8314bc1 100644 --- a/gcc/testsuite/gcc.target/i386/pr80569.c +++ b/gcc/testsuite/gcc.target/i386/pr80569.c @@ -1,6 +1,8 @@ /* PR target/80569 */ /* { dg-do assemble } */ /* { dg-options "-O2 -m16 -march=haswell" } */ +/* Non-gas assemblers choke on .code16gcc. */ +/* { dg-require-effective-target gas } */ void load_kernel(void *setup_addr) { diff --git a/gcc/testsuite/gcc.target/i386/sse2-stv-1.c b/gcc/testsuite/gcc.target/i386/sse2-stv-1.c index a95d4ed..72b57b5 100644 --- a/gcc/testsuite/gcc.target/i386/sse2-stv-1.c +++ b/gcc/testsuite/gcc.target/i386/sse2-stv-1.c @@ -1,5 +1,5 @@ /* { dg-do compile { target ia32 } } */ -/* { dg-options "-O2 -msse2" } */ +/* { dg-options "-O2 -msse2 -mno-stackrealign" } */ unsigned long long a,b,c,d; diff --git a/gcc/testsuite/gcc.target/loongarch/attr-model-5.c b/gcc/testsuite/gcc.target/loongarch/attr-model-5.c new file mode 100644 index 0000000..5f2c3ec --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/attr-model-5.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-mexplicit-relocs=none -mcmodel=extreme -O2 -fno-pic" } */ +/* { dg-final { scan-assembler "la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,x" } } */ +/* { dg-final { scan-assembler "la.local\t\\\$r\[0-9\]+,y" } } */ +/* { dg-final { scan-assembler "la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,counter" } } */ + +#define ATTR_MODEL_TEST +#include "attr-model-test.c" diff --git a/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c new file mode 100644 index 0000000..564ee40 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=always -fdump-rtl-final" } */ + +int a; +extern int b; +__thread int c __attribute__ ((tls_model ("local-exec"))); +__thread int d __attribute__ ((tls_model ("initial-exec"))); +__thread int e __attribute__ ((tls_model ("local-dynamic"))); +__thread int f __attribute__ ((tls_model ("global-dynamic"))); + +void +test (void) +{ + a = b + c + d + e + f; +} + +/* a, b, d, e, f, and __tls_get_addr. */ +/* { dg-final { scan-rtl-dump-times "la_pcrel64_two_parts" 6 "final" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c new file mode 100644 index 0000000..ce83480 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/cmodel-extreme-2.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=auto -fdump-rtl-final" } */ + +#include "cmodel-extreme-1.c" + +/* a, b, d, e, f, and __tls_get_addr. */ +/* { dg-final { scan-rtl-dump-times "la_pcrel64_two_parts" 6 "final" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c new file mode 100644 index 0000000..35bd457 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-extreme-auto-tls-ld-gd.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mexplicit-relocs=auto -mcmodel=extreme -fno-plt" } */ +/* { dg-final { scan-assembler-not "la.tls.\[lg\]d" { target tls_native } } } */ + +#include "./explicit-relocs-auto-tls-ld-gd.c" diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c new file mode 100644 index 0000000..47bffae --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-auto-tls-ld-gd.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mexplicit-relocs=auto -mcmodel=medium -fplt" } */ +/* { dg-final { scan-assembler-not "la.global" { target tls_native } } } */ + +#include "./explicit-relocs-auto-tls-ld-gd.c" diff --git a/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c new file mode 100644 index 0000000..d1a4820 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/explicit-relocs-medium-call36-auto-tls-ld-gd.c @@ -0,0 +1,5 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fPIC -mexplicit-relocs=auto -mcmodel=medium -fplt" } */ +/* { dg-final { scan-assembler "pcaddu18i\t\\\$r1,%call36\\\(__tls_get_addr\\\)" { target { tls_native && loongarch_call36_support } } } } */ + +#include "./explicit-relocs-auto-tls-ld-gd.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c index db1e0f8..fdb4cf1 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-1.c @@ -1,31 +1,33 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fno-pic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ +#define NOIPA __attribute__ ((noipa)) + extern void g (void); -void +NOIPA void f (void) {} -static void +NOIPA static void l (void) {} -void +NOIPA void test (void) { g (); } -void +NOIPA void test1 (void) { f (); } -void +NOIPA void test2 (void) { l (); diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c index 21bf81a..dfba388 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-2.c @@ -1,32 +1,7 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fpic -fno-plt -mexplicit-relocs -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ -extern void g (void); -void -f (void) -{} - -static void -l (void) -{} - -void -test (void) -{ - g (); -} - -void -test1 (void) -{ - f (); -} - -void -test2 (void) -{ - l (); -} +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c index a4da44b..1f5234f8 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fno-pic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c index 16b00f4..c422850 100644 --- a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ +/* { dg-options "-mabi=lp64d -O2 -fpic -fno-plt -mexplicit-relocs=auto -mcmodel=extreme" } */ /* { dg-final { scan-assembler "test:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test1:.*pcalau12i.*%got_pc_hi20.*\n\taddi\.d.*%got_pc_lo12.*\n\tlu32i\.d.*%got64_pc_lo20.*\n\tlu52i\.d.*%got64_pc_hi12.*\n\tldx\.d" } } */ /* { dg-final { scan-assembler "test2:.*pcalau12i.*%pc_hi20.*\n\taddi\.d.*%pc_lo12.*\n\tlu32i\.d.*%pc64_lo20.*\n\tlu52i\.d.*pc64_hi12.*\n\tadd\.d" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c new file mode 100644 index 0000000..b1bd9d2 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O0 -fpic -fno-plt -mexplicit-relocs=none -mcmodel=extreme" } */ +/* { dg-final { scan-assembler "test:.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,g" } } */ +/* { dg-final { scan-assembler "test1:.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,f" } } */ +/* { dg-final { scan-assembler "test2:.*la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,l" } } */ + +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c new file mode 100644 index 0000000..6e6ad5c --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/func-call-extreme-6.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-mabi=lp64d -O0 -fno-pic -fno-plt -mexplicit-relocs=none -mcmodel=extreme" } */ +/* { dg-final { scan-assembler "test:.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,g" } } */ +/* { dg-final { scan-assembler "test1:.*la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,f" } } */ +/* { dg-final { scan-assembler "test2:.*la.local\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,l" } } */ + +#include "func-call-extreme-1.c" diff --git a/gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c b/gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c new file mode 100644 index 0000000..6ce2bde --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/larch-frecipe-intrinsic.c @@ -0,0 +1,30 @@ +/* Test intrinsics for frecipe.{s/d} and frsqrte.{s/d} instructions */ +/* { dg-do compile } */ +/* { dg-options "-mfrecipe -O2" } */ +/* { dg-final { scan-assembler-times "test_frecipe_s:.*frecipe\\.s.*test_frecipe_s" 1 } } */ +/* { dg-final { scan-assembler-times "test_frecipe_d:.*frecipe\\.d.*test_frecipe_d" 1 } } */ +/* { dg-final { scan-assembler-times "test_frsqrte_s:.*frsqrte\\.s.*test_frsqrte_s" 1 } } */ +/* { dg-final { scan-assembler-times "test_frsqrte_d:.*frsqrte\\.d.*test_frsqrte_d" 1 } } */ + +#include <larchintrin.h> + +float +test_frecipe_s (float _1) +{ + return __frecipe_s (_1); +} +double +test_frecipe_d (double _1) +{ + return __frecipe_d (_1); +} +float +test_frsqrte_s (float _1) +{ + return __frsqrte_s (_1); +} +double +test_frsqrte_d (double _1) +{ + return __frsqrte_d (_1); +} diff --git a/gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c b/gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c new file mode 100644 index 0000000..4341f82 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/tls-extreme-macro.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-march=loongarch64 -mabi=lp64d -O2 -mcmodel=extreme -fno-plt -mexplicit-relocs=none" } */ +/* { dg-final { scan-assembler "test_le:.*la.tls.le\t\\\$r\[0-9\]+,\\\.L" { target tls_native } } } */ +/* { dg-final { scan-assembler "test_ie:.*la.tls.ie\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,\\\.L" { target tls_native } } } */ +/* { dg-final { scan-assembler "test_ld:.*la.tls.ld\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,\\\.L.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,__tls_get_addr" { target tls_native } } } */ +/* { dg-final { scan-assembler "test_le:.*la.tls.gd\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,\\\.L.*la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,__tls_get_addr" { target tls_native } } } */ + +__thread int c __attribute__ ((tls_model ("local-exec"))); +__thread int d __attribute__ ((tls_model ("initial-exec"))); +__thread int e __attribute__ ((tls_model ("local-dynamic"))); +__thread int f __attribute__ ((tls_model ("global-dynamic"))); + +int +test_le (void) +{ + return c; +} + +int +test_ie (void) +{ + return d; +} + +int +test_ld (void) +{ + return e; +} + +int +test_gd (void) +{ + return f; +} diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c new file mode 100644 index 0000000..5630418 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p450.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */ +/* { dg-options "-mcpu=sifive-p450 -mabi=lp64d" } */ +/* SiFive p450 => rv64imafdc_za64rs_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs */ + +#if !((__riscv_xlen == 64) \ + && !defined(__riscv_32e) \ + && (__riscv_flen == 64) \ + && defined(__riscv_c) \ + && defined(__riscv_za64rs) \ + && defined(__riscv_zic64b) \ + && defined(__riscv_zicbom) \ + && defined(__riscv_zicbop) \ + && defined(__riscv_zicboz) \ + && defined(__riscv_ziccamoa) \ + && defined(__riscv_ziccif) \ + && defined(__riscv_zicclsm) \ + && defined(__riscv_ziccrse) \ + && defined(__riscv_zicsr) \ + && defined(__riscv_zifencei) \ + && defined(__riscv_zihintntl) \ + && defined(__riscv_zihintpause) \ + && defined(__riscv_zihpm) \ + && defined(__riscv_zfhmin) \ + && defined(__riscv_zba) \ + && defined(__riscv_zbb) \ + && defined(__riscv_zbs)) +#error "unexpected arch" +#endif + +int main() +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c new file mode 100644 index 0000000..8dfd490 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/mcpu-sifive-p670.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-skip-if "-march given" { *-*-* } { "-march=*" } } */ +/* { dg-options "-mcpu=sifive-p670 -mabi=lp64d" } */ +/* SiFive p670 => rv64imafdcv_za64rs_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicsr_zifencei_zihintntl_zihintpause_zihpm_zfhmin_zba_zbb_zbs_zvl128b_zvbb_zvknc_zvkng_zvksc_zvksg */ + +#if !((__riscv_xlen == 64) \ + && !defined(__riscv_32e) \ + && (__riscv_flen == 64) \ + && defined(__riscv_c) \ + && defined(__riscv_za64rs) \ + && defined(__riscv_zic64b) \ + && defined(__riscv_zicbom) \ + && defined(__riscv_zicbop) \ + && defined(__riscv_zicboz) \ + && defined(__riscv_ziccamoa) \ + && defined(__riscv_ziccif) \ + && defined(__riscv_zicclsm) \ + && defined(__riscv_ziccrse) \ + && defined(__riscv_zicsr) \ + && defined(__riscv_zifencei) \ + && defined(__riscv_zihintntl) \ + && defined(__riscv_zihintpause) \ + && defined(__riscv_zihpm) \ + && defined(__riscv_zfhmin) \ + && defined(__riscv_zba) \ + && defined(__riscv_zbb) \ + && defined(__riscv_zbs) \ + && defined(__riscv_zvl128b) \ + && defined(__riscv_zvbb) \ + && defined(__riscv_zvknc) \ + && defined(__riscv_zvkng) \ + && defined(__riscv_zvksc) \ + && defined(__riscv_zvksg)) +#error "unexpected arch" +#endif + +int main() +{ + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c b/gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c new file mode 100644 index 0000000..874dff3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/reg_subreg_costs.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv64 } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */ +/* { dg-options "-march=rv64gc_zba" } */ + +#include <stdint-gcc.h> +void foo(uint32_t a, uint64_t *b_ptr, uint64_t b, uint64_t *c_ptr, uint64_t c) +{ + uint64_t x = a; + *b_ptr = b + x; + *c_ptr = c + x; +} + +/* { dg-final { scan-assembler-not "\\szext.w\\s" } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c new file mode 100644 index 0000000..0607476 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607-run.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { riscv_v && rv64 } } } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-optimized" } */ + +#include "pr113607.c" diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c new file mode 100644 index 0000000..70a9366 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113607.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fdump-tree-optimized" } */ + +struct { + signed b; +} c, d = {6}; + +short e, f; +int g[1000]; +signed char h; +int i, j; +long k, l; + +long m(long n, long o) { + if (n < 1 && o == 0) + return 0; + return n; +} + +static int p() { + long q = 0; + int a = 0; + for (; e < 2; e += 1) + g[e * 7 + 1] = -1; + for (; h < 1; h += 1) { + k = g[8] || f; + l = m(g[f * 7 + 1], k); + a = l; + j = a < 0 || g[f * 7 + 1] < 0 || g[f * 7 + 1] >= 32 ? a : a << g[f * 7 + 1]; + if (j) + ++q; + } + if (q) + c = d; + return i; +} + +int main() { + p(); + if (c.b != 6) + __builtin_abort (); +} + +/* We must not fold VEC_COND_EXPR into COND_SHL. + Therefore, make sure that we still have 2/4 VCOND_MASKs with real else + value. */ + +/* { dg-final { scan-tree-dump-times { = \.VCOND_MASK.\([a-z0-9\._]+, [a-z0-9\._\{\}, ]+, [0-9\.\{\},]+\);} 0 "optimized" } } */ +/* { dg-final { scan-tree-dump-times { = \.VCOND_MASK.\([a-z0-9\._]+, [a-z0-9\._\{\}, ]+, [a-z0-9\._]+\);} 4 "optimized" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c new file mode 100644 index 0000000..588b86c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr113697.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -fno-schedule-insns" } */ + +int +foo (int *__restrict a, int n) +{ + int result = 0; + for (int i = 0; i < n; i++) + result += a[i]; + return result; +} + +/* { dg-final { scan-assembler-times {vsetvli} 3 } } */ +/* { dg-final { scan-assembler-not {vsetivli} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c new file mode 100644 index 0000000..41e31c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-1.c @@ -0,0 +1,154 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1qi) +DEF_RET1_ARG0 (v2qi) +DEF_RET1_ARG0 (v4qi) +DEF_RET1_ARG0 (v8qi) +DEF_RET1_ARG0 (v16qi) +DEF_RET1_ARG0 (v32qi) +DEF_RET1_ARG0 (v64qi) +DEF_RET1_ARG0 (v128qi) +DEF_RET1_ARG0 (v256qi) +DEF_RET1_ARG0 (v512qi) +DEF_RET1_ARG0 (v1024qi) +DEF_RET1_ARG0 (v2048qi) +DEF_RET1_ARG0 (v4096qi) + +DEF_RET1_ARG1 (v1qi) +DEF_RET1_ARG1 (v2qi) +DEF_RET1_ARG1 (v4qi) +DEF_RET1_ARG1 (v8qi) +DEF_RET1_ARG1 (v16qi) +DEF_RET1_ARG1 (v32qi) +DEF_RET1_ARG1 (v64qi) +DEF_RET1_ARG1 (v128qi) +DEF_RET1_ARG1 (v256qi) +DEF_RET1_ARG1 (v512qi) +DEF_RET1_ARG1 (v1024qi) +DEF_RET1_ARG1 (v2048qi) +DEF_RET1_ARG1 (v4096qi) + +DEF_RET1_ARG2 (v1qi) +DEF_RET1_ARG2 (v2qi) +DEF_RET1_ARG2 (v4qi) +DEF_RET1_ARG2 (v8qi) +DEF_RET1_ARG2 (v16qi) +DEF_RET1_ARG2 (v32qi) +DEF_RET1_ARG2 (v64qi) +DEF_RET1_ARG2 (v128qi) +DEF_RET1_ARG2 (v256qi) +DEF_RET1_ARG2 (v512qi) +DEF_RET1_ARG2 (v1024qi) +DEF_RET1_ARG2 (v2048qi) +DEF_RET1_ARG2 (v4096qi) + +DEF_RET1_ARG3 (v1qi) +DEF_RET1_ARG3 (v2qi) +DEF_RET1_ARG3 (v4qi) +DEF_RET1_ARG3 (v8qi) +DEF_RET1_ARG3 (v16qi) +DEF_RET1_ARG3 (v32qi) +DEF_RET1_ARG3 (v64qi) +DEF_RET1_ARG3 (v128qi) +DEF_RET1_ARG3 (v256qi) +DEF_RET1_ARG3 (v512qi) +DEF_RET1_ARG3 (v1024qi) +DEF_RET1_ARG3 (v2048qi) +DEF_RET1_ARG3 (v4096qi) + +DEF_RET1_ARG4 (v1qi) +DEF_RET1_ARG4 (v2qi) +DEF_RET1_ARG4 (v4qi) +DEF_RET1_ARG4 (v8qi) +DEF_RET1_ARG4 (v16qi) +DEF_RET1_ARG4 (v32qi) +DEF_RET1_ARG4 (v64qi) +DEF_RET1_ARG4 (v128qi) +DEF_RET1_ARG4 (v256qi) +DEF_RET1_ARG4 (v512qi) +DEF_RET1_ARG4 (v1024qi) +DEF_RET1_ARG4 (v2048qi) +DEF_RET1_ARG4 (v4096qi) + +DEF_RET1_ARG5 (v1qi) +DEF_RET1_ARG5 (v2qi) +DEF_RET1_ARG5 (v4qi) +DEF_RET1_ARG5 (v8qi) +DEF_RET1_ARG5 (v16qi) +DEF_RET1_ARG5 (v32qi) +DEF_RET1_ARG5 (v64qi) +DEF_RET1_ARG5 (v128qi) +DEF_RET1_ARG5 (v256qi) +DEF_RET1_ARG5 (v512qi) +DEF_RET1_ARG5 (v1024qi) +DEF_RET1_ARG5 (v2048qi) +DEF_RET1_ARG5 (v4096qi) + +DEF_RET1_ARG6 (v1qi) +DEF_RET1_ARG6 (v2qi) +DEF_RET1_ARG6 (v4qi) +DEF_RET1_ARG6 (v8qi) +DEF_RET1_ARG6 (v16qi) +DEF_RET1_ARG6 (v32qi) +DEF_RET1_ARG6 (v64qi) +DEF_RET1_ARG6 (v128qi) +DEF_RET1_ARG6 (v256qi) +DEF_RET1_ARG6 (v512qi) +DEF_RET1_ARG6 (v1024qi) +DEF_RET1_ARG6 (v2048qi) +DEF_RET1_ARG6 (v4096qi) + +DEF_RET1_ARG7 (v1qi) +DEF_RET1_ARG7 (v2qi) +DEF_RET1_ARG7 (v4qi) +DEF_RET1_ARG7 (v8qi) +DEF_RET1_ARG7 (v16qi) +DEF_RET1_ARG7 (v32qi) +DEF_RET1_ARG7 (v64qi) +DEF_RET1_ARG7 (v128qi) +DEF_RET1_ARG7 (v256qi) +DEF_RET1_ARG7 (v512qi) +DEF_RET1_ARG7 (v1024qi) +DEF_RET1_ARG7 (v2048qi) +DEF_RET1_ARG7 (v4096qi) + +DEF_RET1_ARG8 (v1qi) +DEF_RET1_ARG8 (v2qi) +DEF_RET1_ARG8 (v4qi) +DEF_RET1_ARG8 (v8qi) +DEF_RET1_ARG8 (v16qi) +DEF_RET1_ARG8 (v32qi) +DEF_RET1_ARG8 (v64qi) +DEF_RET1_ARG8 (v128qi) +DEF_RET1_ARG8 (v256qi) +DEF_RET1_ARG8 (v512qi) +DEF_RET1_ARG8 (v1024qi) +DEF_RET1_ARG8 (v2048qi) +DEF_RET1_ARG8 (v4096qi) + +DEF_RET1_ARG9 (v1qi) +DEF_RET1_ARG9 (v2qi) +DEF_RET1_ARG9 (v4qi) +DEF_RET1_ARG9 (v8qi) +DEF_RET1_ARG9 (v16qi) +DEF_RET1_ARG9 (v32qi) +DEF_RET1_ARG9 (v64qi) +DEF_RET1_ARG9 (v128qi) +DEF_RET1_ARG9 (v256qi) +DEF_RET1_ARG9 (v512qi) +DEF_RET1_ARG9 (v1024qi) +DEF_RET1_ARG9 (v2048qi) +DEF_RET1_ARG9 (v4096qi) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 9 } } */ +/* { dg-final { scan-assembler-times {lbu\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lhu\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lw\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 35 } } */ +/* { dg-final { scan-assembler-times {sb\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sh\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c new file mode 100644 index 0000000..0abc6cf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-10.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64 --param riscv-autovec-preference=scalable -O3 -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "def.h" + +/* +** v4hf_RET1_ARG1: +** ret +*/ +DEF_RET1_ARG1 (v4hf) + +/* +** v2sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-16 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** addi\s+sp,\s*sp,\s*16 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v2sf) + +/* +** v4sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** sd\s+a2,\s*16\(sp\) +** sd\s+a3,\s*24\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** ld\s+a1,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v4sf) + +/* +** v1df_RET1_ARG3: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*8\(sp\) +** sd\s+a1,\s*16\(sp\) +** sd\s+a2,\s*24\(sp\) +** ... +** ld\s+a0,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG3 (v1df) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c new file mode 100644 index 0000000..8544f16 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-2.c @@ -0,0 +1,142 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1hi) +DEF_RET1_ARG0 (v2hi) +DEF_RET1_ARG0 (v4hi) +DEF_RET1_ARG0 (v8hi) +DEF_RET1_ARG0 (v16hi) +DEF_RET1_ARG0 (v32hi) +DEF_RET1_ARG0 (v64hi) +DEF_RET1_ARG0 (v128hi) +DEF_RET1_ARG0 (v256hi) +DEF_RET1_ARG0 (v512hi) +DEF_RET1_ARG0 (v1024hi) +DEF_RET1_ARG0 (v2048hi) + +DEF_RET1_ARG1 (v1hi) +DEF_RET1_ARG1 (v2hi) +DEF_RET1_ARG1 (v4hi) +DEF_RET1_ARG1 (v8hi) +DEF_RET1_ARG1 (v16hi) +DEF_RET1_ARG1 (v32hi) +DEF_RET1_ARG1 (v64hi) +DEF_RET1_ARG1 (v128hi) +DEF_RET1_ARG1 (v256hi) +DEF_RET1_ARG1 (v512hi) +DEF_RET1_ARG1 (v1024hi) +DEF_RET1_ARG1 (v2048hi) + +DEF_RET1_ARG2 (v1hi) +DEF_RET1_ARG2 (v2hi) +DEF_RET1_ARG2 (v4hi) +DEF_RET1_ARG2 (v8hi) +DEF_RET1_ARG2 (v16hi) +DEF_RET1_ARG2 (v32hi) +DEF_RET1_ARG2 (v64hi) +DEF_RET1_ARG2 (v128hi) +DEF_RET1_ARG2 (v256hi) +DEF_RET1_ARG2 (v512hi) +DEF_RET1_ARG2 (v1024hi) +DEF_RET1_ARG2 (v2048hi) + +DEF_RET1_ARG3 (v1hi) +DEF_RET1_ARG3 (v2hi) +DEF_RET1_ARG3 (v4hi) +DEF_RET1_ARG3 (v8hi) +DEF_RET1_ARG3 (v16hi) +DEF_RET1_ARG3 (v32hi) +DEF_RET1_ARG3 (v64hi) +DEF_RET1_ARG3 (v128hi) +DEF_RET1_ARG3 (v256hi) +DEF_RET1_ARG3 (v512hi) +DEF_RET1_ARG3 (v1024hi) +DEF_RET1_ARG3 (v2048hi) + +DEF_RET1_ARG4 (v1hi) +DEF_RET1_ARG4 (v2hi) +DEF_RET1_ARG4 (v4hi) +DEF_RET1_ARG4 (v8hi) +DEF_RET1_ARG4 (v16hi) +DEF_RET1_ARG4 (v32hi) +DEF_RET1_ARG4 (v64hi) +DEF_RET1_ARG4 (v128hi) +DEF_RET1_ARG4 (v256hi) +DEF_RET1_ARG4 (v512hi) +DEF_RET1_ARG4 (v1024hi) +DEF_RET1_ARG4 (v2048hi) + +DEF_RET1_ARG5 (v1hi) +DEF_RET1_ARG5 (v2hi) +DEF_RET1_ARG5 (v4hi) +DEF_RET1_ARG5 (v8hi) +DEF_RET1_ARG5 (v16hi) +DEF_RET1_ARG5 (v32hi) +DEF_RET1_ARG5 (v64hi) +DEF_RET1_ARG5 (v128hi) +DEF_RET1_ARG5 (v256hi) +DEF_RET1_ARG5 (v512hi) +DEF_RET1_ARG5 (v1024hi) +DEF_RET1_ARG5 (v2048hi) + +DEF_RET1_ARG6 (v1hi) +DEF_RET1_ARG6 (v2hi) +DEF_RET1_ARG6 (v4hi) +DEF_RET1_ARG6 (v8hi) +DEF_RET1_ARG6 (v16hi) +DEF_RET1_ARG6 (v32hi) +DEF_RET1_ARG6 (v64hi) +DEF_RET1_ARG6 (v128hi) +DEF_RET1_ARG6 (v256hi) +DEF_RET1_ARG6 (v512hi) +DEF_RET1_ARG6 (v1024hi) +DEF_RET1_ARG6 (v2048hi) + +DEF_RET1_ARG7 (v1hi) +DEF_RET1_ARG7 (v2hi) +DEF_RET1_ARG7 (v4hi) +DEF_RET1_ARG7 (v8hi) +DEF_RET1_ARG7 (v16hi) +DEF_RET1_ARG7 (v32hi) +DEF_RET1_ARG7 (v64hi) +DEF_RET1_ARG7 (v128hi) +DEF_RET1_ARG7 (v256hi) +DEF_RET1_ARG7 (v512hi) +DEF_RET1_ARG7 (v1024hi) +DEF_RET1_ARG7 (v2048hi) + +DEF_RET1_ARG8 (v1hi) +DEF_RET1_ARG8 (v2hi) +DEF_RET1_ARG8 (v4hi) +DEF_RET1_ARG8 (v8hi) +DEF_RET1_ARG8 (v16hi) +DEF_RET1_ARG8 (v32hi) +DEF_RET1_ARG8 (v64hi) +DEF_RET1_ARG8 (v128hi) +DEF_RET1_ARG8 (v256hi) +DEF_RET1_ARG8 (v512hi) +DEF_RET1_ARG8 (v1024hi) +DEF_RET1_ARG8 (v2048hi) + +DEF_RET1_ARG9 (v1hi) +DEF_RET1_ARG9 (v2hi) +DEF_RET1_ARG9 (v4hi) +DEF_RET1_ARG9 (v8hi) +DEF_RET1_ARG9 (v16hi) +DEF_RET1_ARG9 (v32hi) +DEF_RET1_ARG9 (v64hi) +DEF_RET1_ARG9 (v128hi) +DEF_RET1_ARG9 (v256hi) +DEF_RET1_ARG9 (v512hi) +DEF_RET1_ARG9 (v1024hi) +DEF_RET1_ARG9 (v2048hi) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 8 } } */ +/* { dg-final { scan-assembler-times {lhu\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lw\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 33 } } */ +/* { dg-final { scan-assembler-times {sh\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c new file mode 100644 index 0000000..17b0693 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-3.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1si) +DEF_RET1_ARG0 (v2si) +DEF_RET1_ARG0 (v4si) +DEF_RET1_ARG0 (v8si) +DEF_RET1_ARG0 (v16si) +DEF_RET1_ARG0 (v32si) +DEF_RET1_ARG0 (v64si) +DEF_RET1_ARG0 (v128si) +DEF_RET1_ARG0 (v256si) +DEF_RET1_ARG0 (v512si) +DEF_RET1_ARG0 (v1024si) + +DEF_RET1_ARG1 (v1si) +DEF_RET1_ARG1 (v2si) +DEF_RET1_ARG1 (v4si) +DEF_RET1_ARG1 (v8si) +DEF_RET1_ARG1 (v16si) +DEF_RET1_ARG1 (v32si) +DEF_RET1_ARG1 (v64si) +DEF_RET1_ARG1 (v128si) +DEF_RET1_ARG1 (v256si) +DEF_RET1_ARG1 (v512si) +DEF_RET1_ARG1 (v1024si) + +DEF_RET1_ARG2 (v1si) +DEF_RET1_ARG2 (v2si) +DEF_RET1_ARG2 (v4si) +DEF_RET1_ARG2 (v8si) +DEF_RET1_ARG2 (v16si) +DEF_RET1_ARG2 (v32si) +DEF_RET1_ARG2 (v64si) +DEF_RET1_ARG2 (v128si) +DEF_RET1_ARG2 (v256si) +DEF_RET1_ARG2 (v512si) +DEF_RET1_ARG2 (v1024si) + +DEF_RET1_ARG3 (v1si) +DEF_RET1_ARG3 (v2si) +DEF_RET1_ARG3 (v4si) +DEF_RET1_ARG3 (v8si) +DEF_RET1_ARG3 (v16si) +DEF_RET1_ARG3 (v32si) +DEF_RET1_ARG3 (v64si) +DEF_RET1_ARG3 (v128si) +DEF_RET1_ARG3 (v256si) +DEF_RET1_ARG3 (v512si) +DEF_RET1_ARG3 (v1024si) + +DEF_RET1_ARG4 (v1si) +DEF_RET1_ARG4 (v2si) +DEF_RET1_ARG4 (v4si) +DEF_RET1_ARG4 (v8si) +DEF_RET1_ARG4 (v16si) +DEF_RET1_ARG4 (v32si) +DEF_RET1_ARG4 (v64si) +DEF_RET1_ARG4 (v128si) +DEF_RET1_ARG4 (v256si) +DEF_RET1_ARG4 (v512si) +DEF_RET1_ARG4 (v1024si) + +DEF_RET1_ARG5 (v1si) +DEF_RET1_ARG5 (v2si) +DEF_RET1_ARG5 (v4si) +DEF_RET1_ARG5 (v8si) +DEF_RET1_ARG5 (v16si) +DEF_RET1_ARG5 (v32si) +DEF_RET1_ARG5 (v64si) +DEF_RET1_ARG5 (v128si) +DEF_RET1_ARG5 (v256si) +DEF_RET1_ARG5 (v512si) +DEF_RET1_ARG5 (v1024si) + +DEF_RET1_ARG6 (v1si) +DEF_RET1_ARG6 (v2si) +DEF_RET1_ARG6 (v4si) +DEF_RET1_ARG6 (v8si) +DEF_RET1_ARG6 (v16si) +DEF_RET1_ARG6 (v32si) +DEF_RET1_ARG6 (v64si) +DEF_RET1_ARG6 (v128si) +DEF_RET1_ARG6 (v256si) +DEF_RET1_ARG6 (v512si) +DEF_RET1_ARG6 (v1024si) + +DEF_RET1_ARG7 (v1si) +DEF_RET1_ARG7 (v2si) +DEF_RET1_ARG7 (v4si) +DEF_RET1_ARG7 (v8si) +DEF_RET1_ARG7 (v16si) +DEF_RET1_ARG7 (v32si) +DEF_RET1_ARG7 (v64si) +DEF_RET1_ARG7 (v128si) +DEF_RET1_ARG7 (v256si) +DEF_RET1_ARG7 (v512si) +DEF_RET1_ARG7 (v1024si) + +DEF_RET1_ARG8 (v1si) +DEF_RET1_ARG8 (v2si) +DEF_RET1_ARG8 (v4si) +DEF_RET1_ARG8 (v8si) +DEF_RET1_ARG8 (v16si) +DEF_RET1_ARG8 (v32si) +DEF_RET1_ARG8 (v64si) +DEF_RET1_ARG8 (v128si) +DEF_RET1_ARG8 (v256si) +DEF_RET1_ARG8 (v512si) +DEF_RET1_ARG8 (v1024si) + +DEF_RET1_ARG9 (v1si) +DEF_RET1_ARG9 (v2si) +DEF_RET1_ARG9 (v4si) +DEF_RET1_ARG9 (v8si) +DEF_RET1_ARG9 (v16si) +DEF_RET1_ARG9 (v32si) +DEF_RET1_ARG9 (v64si) +DEF_RET1_ARG9 (v128si) +DEF_RET1_ARG9 (v256si) +DEF_RET1_ARG9 (v512si) +DEF_RET1_ARG9 (v1024si) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 7 } } */ +/* { dg-final { scan-assembler-times {lw\s+a0,\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 31 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c new file mode 100644 index 0000000..8c3f6ba --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-4.c @@ -0,0 +1,118 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1di) +DEF_RET1_ARG0 (v2di) +DEF_RET1_ARG0 (v4di) +DEF_RET1_ARG0 (v8di) +DEF_RET1_ARG0 (v16di) +DEF_RET1_ARG0 (v32di) +DEF_RET1_ARG0 (v64di) +DEF_RET1_ARG0 (v128di) +DEF_RET1_ARG0 (v256di) +DEF_RET1_ARG0 (v512di) + +DEF_RET1_ARG1 (v1di) +DEF_RET1_ARG1 (v2di) +DEF_RET1_ARG1 (v4di) +DEF_RET1_ARG1 (v8di) +DEF_RET1_ARG1 (v16di) +DEF_RET1_ARG1 (v32di) +DEF_RET1_ARG1 (v64di) +DEF_RET1_ARG1 (v128di) +DEF_RET1_ARG1 (v256di) +DEF_RET1_ARG1 (v512di) + +DEF_RET1_ARG2 (v1di) +DEF_RET1_ARG2 (v2di) +DEF_RET1_ARG2 (v4di) +DEF_RET1_ARG2 (v8di) +DEF_RET1_ARG2 (v16di) +DEF_RET1_ARG2 (v32di) +DEF_RET1_ARG2 (v64di) +DEF_RET1_ARG2 (v128di) +DEF_RET1_ARG2 (v256di) +DEF_RET1_ARG2 (v512di) + +DEF_RET1_ARG3 (v1di) +DEF_RET1_ARG3 (v2di) +DEF_RET1_ARG3 (v4di) +DEF_RET1_ARG3 (v8di) +DEF_RET1_ARG3 (v16di) +DEF_RET1_ARG3 (v32di) +DEF_RET1_ARG3 (v64di) +DEF_RET1_ARG3 (v128di) +DEF_RET1_ARG3 (v256di) +DEF_RET1_ARG3 (v512di) + +DEF_RET1_ARG4 (v1di) +DEF_RET1_ARG4 (v2di) +DEF_RET1_ARG4 (v4di) +DEF_RET1_ARG4 (v8di) +DEF_RET1_ARG4 (v16di) +DEF_RET1_ARG4 (v32di) +DEF_RET1_ARG4 (v64di) +DEF_RET1_ARG4 (v128di) +DEF_RET1_ARG4 (v256di) +DEF_RET1_ARG4 (v512di) + +DEF_RET1_ARG5 (v1di) +DEF_RET1_ARG5 (v2di) +DEF_RET1_ARG5 (v4di) +DEF_RET1_ARG5 (v8di) +DEF_RET1_ARG5 (v16di) +DEF_RET1_ARG5 (v32di) +DEF_RET1_ARG5 (v64di) +DEF_RET1_ARG5 (v128di) +DEF_RET1_ARG5 (v256di) +DEF_RET1_ARG5 (v512di) + +DEF_RET1_ARG6 (v1di) +DEF_RET1_ARG6 (v2di) +DEF_RET1_ARG6 (v4di) +DEF_RET1_ARG6 (v8di) +DEF_RET1_ARG6 (v16di) +DEF_RET1_ARG6 (v32di) +DEF_RET1_ARG6 (v64di) +DEF_RET1_ARG6 (v128di) +DEF_RET1_ARG6 (v256di) +DEF_RET1_ARG6 (v512di) + +DEF_RET1_ARG7 (v1di) +DEF_RET1_ARG7 (v2di) +DEF_RET1_ARG7 (v4di) +DEF_RET1_ARG7 (v8di) +DEF_RET1_ARG7 (v16di) +DEF_RET1_ARG7 (v32di) +DEF_RET1_ARG7 (v64di) +DEF_RET1_ARG7 (v128di) +DEF_RET1_ARG7 (v256di) +DEF_RET1_ARG7 (v512di) + +DEF_RET1_ARG8 (v1di) +DEF_RET1_ARG8 (v2di) +DEF_RET1_ARG8 (v4di) +DEF_RET1_ARG8 (v8di) +DEF_RET1_ARG8 (v16di) +DEF_RET1_ARG8 (v32di) +DEF_RET1_ARG8 (v64di) +DEF_RET1_ARG8 (v128di) +DEF_RET1_ARG8 (v256di) +DEF_RET1_ARG8 (v512di) + +DEF_RET1_ARG9 (v1di) +DEF_RET1_ARG9 (v2di) +DEF_RET1_ARG9 (v4di) +DEF_RET1_ARG9 (v8di) +DEF_RET1_ARG9 (v16di) +DEF_RET1_ARG9 (v32di) +DEF_RET1_ARG9 (v64di) +DEF_RET1_ARG9 (v128di) +DEF_RET1_ARG9 (v256di) +DEF_RET1_ARG9 (v512di) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 6 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 29 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c new file mode 100644 index 0000000..a0208d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-5.c @@ -0,0 +1,141 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1hf) +DEF_RET1_ARG0 (v2hf) +DEF_RET1_ARG0 (v4hf) +DEF_RET1_ARG0 (v8hf) +DEF_RET1_ARG0 (v16hf) +DEF_RET1_ARG0 (v32hf) +DEF_RET1_ARG0 (v64hf) +DEF_RET1_ARG0 (v128hf) +DEF_RET1_ARG0 (v256hf) +DEF_RET1_ARG0 (v512hf) +DEF_RET1_ARG0 (v1024hf) +DEF_RET1_ARG0 (v2048hf) + +DEF_RET1_ARG1 (v1hf) +DEF_RET1_ARG1 (v2hf) +DEF_RET1_ARG1 (v4hf) +DEF_RET1_ARG1 (v8hf) +DEF_RET1_ARG1 (v16hf) +DEF_RET1_ARG1 (v32hf) +DEF_RET1_ARG1 (v64hf) +DEF_RET1_ARG1 (v128hf) +DEF_RET1_ARG1 (v256hf) +DEF_RET1_ARG1 (v512hf) +DEF_RET1_ARG1 (v1024hf) +DEF_RET1_ARG1 (v2048hf) + +DEF_RET1_ARG2 (v1hf) +DEF_RET1_ARG2 (v2hf) +DEF_RET1_ARG2 (v4hf) +DEF_RET1_ARG2 (v8hf) +DEF_RET1_ARG2 (v16hf) +DEF_RET1_ARG2 (v32hf) +DEF_RET1_ARG2 (v64hf) +DEF_RET1_ARG2 (v128hf) +DEF_RET1_ARG2 (v256hf) +DEF_RET1_ARG2 (v512hf) +DEF_RET1_ARG2 (v1024hf) +DEF_RET1_ARG2 (v2048hf) + +DEF_RET1_ARG3 (v1hf) +DEF_RET1_ARG3 (v2hf) +DEF_RET1_ARG3 (v4hf) +DEF_RET1_ARG3 (v8hf) +DEF_RET1_ARG3 (v16hf) +DEF_RET1_ARG3 (v32hf) +DEF_RET1_ARG3 (v64hf) +DEF_RET1_ARG3 (v128hf) +DEF_RET1_ARG3 (v256hf) +DEF_RET1_ARG3 (v512hf) +DEF_RET1_ARG3 (v1024hf) +DEF_RET1_ARG3 (v2048hf) + +DEF_RET1_ARG4 (v1hf) +DEF_RET1_ARG4 (v2hf) +DEF_RET1_ARG4 (v4hf) +DEF_RET1_ARG4 (v8hf) +DEF_RET1_ARG4 (v16hf) +DEF_RET1_ARG4 (v32hf) +DEF_RET1_ARG4 (v64hf) +DEF_RET1_ARG4 (v128hf) +DEF_RET1_ARG4 (v256hf) +DEF_RET1_ARG4 (v512hf) +DEF_RET1_ARG4 (v1024hf) +DEF_RET1_ARG4 (v2048hf) + +DEF_RET1_ARG5 (v1hf) +DEF_RET1_ARG5 (v2hf) +DEF_RET1_ARG5 (v4hf) +DEF_RET1_ARG5 (v8hf) +DEF_RET1_ARG5 (v16hf) +DEF_RET1_ARG5 (v32hf) +DEF_RET1_ARG5 (v64hf) +DEF_RET1_ARG5 (v128hf) +DEF_RET1_ARG5 (v256hf) +DEF_RET1_ARG5 (v512hf) +DEF_RET1_ARG5 (v1024hf) +DEF_RET1_ARG5 (v2048hf) + +DEF_RET1_ARG6 (v1hf) +DEF_RET1_ARG6 (v2hf) +DEF_RET1_ARG6 (v4hf) +DEF_RET1_ARG6 (v8hf) +DEF_RET1_ARG6 (v16hf) +DEF_RET1_ARG6 (v32hf) +DEF_RET1_ARG6 (v64hf) +DEF_RET1_ARG6 (v128hf) +DEF_RET1_ARG6 (v256hf) +DEF_RET1_ARG6 (v512hf) +DEF_RET1_ARG6 (v1024hf) +DEF_RET1_ARG6 (v2048hf) + +DEF_RET1_ARG7 (v1hf) +DEF_RET1_ARG7 (v2hf) +DEF_RET1_ARG7 (v4hf) +DEF_RET1_ARG7 (v8hf) +DEF_RET1_ARG7 (v16hf) +DEF_RET1_ARG7 (v32hf) +DEF_RET1_ARG7 (v64hf) +DEF_RET1_ARG7 (v128hf) +DEF_RET1_ARG7 (v256hf) +DEF_RET1_ARG7 (v512hf) +DEF_RET1_ARG7 (v1024hf) +DEF_RET1_ARG7 (v2048hf) + +DEF_RET1_ARG8 (v1hf) +DEF_RET1_ARG8 (v2hf) +DEF_RET1_ARG8 (v4hf) +DEF_RET1_ARG8 (v8hf) +DEF_RET1_ARG8 (v16hf) +DEF_RET1_ARG8 (v32hf) +DEF_RET1_ARG8 (v64hf) +DEF_RET1_ARG8 (v128hf) +DEF_RET1_ARG8 (v256hf) +DEF_RET1_ARG8 (v512hf) +DEF_RET1_ARG8 (v1024hf) +DEF_RET1_ARG8 (v2048hf) + +DEF_RET1_ARG9 (v1hf) +DEF_RET1_ARG9 (v2hf) +DEF_RET1_ARG9 (v4hf) +DEF_RET1_ARG9 (v8hf) +DEF_RET1_ARG9 (v16hf) +DEF_RET1_ARG9 (v32hf) +DEF_RET1_ARG9 (v64hf) +DEF_RET1_ARG9 (v128hf) +DEF_RET1_ARG9 (v256hf) +DEF_RET1_ARG9 (v512hf) +DEF_RET1_ARG9 (v1024hf) +DEF_RET1_ARG9 (v2048hf) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 8 } } */ +/* { dg-final { scan-assembler-times {lhu\s+a[0-1],\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {lw\s+a[0-1],\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {sh\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c new file mode 100644 index 0000000..58ef8bf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-6.c @@ -0,0 +1,129 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1sf) +DEF_RET1_ARG0 (v2sf) +DEF_RET1_ARG0 (v4sf) +DEF_RET1_ARG0 (v8sf) +DEF_RET1_ARG0 (v16sf) +DEF_RET1_ARG0 (v32sf) +DEF_RET1_ARG0 (v64sf) +DEF_RET1_ARG0 (v128sf) +DEF_RET1_ARG0 (v256sf) +DEF_RET1_ARG0 (v512sf) +DEF_RET1_ARG0 (v1024sf) + +DEF_RET1_ARG1 (v1sf) +DEF_RET1_ARG1 (v2sf) +DEF_RET1_ARG1 (v4sf) +DEF_RET1_ARG1 (v8sf) +DEF_RET1_ARG1 (v16sf) +DEF_RET1_ARG1 (v32sf) +DEF_RET1_ARG1 (v64sf) +DEF_RET1_ARG1 (v128sf) +DEF_RET1_ARG1 (v256sf) +DEF_RET1_ARG1 (v512sf) +DEF_RET1_ARG1 (v1024sf) + +DEF_RET1_ARG2 (v1sf) +DEF_RET1_ARG2 (v2sf) +DEF_RET1_ARG2 (v4sf) +DEF_RET1_ARG2 (v8sf) +DEF_RET1_ARG2 (v16sf) +DEF_RET1_ARG2 (v32sf) +DEF_RET1_ARG2 (v64sf) +DEF_RET1_ARG2 (v128sf) +DEF_RET1_ARG2 (v256sf) +DEF_RET1_ARG2 (v512sf) +DEF_RET1_ARG2 (v1024sf) + +DEF_RET1_ARG3 (v1sf) +DEF_RET1_ARG3 (v2sf) +DEF_RET1_ARG3 (v4sf) +DEF_RET1_ARG3 (v8sf) +DEF_RET1_ARG3 (v16sf) +DEF_RET1_ARG3 (v32sf) +DEF_RET1_ARG3 (v64sf) +DEF_RET1_ARG3 (v128sf) +DEF_RET1_ARG3 (v256sf) +DEF_RET1_ARG3 (v512sf) +DEF_RET1_ARG3 (v1024sf) + +DEF_RET1_ARG4 (v1sf) +DEF_RET1_ARG4 (v2sf) +DEF_RET1_ARG4 (v4sf) +DEF_RET1_ARG4 (v8sf) +DEF_RET1_ARG4 (v16sf) +DEF_RET1_ARG4 (v32sf) +DEF_RET1_ARG4 (v64sf) +DEF_RET1_ARG4 (v128sf) +DEF_RET1_ARG4 (v256sf) +DEF_RET1_ARG4 (v512sf) +DEF_RET1_ARG4 (v1024sf) + +DEF_RET1_ARG5 (v1sf) +DEF_RET1_ARG5 (v2sf) +DEF_RET1_ARG5 (v4sf) +DEF_RET1_ARG5 (v8sf) +DEF_RET1_ARG5 (v16sf) +DEF_RET1_ARG5 (v32sf) +DEF_RET1_ARG5 (v64sf) +DEF_RET1_ARG5 (v128sf) +DEF_RET1_ARG5 (v256sf) +DEF_RET1_ARG5 (v512sf) +DEF_RET1_ARG5 (v1024sf) + +DEF_RET1_ARG6 (v1sf) +DEF_RET1_ARG6 (v2sf) +DEF_RET1_ARG6 (v4sf) +DEF_RET1_ARG6 (v8sf) +DEF_RET1_ARG6 (v16sf) +DEF_RET1_ARG6 (v32sf) +DEF_RET1_ARG6 (v64sf) +DEF_RET1_ARG6 (v128sf) +DEF_RET1_ARG6 (v256sf) +DEF_RET1_ARG6 (v512sf) +DEF_RET1_ARG6 (v1024sf) + +DEF_RET1_ARG7 (v1sf) +DEF_RET1_ARG7 (v2sf) +DEF_RET1_ARG7 (v4sf) +DEF_RET1_ARG7 (v8sf) +DEF_RET1_ARG7 (v16sf) +DEF_RET1_ARG7 (v32sf) +DEF_RET1_ARG7 (v64sf) +DEF_RET1_ARG7 (v128sf) +DEF_RET1_ARG7 (v256sf) +DEF_RET1_ARG7 (v512sf) +DEF_RET1_ARG7 (v1024sf) + +DEF_RET1_ARG8 (v1sf) +DEF_RET1_ARG8 (v2sf) +DEF_RET1_ARG8 (v4sf) +DEF_RET1_ARG8 (v8sf) +DEF_RET1_ARG8 (v16sf) +DEF_RET1_ARG8 (v32sf) +DEF_RET1_ARG8 (v64sf) +DEF_RET1_ARG8 (v128sf) +DEF_RET1_ARG8 (v256sf) +DEF_RET1_ARG8 (v512sf) +DEF_RET1_ARG8 (v1024sf) + +DEF_RET1_ARG9 (v1sf) +DEF_RET1_ARG9 (v2sf) +DEF_RET1_ARG9 (v4sf) +DEF_RET1_ARG9 (v8sf) +DEF_RET1_ARG9 (v16sf) +DEF_RET1_ARG9 (v32sf) +DEF_RET1_ARG9 (v64sf) +DEF_RET1_ARG9 (v128sf) +DEF_RET1_ARG9 (v256sf) +DEF_RET1_ARG9 (v512sf) +DEF_RET1_ARG9 (v1024sf) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 7 } } */ +/* { dg-final { scan-assembler-times {lw\s+a[0-1],\s*[0-9]+\(sp\)} 8 } } */ +/* { dg-final { scan-assembler-times {sw\s+a[0-7],\s*[0-9]+\(sp\)} 43 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c new file mode 100644 index 0000000..e35ccd5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-7.c @@ -0,0 +1,118 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b --param riscv-autovec-preference=scalable -mabi=lp64d -O3" } */ + +#include "def.h" + +DEF_RET1_ARG0 (v1df) +DEF_RET1_ARG0 (v2df) +DEF_RET1_ARG0 (v4df) +DEF_RET1_ARG0 (v8df) +DEF_RET1_ARG0 (v16df) +DEF_RET1_ARG0 (v32df) +DEF_RET1_ARG0 (v64df) +DEF_RET1_ARG0 (v128df) +DEF_RET1_ARG0 (v256df) +DEF_RET1_ARG0 (v512df) + +DEF_RET1_ARG1 (v1df) +DEF_RET1_ARG1 (v2df) +DEF_RET1_ARG1 (v4df) +DEF_RET1_ARG1 (v8df) +DEF_RET1_ARG1 (v16df) +DEF_RET1_ARG1 (v32df) +DEF_RET1_ARG1 (v64df) +DEF_RET1_ARG1 (v128df) +DEF_RET1_ARG1 (v256df) +DEF_RET1_ARG1 (v512df) + +DEF_RET1_ARG2 (v1df) +DEF_RET1_ARG2 (v2df) +DEF_RET1_ARG2 (v4df) +DEF_RET1_ARG2 (v8df) +DEF_RET1_ARG2 (v16df) +DEF_RET1_ARG2 (v32df) +DEF_RET1_ARG2 (v64df) +DEF_RET1_ARG2 (v128df) +DEF_RET1_ARG2 (v256df) +DEF_RET1_ARG2 (v512df) + +DEF_RET1_ARG3 (v1df) +DEF_RET1_ARG3 (v2df) +DEF_RET1_ARG3 (v4df) +DEF_RET1_ARG3 (v8df) +DEF_RET1_ARG3 (v16df) +DEF_RET1_ARG3 (v32df) +DEF_RET1_ARG3 (v64df) +DEF_RET1_ARG3 (v128df) +DEF_RET1_ARG3 (v256df) +DEF_RET1_ARG3 (v512df) + +DEF_RET1_ARG4 (v1df) +DEF_RET1_ARG4 (v2df) +DEF_RET1_ARG4 (v4df) +DEF_RET1_ARG4 (v8df) +DEF_RET1_ARG4 (v16df) +DEF_RET1_ARG4 (v32df) +DEF_RET1_ARG4 (v64df) +DEF_RET1_ARG4 (v128df) +DEF_RET1_ARG4 (v256df) +DEF_RET1_ARG4 (v512df) + +DEF_RET1_ARG5 (v1df) +DEF_RET1_ARG5 (v2df) +DEF_RET1_ARG5 (v4df) +DEF_RET1_ARG5 (v8df) +DEF_RET1_ARG5 (v16df) +DEF_RET1_ARG5 (v32df) +DEF_RET1_ARG5 (v64df) +DEF_RET1_ARG5 (v128df) +DEF_RET1_ARG5 (v256df) +DEF_RET1_ARG5 (v512df) + +DEF_RET1_ARG6 (v1df) +DEF_RET1_ARG6 (v2df) +DEF_RET1_ARG6 (v4df) +DEF_RET1_ARG6 (v8df) +DEF_RET1_ARG6 (v16df) +DEF_RET1_ARG6 (v32df) +DEF_RET1_ARG6 (v64df) +DEF_RET1_ARG6 (v128df) +DEF_RET1_ARG6 (v256df) +DEF_RET1_ARG6 (v512df) + +DEF_RET1_ARG7 (v1df) +DEF_RET1_ARG7 (v2df) +DEF_RET1_ARG7 (v4df) +DEF_RET1_ARG7 (v8df) +DEF_RET1_ARG7 (v16df) +DEF_RET1_ARG7 (v32df) +DEF_RET1_ARG7 (v64df) +DEF_RET1_ARG7 (v128df) +DEF_RET1_ARG7 (v256df) +DEF_RET1_ARG7 (v512df) + +DEF_RET1_ARG8 (v1df) +DEF_RET1_ARG8 (v2df) +DEF_RET1_ARG8 (v4df) +DEF_RET1_ARG8 (v8df) +DEF_RET1_ARG8 (v16df) +DEF_RET1_ARG8 (v32df) +DEF_RET1_ARG8 (v64df) +DEF_RET1_ARG8 (v128df) +DEF_RET1_ARG8 (v256df) +DEF_RET1_ARG8 (v512df) + +DEF_RET1_ARG9 (v1df) +DEF_RET1_ARG9 (v2df) +DEF_RET1_ARG9 (v4df) +DEF_RET1_ARG9 (v8df) +DEF_RET1_ARG9 (v16df) +DEF_RET1_ARG9 (v32df) +DEF_RET1_ARG9 (v64df) +DEF_RET1_ARG9 (v128df) +DEF_RET1_ARG9 (v256df) +DEF_RET1_ARG9 (v512df) + +/* { dg-final { scan-assembler-times {li\s+a[0-1],\s*0} 6 } } */ +/* { dg-final { scan-assembler-times {ld\s+a[0-1],\s*[0-9]+\(sp\)} 29 } } */ +/* { dg-final { scan-assembler-times {sd\s+a[0-7],\s*[0-9]+\(sp\)} 103 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c new file mode 100644 index 0000000..ed66a2c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-8.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvl4096b -mabi=lp64d --param riscv-autovec-preference=scalable -O3 -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "def.h" + +/* +** v8qi_RET1_ARG0: +** li\s+a0,\s*0 +** ret +*/ +DEF_RET1_ARG0 (v8qi) + +/* +** v4hi_RET1_ARG1: +** ret +*/ +DEF_RET1_ARG1 (v4hi) + +/* +** v2si_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-16 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** addi\s+sp,\s*sp,\s*16 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v2si) + +/* +** v1di_RET1_ARG3: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*8\(sp\) +** sd\s+a1,\s*16\(sp\) +** sd\s+a2,\s*24\(sp\) +** ... +** ld\s+a0,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG3 (v1di) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c new file mode 100644 index 0000000..ab8e79c --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-9.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh_zvl4096b -mabi=lp64d --param riscv-autovec-preference=scalable -O3 -fno-schedule-insns -fno-schedule-insns2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "def.h" + +/* +** v4hf_RET1_ARG1: +** ret +*/ +DEF_RET1_ARG1 (v4hf) + +/* +** v2sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-16 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** addi\s+sp,\s*sp,\s*16 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v2sf) + +/* +** v4sf_RET1_ARG2: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*0\(sp\) +** sd\s+a1,\s*8\(sp\) +** sd\s+a2,\s*16\(sp\) +** sd\s+a3,\s*24\(sp\) +** ... +** ld\s+a0,\s*0\(sp\) +** ld\s+a1,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG2 (v4sf) + +/* +** v1df_RET1_ARG3: +** addi\s+sp,\s*sp,\s*-32 +** sd\s+a0,\s*8\(sp\) +** sd\s+a1,\s*16\(sp\) +** sd\s+a2,\s*24\(sp\) +** ... +** ld\s+a0,\s*8\(sp\) +** addi\s+sp,\s*sp,\s*32 +** jr\s+ra +*/ +DEF_RET1_ARG3 (v1df) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c new file mode 100644 index 0000000..d8aa5c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-1.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef char v16qi __attribute__ ((vector_size (16))); + +v16qi +add (v16qi a1, v16qi a2, v16qi a3, v16qi a4, v16qi a5, v16qi a6, v16qi a7, + v16qi a8, v16qi a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v16qi a1 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a2 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a3 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a4 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a5 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a6 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a7 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a8 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi a9 = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }; + v16qi expected = { + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + }; + v16qi result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 16; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c new file mode 100644 index 0000000..57376a3 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-2.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef short v8hi __attribute__ ((vector_size (16))); + +v8hi +add (v8hi a1, v8hi a2, v8hi a3, v8hi a4, v8hi a5, v8hi a6, v8hi a7, + v8hi a8, v8hi a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v8hi a1 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a2 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a3 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a4 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a5 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a6 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a7 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a8 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi a9 = { + 1, 1, 1, 1, 1, 1, 1, 1, + }; + v8hi expected = { + 9, 9, 9, 9, 9, 9, 9, 9, + }; + v8hi result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 8; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c new file mode 100644 index 0000000..b37cd56 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-3.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef int v4si __attribute__ ((vector_size (16))); + +v4si +add (v4si a1, v4si a2, v4si a3, v4si a4, v4si a5, v4si a6, v4si a7, + v4si a8, v4si a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v4si a1 = { + 1, 1, 1, 1, + }; + v4si a2 = { + 1, 1, 1, 1, + }; + v4si a3 = { + 1, 1, 1, 1, + }; + v4si a4 = { + 1, 1, 1, 1, + }; + v4si a5 = { + 1, 1, 1, 1, + }; + v4si a6 = { + 1, 1, 1, 1, + }; + v4si a7 = { + 1, 1, 1, 1, + }; + v4si a8 = { + 1, 1, 1, 1, + }; + v4si a9 = { + 1, 1, 1, 1, + }; + v4si expected = { + 9, 9, 9, 9, + }; + v4si result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 4; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c new file mode 100644 index 0000000..0788447 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-4.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef long long v2di __attribute__ ((vector_size (16))); + +v2di +add (v2di a1, v2di a2, v2di a3, v2di a4, v2di a5, v2di a6, v2di a7, + v2di a8, v2di a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v2di a1 = { + 1, 1, + }; + v2di a2 = { + 1, 1, + }; + v2di a3 = { + 1, 1, + }; + v2di a4 = { + 1, 1, + }; + v2di a5 = { + 1, 1, + }; + v2di a6 = { + 1, 1, + }; + v2di a7 = { + 1, 1, + }; + v2di a8 = { + 1, 1, + }; + v2di a9 = { + 1, 1, + }; + v2di expected = { + 9, 9, + }; + v2di result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 2; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c new file mode 100644 index 0000000..ec8658d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-5.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef float v4sf __attribute__ ((vector_size (16))); + +v4sf +add (v4sf a1, v4sf a2, v4sf a3, v4sf a4, v4sf a5, v4sf a6, v4sf a7, + v4sf a8, v4sf a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v4sf a1 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a2 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a3 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a4 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a5 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a6 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a7 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a8 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf a9 = { + 1.0, 1.0, 1.0, 1.0, + }; + v4sf expected = { + 9.0, 9.0, 9.0, 9.0, + }; + v4sf result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 4; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c new file mode 100644 index 0000000..bbb53a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/calling-convention-run-6.c @@ -0,0 +1,55 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=scalable" } */ + +typedef long long v2df __attribute__ ((vector_size (16))); + +v2df +add (v2df a1, v2df a2, v2df a3, v2df a4, v2df a5, v2df a6, v2df a7, + v2df a8, v2df a9) +{ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; +} + +int +main () +{ + v2df a1 = { + 1.0, 1.0, + }; + v2df a2 = { + 1.0, 1.0, + }; + v2df a3 = { + 1.0, 1.0, + }; + v2df a4 = { + 1.0, 1.0, + }; + v2df a5 = { + 1.0, 1.0, + }; + v2df a6 = { + 1.0, 1.0, + }; + v2df a7 = { + 1.0, 1.0, + }; + v2df a8 = { + 1.0, 1.0, + }; + v2df a9 = { + 1.0, 1.0, + }; + v2df expected = { + 9.0, 9.0, + }; + v2df result = add (a1, a2, a3, a4, a5, a6, a7, a8, a9); + + unsigned i; + + for (i = 0; i < 2; i++) + if (result[i] != expected[i]) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h index cb7a1c9..ef55c4d 100644 --- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls/def.h @@ -860,3 +860,77 @@ typedef double v512df __attribute__ ((vector_size (4096))); TYPE1 v = {__VA_ARGS__}; \ *(TYPE1 *) out = v; \ } + +#define DEF_RET1_ARG0(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG0 () \ + { \ + TYPE r = {}; \ + return r; \ + } + +#define DEF_RET1_ARG1(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG1 (TYPE a1) \ + { \ + return a1; \ + } + +#define DEF_RET1_ARG2(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG2 (TYPE a1, TYPE a2) \ + { \ + return a1 + a2; \ + } + +#define DEF_RET1_ARG3(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG3 (TYPE a1, TYPE a2, TYPE a3) \ + { \ + return a1 + a2 + a3; \ + } + +#define DEF_RET1_ARG4(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG4 (TYPE a1, TYPE a2, TYPE a3, TYPE a4) \ + { \ + return a1 + a2 + a3 + a4; \ + } + +#define DEF_RET1_ARG5(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG5 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5) \ + { \ + return a1 + a2 + a3 + a4 + a5; \ + } + +#define DEF_RET1_ARG6(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG6 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6; \ + } + +#define DEF_RET1_ARG7(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG7 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6, \ + TYPE a7) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6 + a7; \ + } + +#define DEF_RET1_ARG8(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG8 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6, \ + TYPE a7, TYPE a8) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; \ + } + +#define DEF_RET1_ARG9(TYPE) \ + TYPE __attribute__((noinline)) \ + TYPE##_RET1_ARG9 (TYPE a1, TYPE a2, TYPE a3, TYPE a4, TYPE a5, TYPE a6, \ + TYPE a7, TYPE a8, TYPE a9) \ + { \ + return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9; \ + } diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c new file mode 100644 index 0000000..bd4943b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-1.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3" } */ + +#include "riscv_vector.h" + +void +test () +{ + __riscv_vand (); /* { dg-error {no matching function call to '__riscv_vand' with empty args} } */ + __riscv_vand_tu (); /* { dg-error {no matching function call to '__riscv_vand_tu' with empty args} } */ + __riscv_vand_tumu (); /* { dg-error {no matching function call to '__riscv_vand_tumu' with empty args} } */ + + __riscv_vcompress (); /* { dg-error {no matching function call to '__riscv_vcompress' with empty args} } */ + __riscv_vcompress_tu (); /* { dg-error {no matching function call to '__riscv_vcompress_tu' with empty args} } */ + + __riscv_vcpop (); /* { dg-error {no matching function call to '__riscv_vcpop' with empty args} } */ + + __riscv_vdiv (); /* { dg-error {no matching function call to '__riscv_vdiv' with empty args} } */ + __riscv_vdiv_tu (); /* { dg-error {no matching function call to '__riscv_vdiv_tu' with empty args} } */ + __riscv_vdiv_tumu (); /* { dg-error {no matching function call to '__riscv_vdiv_tumu' with empty args} } */ + + __riscv_vfabs (); /* { dg-error {no matching function call to '__riscv_vfabs' with empty args} } */ + __riscv_vfabs_tu (); /* { dg-error {no matching function call to '__riscv_vfabs_tu' with empty args} } */ + __riscv_vfabs_tumu (); /* { dg-error {no matching function call to '__riscv_vfabs_tumu' with empty args} } */ + + __riscv_vfadd (); /* { dg-error {no matching function call to '__riscv_vfadd' with empty args} } */ + __riscv_vfadd_tu (); /* { dg-error {no matching function call to '__riscv_vfadd_tu' with empty args} } */ + __riscv_vfadd_tumu (); /* { dg-error {no matching function call to '__riscv_vfadd_tumu' with empty args} } */ + + __riscv_vfclass (); /* { dg-error {no matching function call to '__riscv_vfclass' with empty args} } */ + __riscv_vfclass_tu (); /* { dg-error {no matching function call to '__riscv_vfclass_tu' with empty args} } */ + __riscv_vfclass_tumu (); /* { dg-error {no matching function call to '__riscv_vfclass_tumu' with empty args} } */ + + __riscv_vfcvt_x (); /* { dg-error {no matching function call to '__riscv_vfcvt_x' with empty args} } */ + __riscv_vfcvt_x_tu (); /* { dg-error {no matching function call to '__riscv_vfcvt_x_tu' with empty args} } */ + __riscv_vfcvt_x_tumu (); /* { dg-error {no matching function call to '__riscv_vfcvt_x_tumu' with empty args} } */ + + __riscv_vfirst (); /* { dg-error {no matching function call to '__riscv_vfirst' with empty args} } */ + + __riscv_vfmadd (); /* { dg-error {no matching function call to '__riscv_vfmadd' with empty args} } */ + __riscv_vfmadd_tu (); /* { dg-error {no matching function call to '__riscv_vfmadd_tu' with empty args} } */ + __riscv_vfmadd_tumu (); /* { dg-error {no matching function call to '__riscv_vfmadd_tumu' with empty args} } */ + + __riscv_vfmerge (); /* { dg-error {no matching function call to '__riscv_vfmerge' with empty args} } */ + __riscv_vfmerge_tu (); /* { dg-error {no matching function call to '__riscv_vfmerge_tu' with empty args} } */ + + __riscv_vfncvt_x (); /* { dg-error {no matching function call to '__riscv_vfncvt_x' with empty args} } */ + __riscv_vfncvt_x_tu (); /* { dg-error {no matching function call to '__riscv_vfncvt_x_tu' with empty args} } */ + __riscv_vfncvt_x_tumu (); /* { dg-error {no matching function call to '__riscv_vfncvt_x_tumu' with empty args} } */ + + __riscv_vfrec7 (); /* { dg-error {no matching function call to '__riscv_vfrec7' with empty args} } */ + __riscv_vfrec7_tu (); /* { dg-error {no matching function call to '__riscv_vfrec7_tu' with empty args} } */ + __riscv_vfrec7_tumu (); /* { dg-error {no matching function call to '__riscv_vfrec7_tumu' with empty args} } */ + + __riscv_vfrsqrt7 (); /* { dg-error {no matching function call to '__riscv_vfrsqrt7' with empty args} } */ + __riscv_vfrsqrt7_tu (); /* { dg-error {no matching function call to '__riscv_vfrsqrt7_tu' with empty args} } */ + __riscv_vfrsqrt7_tumu (); /* { dg-error {no matching function call to '__riscv_vfrsqrt7_tumu' with empty args} } */ + + __riscv_vfsgnjn (); /* { dg-error {no matching function call to '__riscv_vfsgnjn' with empty args} } */ + __riscv_vfsgnjn_tu (); /* { dg-error {no matching function call to '__riscv_vfsgnjn_tu' with empty args} } */ + __riscv_vfsgnjn_tumu (); /* { dg-error {no matching function call to '__riscv_vfsgnjn_tumu' with empty args} } */ + + __riscv_vfslide1down (); /* { dg-error {no matching function call to '__riscv_vfslide1down' with empty args} } */ + __riscv_vfslide1down_tu (); /* { dg-error {no matching function call to '__riscv_vfslide1down_tu' with empty args} } */ + __riscv_vfslide1down_tumu (); /* { dg-error {no matching function call to '__riscv_vfslide1down_tumu' with empty args} } */ + + __riscv_vfwmul (); /* { dg-error {no matching function call to '__riscv_vfwmul' with empty args} } */ + __riscv_vfwmul_tu (); /* { dg-error {no matching function call to '__riscv_vfwmul_tu' with empty args} } */ + __riscv_vfwmul_tumu (); /* { dg-error {no matching function call to '__riscv_vfwmul_tumu' with empty args} } */ + + __riscv_vle32 (); /* { dg-error {no matching function call to '__riscv_vle32' with empty args} } */ + __riscv_vle32_tu (); /* { dg-error {no matching function call to '__riscv_vle32_tu' with empty args} } */ + __riscv_vle32_tumu (); /* { dg-error {no matching function call to '__riscv_vle32_tumu' with empty args} } */ + + __riscv_vlse64 (); /* { dg-error {no matching function call to '__riscv_vlse64' with empty args} } */ + __riscv_vlse64_tu (); /* { dg-error {no matching function call to '__riscv_vlse64_tu' with empty args} } */ + __riscv_vlse64_tumu (); /* { dg-error {no matching function call to '__riscv_vlse64_tumu' with empty args} } */ + + __riscv_vmfeq (); /* { dg-error {no matching function call to '__riscv_vmfeq' with empty args} } */ + + __riscv_vreinterpret_u8m1 (); /* { dg-error {no matching function call to '__riscv_vreinterpret_u8m1' with empty args} } */ + + __riscv_vfredosum (); /* { dg-error {no matching function call to '__riscv_vfredosum' with empty args} } */ + __riscv_vfredosum_tu (); /* { dg-error {no matching function call to '__riscv_vfredosum_tu' with empty args} } */ +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c new file mode 100644 index 0000000..621fb9f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr113766-2.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64 -O3" } */ + +#include "riscv_vector.h" + +void +test (vint32m1_t vi32m1, vint64m1_t vi64m1, vfloat32m1_t vf32m1, unsigned vl) +{ + __riscv_vand (vi32m1, vl); /* { dg-error {too few arguments to function '__riscv_vand_vx_i32m1'} } */ + + __riscv_vcompress (vi32m1, vl); /* { dg-error {too many arguments to function '__riscv_vcompress'} } */ + + __riscv_vcpop (vi32m1, vl); /* { dg-error {too many arguments to function '__riscv_vcpop'} } */ + + __riscv_vdiv (vi32m1, vl); /* { dg-error {too few arguments to function '__riscv_vdiv_vx_i32m1'} } */ + + __riscv_vfabs (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfabs'} } */ + + __riscv_vfadd (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfadd'} } */ + + __riscv_vfcvt_x (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfcvt_x'} } */ + + __riscv_vfirst (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfirst'} } */ + + __riscv_vfmadd (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfmadd'} } */ + + __riscv_vfmerge (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfmerge'} } */ + + __riscv_vfncvt_x (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfncvt_x'} } */ + + __riscv_vfrec7 (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfrec7'} } */ + + __riscv_vfrsqrt7 (vf32m1); /* { dg-error {too many arguments to function '__riscv_vfrsqrt7'} } */ + + __riscv_vfsgnjn (vf32m1, vl); /* { dg-error {too few arguments to function '__riscv_vfsgnjn_vf_f32m1'} } */ + + __riscv_vfslide1down (vf32m1, vl); /* { dg-error {too few arguments to function '__riscv_vfslide1down_vf_f32m1'} } */ + + __riscv_vfwmul (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfwmul'} } */ + + __riscv_vle32 (vi32m1, vl); /* { dg-error {too many arguments to function '__riscv_vle32'} } */ + + __riscv_vlse64 (vi64m1, vl); /* { dg-error {too many arguments to function '__riscv_vlse64'} } */ + + __riscv_vmfeq (vf32m1, vl); /* { dg-error {too few arguments to function '__riscv_vmfeq_vf_f32m1_b32'} } */ + + __riscv_vfredosum (vf32m1, vl); /* { dg-error {too many arguments to function '__riscv_vfredosum'} } */ +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c new file mode 100644 index 0000000..98eacc1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/vsetvl/vsetvl_pre-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "--param=riscv-autovec-preference=scalable -march=rv64gcv -mabi=lp64d -O3 -fdump-rtl-vsetvl-details" } */ + +#include "riscv_vector.h" +void +foo (int *in, int *out) +{ + vint32mf2_t v = *(vint32mf2_t *) (in + 100); + *(vint32mf2_t *) (out + 200) = v; +} + +/* { dg-final { scan-rtl-dump "Eliminate vsetvl_pre" "vsetvl" { target { no-opts "-O0" } } } } */ diff --git a/gcc/testsuite/gcc.target/riscv/za-ext.c b/gcc/testsuite/gcc.target/riscv/za-ext.c new file mode 100644 index 0000000..126da2f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/za-ext.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_za64rs_za128rs" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_za64rs_za128rs" { target { rv32 } } } */ + +#ifndef __riscv_za64rs +#error "Feature macro for 'za64rs' not defined" +#endif + +#ifndef __riscv_za128rs +#error "Feature macro for 'za128rs' not defined" +#endif + +int +foo (int a) +{ + return a; +} diff --git a/gcc/testsuite/gcc.target/riscv/zi-ext.c b/gcc/testsuite/gcc.target/riscv/zi-ext.c new file mode 100644 index 0000000..65a7acb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zi-ext.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zic64b_ziccamoa_ziccif_zicclsm_ziccrse" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zic64b_ziccamoa_ziccif_zicclsm_ziccrse" { target { rv32 } } } */ + +#ifndef __riscv_zic64b +#error "Feature macro for 'zic64b' not defined" +#endif + +#ifndef __riscv_ziccamoa +#error "Feature macro for 'ziccamoa' not defined" +#endif + +#ifndef __riscv_ziccif +#error "Feature macro for 'ziccif' not defined" +#endif + +#ifndef __riscv_zicclsm +#error "Feature macro for 'zicclsm' not defined" +#endif + +#ifndef __riscv_ziccrse +#error "Feature macro for 'ziccrse' not defined" +#endif + +int +foo (int a) +{ + return a; +} diff --git a/gcc/testsuite/gdc.dg/asan/asan.exp b/gcc/testsuite/gdc.dg/asan/asan.exp index 72b3669..89c6bf3 100644 --- a/gcc/testsuite/gdc.dg/asan/asan.exp +++ b/gcc/testsuite/gdc.dg/asan/asan.exp @@ -20,7 +20,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ so make sure we provide paths for it. +asan_init 1 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/gdc.dg/ubsan/ubsan.exp b/gcc/testsuite/gdc.dg/ubsan/ubsan.exp index 6ad665a..7613a3b 100644 --- a/gcc/testsuite/gdc.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/gdc.dg/ubsan/ubsan.exp @@ -20,7 +20,8 @@ load_lib ubsan-dg.exp # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ so make sure we provide paths for it. +ubsan_init 1 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d index 3bc699a..9909620 100644 --- a/gcc/testsuite/gdc.test/compilable/b18242.d +++ b/gcc/testsuite/gdc.test/compilable/b18242.d @@ -7,7 +7,7 @@ class Object { } class TypeInfo { } class TypeInfo_Class : TypeInfo { - version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; } + version(D_LP64) { ubyte[136+16] _x; } else { ubyte[68+16] _x; } } class Throwable { } diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4162.d b/gcc/testsuite/gdc.test/compilable/ddoc4162.d index dd24475..f609fc9 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc4162.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc4162.d @@ -1,4 +1,4 @@ -// PERMUTE_ARGS: +// PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446.d b/gcc/testsuite/gdc.test/compilable/ddoc5446.d index 29cb8c9..2da477f 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc5446.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc5446.d @@ -1,4 +1,4 @@ -// PERMUTE_ARGS: +// PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // EXTRA_FILES: ddoc5446a.d ddoc5446b.d // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7795.d b/gcc/testsuite/gdc.test/compilable/ddoc7795.d index 2a6ba02..9ad7740 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc7795.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc7795.d @@ -1,4 +1,4 @@ -// PERMUTE_ARGS: +// PERMUTE_ARGS: // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- // POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12.d b/gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d index 337f37a..337f37a 100644 --- a/gcc/testsuite/gdc.test/compilable/ddoc12.d +++ b/gcc/testsuite/gdc.test/compilable/ddoc_bom_UTF8.d diff --git a/gcc/testsuite/gdc.test/compilable/imports/defines.c b/gcc/testsuite/gdc.test/compilable/imports/defines.c index 6bd0736..8a5601a 100644 --- a/gcc/testsuite/gdc.test/compilable/imports/defines.c +++ b/gcc/testsuite/gdc.test/compilable/imports/defines.c @@ -26,3 +26,7 @@ _Static_assert(F80 == 9.0L, "9"); #define SSS "hello" _Static_assert(SSS[0] == 'h', "10"); + +#define ABC 12 +#define GHI (size) abbadabba +#define DEF (ABC + 5) diff --git a/gcc/testsuite/gdc.test/compilable/issue20339.d b/gcc/testsuite/gdc.test/compilable/issue20339.d new file mode 100644 index 0000000..3d5bdd8 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue20339.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +4 +false +false +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=20339 + +struct S +{ + pragma(msg, cast(int)S.sizeof); + + this(this){} + ~this(){} + + int f; +} + +static assert(__traits(isPOD, S) == false); + + +pragma(msg, __traits(isPOD, T)); + +struct T +{ + this(this){} + ~this(){} +} + +static assert(__traits(isPOD, T) == false); + + +struct U +{ + pragma(msg, __traits(isPOD, U)); + + this(this){} + ~this(){} +} + +static assert(__traits(isPOD, U) == false); diff --git a/gcc/testsuite/gdc.test/compilable/issue24316.d b/gcc/testsuite/gdc.test/compilable/issue24316.d new file mode 100644 index 0000000..16d8a8b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue24316.d @@ -0,0 +1,13 @@ +struct S +{ + int i; +} + +int f(immutable S *s) +{ + return s.i; +} + +immutable S globalS = S(5); + +static assert (f(&globalS) == 5); diff --git a/gcc/testsuite/gdc.test/compilable/test13281.d b/gcc/testsuite/gdc.test/compilable/test13281.d index 0d747fa..ab92fcc 100644 --- a/gcc/testsuite/gdc.test/compilable/test13281.d +++ b/gcc/testsuite/gdc.test/compilable/test13281.d @@ -36,12 +36,27 @@ static assert((123 ).stringof == "123"); static assert((123u ).stringof == "123u"); static assert((123L ).stringof == "123L"); static assert((123uL).stringof == "123LU"); -static assert((123.5 ).stringof == "1.235e+2"); -static assert((123.5f ).stringof == "1.235e+2F"); -static assert((123.5L ).stringof == "1.235e+2L"); -static assert((123.5i ).stringof == "1.235e+2i"); -static assert((123.5fi).stringof == "1.235e+2Fi"); -static assert((123.5Li).stringof == "1.235e+2Li"); -static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); -static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); -static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); +version (GNU) +{ + static assert((123.5 ).stringof == "1.235e+2"); + static assert((123.5f ).stringof == "1.235e+2F"); + static assert((123.5L ).stringof == "1.235e+2L"); + static assert((123.5i ).stringof == "1.235e+2i"); + static assert((123.5fi).stringof == "1.235e+2Fi"); + static assert((123.5Li).stringof == "1.235e+2Li"); + static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); + static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); + static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); +} +else +{ + static assert((123.5 ).stringof == "123.5"); + static assert((123.5f ).stringof == "123.5F"); + static assert((123.5L ).stringof == "123.5L"); + static assert((123.5i ).stringof == "123.5i"); + static assert((123.5fi).stringof == "123.5Fi"); + static assert((123.5Li).stringof == "123.5Li"); + static assert((123.5 +5.5i ).stringof == "123.5 + 5.5i"); + static assert((123.5f+5.5fi).stringof == "123.5F + 5.5Fi"); + static assert((123.5L+5.5Li).stringof == "123.5L + 5.5Li"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test24338.d b/gcc/testsuite/gdc.test/compilable/test24338.d new file mode 100644 index 0000000..467b8bd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test24338.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=24338 + +enum Foo: char[4] +{ + elem = "test" +} + +immutable a = [Foo.elem]; +immutable b = [Foo.elem]; +immutable c = a ~ b; diff --git a/gcc/testsuite/gdc.test/compilable/test9565.d b/gcc/testsuite/gdc.test/compilable/test9565.d deleted file mode 100644 index 9e3ee6a..0000000 --- a/gcc/testsuite/gdc.test/compilable/test9565.d +++ /dev/null @@ -1,86 +0,0 @@ -// REQUIRED_ARGS: -o- -// PERMUTE_ARGS: - -template TypeTuple(T...) { alias TypeTuple = T; } - -bool startsWith(string s, string m) { return s[0 .. m.length] == m; } - -void main() -{ - enum string castPrefix = "cast(" ~ size_t.stringof ~ ")"; - - // TypeSArray - static assert((int[10]).stringof == "int[10]", T.stringof); - - int[] arr; - - // IndexExp - { - // index == IntegerExp - static assert((arr[ 4 ]).stringof == "arr[4]"); - static assert((arr[ 4U ]).stringof == "arr[4]"); - static assert((arr[ 4L ]).stringof == "arr[4]"); - static assert((arr[ 4LU]).stringof == "arr[4]"); - - // index == UAddExp - static assert((arr[+4 ]).stringof == "arr[4]"); - static assert((arr[+4U ]).stringof == "arr[4]"); - static assert((arr[+4L ]).stringof == "arr[4]"); - static assert((arr[+4LU]).stringof == "arr[4]"); - - // index == NegExp - static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]"); - static assert((arr[-4U ]).stringof == "arr[4294967292]"); - static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]"); - static if (is(size_t == ulong)) - { - static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]"); - static assert((arr[-4LU]).stringof == "arr[-4LU]"); - - // IntegerLiteral needs suffix if the value is greater than long.max - static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]"); - static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]"); - } - - foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong)) - { - enum Int p4 = +4; - enum string result1 = (arr[p4]).stringof; - static assert(result1 == "arr[4]"); - - enum string result2 = (arr[cast(Int)+4]).stringof; - static assert(result2 == "arr[4]"); - } - foreach (Int; TypeTuple!(byte, short, int, long)) - { - // keep "cast(Type)" in the string representation - - enum Int m4 = -4; - static if (is(typeof({ size_t x = m4; }))) - { - enum string result1 = (arr[m4]).stringof; - static assert(result1.startsWith("arr[" ~ castPrefix)); - } - else - static assert(!__traits(compiles, arr[m4])); - - enum string result2 = (arr[cast(Int)-4]).stringof; - static assert(result2.startsWith("arr[" ~ castPrefix)); - } - } - - // SliceExp - { - // lwr,upr == IntegerExp - static assert((arr[4 .. 8 ]).stringof == "arr[4..8]"); - static assert((arr[4U .. 8U ]).stringof == "arr[4..8]"); - static assert((arr[4L .. 8L ]).stringof == "arr[4..8]"); - static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]"); - - // lwr,upr == UAddExp - static assert((arr[+4 .. +8 ]).stringof == "arr[4..8]"); - static assert((arr[+4U .. +8U ]).stringof == "arr[4..8]"); - static assert((arr[+4L .. +8L ]).stringof == "arr[4..8]"); - static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]"); - } -} diff --git a/gcc/testsuite/gdc.test/compilable/testdefines.d b/gcc/testsuite/gdc.test/compilable/testdefines.d index 4507266..9dd8cf2 100644 --- a/gcc/testsuite/gdc.test/compilable/testdefines.d +++ b/gcc/testsuite/gdc.test/compilable/testdefines.d @@ -12,3 +12,6 @@ static assert(F64 == 8.0); static assert(F80 == 9.0L); static assert(SSS == "hello"); + +static assert(ABC == 12); +static assert(DEF == 17); diff --git a/gcc/testsuite/gdc.test/fail_compilation/array_bool.d b/gcc/testsuite/gdc.test/fail_compilation/array_bool.d new file mode 100644 index 0000000..923766a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/array_bool.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/array_bool.d(13): Deprecation: assert condition cannot be a string literal +fail_compilation/array_bool.d(13): If intentional, use `"foo" !is null` instead to preserve behaviour +fail_compilation/array_bool.d(14): Deprecation: static assert condition cannot be a string literal +fail_compilation/array_bool.d(14): If intentional, use `"foo" !is null` instead to preserve behaviour +--- +*/ +void main() +{ + assert("foo"); + static assert("foo"); + + assert("foo".ptr); // OK + static assert("foo".ptr); // OK + + enum e = "bar"; + static assert(e); // OK + assert(e); // OK +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19523.d b/gcc/testsuite/gdc.test/fail_compilation/b19523.d index 3626666..d2a05c7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b19523.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b19523.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/b19523.d(12): Error: undefined identifier `SomeStruct` -fail_compilation/b19523.d(13): Error: function `b19523.foo(int delegate() arg)` is not callable using argument types `(_error_)` -fail_compilation/b19523.d(13): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg` ---- +---- +fail_compilation/b19523.d(13): Error: undefined identifier `SomeStruct` +fail_compilation/b19523.d(14): Error: function `foo` is not callable using argument types `(_error_)` +fail_compilation/b19523.d(14): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg` +fail_compilation/b19523.d(19): `b19523.foo(int delegate() arg)` declared here +---- */ module b19523; diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d index 3ddcdaa..50ef6af 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d @@ -1,16 +1,19 @@ /* TEST_OUTPUT: --- -fail_compilation/b20011.d(25): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue -fail_compilation/b20011.d(28): Error: cannot modify expression `S2(null).member` because it is not an lvalue -fail_compilation/b20011.d(29): Error: cannot modify expression `S2(null).member` because it is not an lvalue -fail_compilation/b20011.d(32): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue -fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(37): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` -fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(38): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p` -fail_compilation/b20011.d(39): Error: function `b20011.main.assignableByConstRef(ref const(ubyte) p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(39): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p` +fail_compilation/b20011.d(28): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue +fail_compilation/b20011.d(31): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(32): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(35): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue +fail_compilation/b20011.d(40): Error: function `assignableByRef` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(40): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` +fail_compilation/b20011.d(37): `b20011.main.assignableByRef(ref ubyte p)` declared here +fail_compilation/b20011.d(41): Error: function `assignableByOut` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(41): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p` +fail_compilation/b20011.d(38): `b20011.main.assignableByOut(out ubyte p)` declared here +fail_compilation/b20011.d(42): Error: function `assignableByConstRef` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(42): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p` +fail_compilation/b20011.d(39): `b20011.main.assignableByConstRef(ref const(ubyte) p)` declared here --- */ module b20011; diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d index 5b16f72..ac167f3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d @@ -1,10 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` -fail_compilation/bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` -fail_compilation/bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` -fail_compilation/bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` +fail_compilation/bug15613.d(18): Error: function `f` is not callable using argument types `(typeof(null))` +fail_compilation/bug15613.d(18): cannot pass argument `null` of type `typeof(null)` to parameter `int...` +fail_compilation/bug15613.d(13): `bug15613.f(int...)` declared here +fail_compilation/bug15613.d(19): Error: function `g` is not callable using argument types `(int)` +fail_compilation/bug15613.d(19): cannot pass argument `8` of type `int` to parameter `Object` +fail_compilation/bug15613.d(14): `bug15613.g(Object, ...)` declared here --- */ @@ -20,8 +22,9 @@ void main() /* TEST_OUTPUT: --- -fail_compilation/bug15613.d(32): Error: function `bug15613.h(int[]...)` is not callable using argument types `(int, void function(int[]...))` -fail_compilation/bug15613.d(32): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` +fail_compilation/bug15613.d(35): Error: function `h` is not callable using argument types `(int, void function(int[]...))` +fail_compilation/bug15613.d(35): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` +fail_compilation/bug15613.d(31): `bug15613.h(int[]...)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d index ca98797..608e347 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d @@ -10,9 +10,11 @@ void g() /* TEST_OUTPUT: --- -fail_compilation/bug16165.d(6): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(Object, Object, int)` +fail_compilation/bug16165.d(6): Error: function `f` is not callable using argument types `(Object, Object, int)` fail_compilation/bug16165.d(6): cannot pass argument `o` of type `object.Object` to parameter `int x` -fail_compilation/bug16165.d(7): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(int, int, int)` +fail_compilation/bug16165.d(1): `bug16165.f(int x, Object y)` declared here +fail_compilation/bug16165.d(7): Error: function `f` is not callable using argument types `(int, int, int)` fail_compilation/bug16165.d(7): cannot pass argument `6` of type `int` to parameter `Object y` +fail_compilation/bug16165.d(1): `bug16165.f(int x, Object y)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d index f0a9456..13974aa 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d @@ -62,12 +62,13 @@ void test3() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argument types `(int, S)` -fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` -fail_compilation/bug9631.d(80): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` -fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` +fail_compilation/bug9631.d(80): Error: function `f` is not callable using argument types `(int, S)` +fail_compilation/bug9631.d(80): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` +fail_compilation/bug9631.d(79): `bug9631.arg.f(int i, S s)` declared here +fail_compilation/bug9631.d(81): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(81): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` +fail_compilation/bug9631.d(87): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(87): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` --- */ void arg() @@ -89,12 +90,13 @@ void arg() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S __param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` -fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` is not callable using argument types `!()(S)` -fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)` -fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` is not callable using argument types `!()(S, int)` -fail_compilation/bug9631.d(108): Candidate is: `ft2(T)(S, T)` +fail_compilation/bug9631.d(108): Error: function `ft` is not callable using argument types `(S)` +fail_compilation/bug9631.d(108): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` +fail_compilation/bug9631.d(107): `bug9631.targ.ft!().ft(S __param_0)` declared here +fail_compilation/bug9631.d(109): Error: template `ft` is not callable using argument types `!()(S)` +fail_compilation/bug9631.d(107): Candidate is: `ft()(tem!().S)` +fail_compilation/bug9631.d(111): Error: template `ft2` is not callable using argument types `!()(S, int)` +fail_compilation/bug9631.d(110): Candidate is: `ft2(T)(S, T)` --- */ void targ() diff --git a/gcc/testsuite/gdc.test/fail_compilation/callconst.d b/gcc/testsuite/gdc.test/fail_compilation/callconst.d index 74c1902..a3aee7c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/callconst.d +++ b/gcc/testsuite/gdc.test/fail_compilation/callconst.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/callconst.d(13): Error: function `callconst.func(ref X)` is not callable using argument types `(const(X))` -fail_compilation/callconst.d(13): cannot pass argument `x` of type `const(X)` to parameter `ref X` +fail_compilation/callconst.d(14): Error: function `func` is not callable using argument types `(const(X))` +fail_compilation/callconst.d(14): cannot pass argument `x` of type `const(X)` to parameter `ref X` +fail_compilation/callconst.d(17): `callconst.func(ref X)` declared here --- */ struct X {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d index a3ad34a..4c31e9e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d @@ -2,12 +2,12 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.f` is not callable using argument types `!()(int)` +fail_compilation/constraints_aggr.d(32): Error: template `f` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(60): Candidate is: `f(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_aggr.d(33): Error: template `imports.constraints.C.g` is not callable using argument types `!()()` +fail_compilation/constraints_aggr.d(33): Error: template `g` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(63): Candidate is: `g(this T)()` with `T = imports.constraints.C` must satisfy the following constraint: diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d index fbb4aa9..d15d281 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d @@ -2,72 +2,72 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test1` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(79): Error: template `test1` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test2` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(80): Error: template `test2` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(10): Candidate is: `test2(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test3` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(81): Error: template `test3` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(11): Candidate is: `test3(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test4` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(82): Error: template `test4` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(12): Candidate is: `test4(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test5` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(83): Error: template `test5` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(13): Candidate is: `test5(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test6` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(84): Error: template `test6` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(14): Candidate is: `test6(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T !P!T` -fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test7` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(85): Error: template `test7` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(15): Candidate is: `test7(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test8` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(86): Error: template `test8` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(16): Candidate is: `test8(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test9` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(87): Error: template `test9` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(17): Candidate is: `test9(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test10` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(88): Error: template `test10` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(18): Candidate is: `test10(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test11` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(89): Error: template `test11` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(19): Candidate is: `test11(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func1.d(90): Error: template `imports.constraints.test12` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(90): Error: template `test12` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(20): Candidate is: `test12(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(92): Error: template `imports.constraints.test1` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func1.d(92): Error: template `test1` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d index 4b8ebd5..36fa554 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d @@ -2,83 +2,83 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test13` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(94): Error: template `test13` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(23): Candidate is: `test13(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test14` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(95): Error: template `test14` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(24): Candidate is: `test14(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T` -fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test15` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(96): Error: template `test15` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(25): Candidate is: `test15(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test16` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(97): Error: template `test16` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(26): Candidate is: `test16(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test17` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(98): Error: template `test17` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(27): Candidate is: `test17(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test18` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(99): Error: template `test18` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(28): Candidate is: `test18(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test19` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(100): Error: template `test19` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(29): Candidate is: `test19(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T N!T` -fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test20` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(101): Error: template `test20` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(30): Candidate is: `test20(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test21` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(102): Error: template `test21` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(31): Candidate is: `test21(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test22` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(103): Error: template `test22` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(32): Candidate is: `test22(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test23` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(104): Error: template `test23` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(33): Candidate is: `test23(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T !P!T` -fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test24` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(105): Error: template `test24` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(34): Candidate is: `test24(R)(R r)` with `R = int` must satisfy the following constraint: ` __traits(hasMember, R, "stuff")` -fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test25` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(106): Error: template `test25` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(35): Candidate is: `test25(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(107): Error: template `imports.constraints.test26` is not callable using argument types `!(float)(int)` +fail_compilation/constraints_func2.d(107): Error: template `test26` is not callable using argument types `!(float)(int)` fail_compilation/imports/constraints.d(36): Candidate is: `test26(T, U)(U u)` with `T = float, U = int` diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d index d16bdf0..b4bc3fe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d @@ -1,7 +1,7 @@ /* EXTRA_FILES: imports/constraints.d TEST_OUTPUT: ---- +---- fail_compilation/constraints_func3.d(53): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)` fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)` with `T = int` @@ -23,27 +23,27 @@ fail_compilation/imports/constraints.d(42): `overload(T, must satisfy one of the following constraints: ` N!T N!V` -fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` +fail_compilation/constraints_func3.d(56): Error: template `variadic` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` -fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` +fail_compilation/constraints_func3.d(57): Error: template `variadic` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = ()` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func3.d(58): Error: template `variadic` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int)` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(59): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func3.d(59): Error: template `variadic` is not callable using argument types `!()(int, int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int, int)` must satisfy the following constraint: ` N!int` ---- +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d index c4dea0e..536a3d4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/constraints.d REQUIRED_ARGS: -verrors=context TEST_OUTPUT: ---- +---- fail_compilation/constraints_func4.d(90): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)` overload(0); ^ @@ -44,13 +44,13 @@ fail_compilation/imports/constraints.d(42): `overload(T, N!V` void overload(T, V)(T v1, V v2) if (N!T || N!V); ^ -fail_compilation/constraints_func4.d(93): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` +fail_compilation/constraints_func4.d(93): Error: template `variadic` is not callable using argument types `!()()` variadic(); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(94): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` +fail_compilation/constraints_func4.d(94): Error: template `variadic` is not callable using argument types `!()(int)` variadic(0); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -60,7 +60,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(95): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func4.d(95): Error: template `variadic` is not callable using argument types `!()(int, int)` variadic(0, 1); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -70,7 +70,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(96): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func4.d(96): Error: template `variadic` is not callable using argument types `!()(int, int, int)` variadic(0, 1, 2); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -80,7 +80,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ ---- +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d index f8edc5c..dfcddaa 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11425.d(13): Error: variable `x` is shadowing variable `diag11425.main.x` +fail_compilation/diag11425.d(14): Error: variable `x` is shadowing variable `diag11425.main.x` +fail_compilation/diag11425.d(11): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d index 25e0515..9248e09 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)` -fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` is not callable using argument types `!()()` +fail_compilation/diag13942.d(26): Error: template `to` is not callable using argument types `!()()` fail_compilation/diag13942.d(17): Candidate is: `to(A...)(A args)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d index fc8f660..7e2efd2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`? fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` -fail_compilation/diag16977.d(27): Error: template `diag16977.templ` is not callable using argument types `!()(int)` +fail_compilation/diag16977.d(27): Error: template `templ` is not callable using argument types `!()(int)` fail_compilation/diag16977.d(20): Candidate is: `templ(S)(S s)` with `S = int` must satisfy the following constraint: diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d index 053626a..0653490 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag20268.d(12): Error: template `diag20268.__lambda4` is not callable using argument types `!()(int)` +fail_compilation/diag20268.d(12): Error: template `__lambda4` is not callable using argument types `!()(int)` fail_compilation/diag20268.d(11): Candidate is: `__lambda4(__T1, __T2)(x, y)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d index a530eb6..c21226f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d @@ -2,10 +2,10 @@ TEST_OUTPUT: --- fail_compilation/diag23355.d(1): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: template `diag23355.ffi1` is not callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `ffi1` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(1): Candidate is: `ffi1(T)(T[n] s)` fail_compilation/diag23355.d(2): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: template `diag23355.ffi2` is not callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `ffi2` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(2): Candidate is: `ffi2()(T[n] s)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d index 4c8dfe8..0d19620 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d @@ -1,32 +1,33 @@ /* TEST_OUTPUT: --- -fail_compilation/diag8101.d(61): Error: function `diag8101.f_0(int)` is not callable using argument types `()` -fail_compilation/diag8101.d(61): too few arguments, expected 1, got 0 -fail_compilation/diag8101.d(62): Error: none of the overloads of `f_1` are callable using argument types `()` -fail_compilation/diag8101.d(35): Candidates are: `diag8101.f_1(int)` -fail_compilation/diag8101.d(36): `diag8101.f_1(int, int)` -fail_compilation/diag8101.d(63): Error: none of the overloads of `f_2` are callable using argument types `()` -fail_compilation/diag8101.d(38): Candidates are: `diag8101.f_2(int)` -fail_compilation/diag8101.d(39): `diag8101.f_2(int, int)` -fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int)` -fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int, int)` -fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int, int)` -fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int, int)` -fail_compilation/diag8101.d(63): ... (1 more, -v to show) ... -fail_compilation/diag8101.d(65): Error: template `diag8101.t_0` is not callable using argument types `!()()` -fail_compilation/diag8101.d(46): Candidate is: `t_0(T1)()` -fail_compilation/diag8101.d(66): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` -fail_compilation/diag8101.d(48): Candidates are: `t_1(T1)()` -fail_compilation/diag8101.d(49): `t_1(T1, T2)()` -fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` -fail_compilation/diag8101.d(51): Candidates are: `t_2(T1)()` -fail_compilation/diag8101.d(52): `t_2(T1, T2)()` -fail_compilation/diag8101.d(53): `t_2(T1, T2, T3)()` -fail_compilation/diag8101.d(54): `t_2(T1, T2, T3, T4)()` -fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4, T5)()` -fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5, T6)()` -fail_compilation/diag8101.d(67): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(62): Error: function `f_0` is not callable using argument types `()` +fail_compilation/diag8101.d(62): too few arguments, expected 1, got 0 +fail_compilation/diag8101.d(34): `diag8101.f_0(int)` declared here +fail_compilation/diag8101.d(63): Error: none of the overloads of `f_1` are callable using argument types `()` +fail_compilation/diag8101.d(36): Candidates are: `diag8101.f_1(int)` +fail_compilation/diag8101.d(37): `diag8101.f_1(int, int)` +fail_compilation/diag8101.d(64): Error: none of the overloads of `f_2` are callable using argument types `()` +fail_compilation/diag8101.d(39): Candidates are: `diag8101.f_2(int)` +fail_compilation/diag8101.d(40): `diag8101.f_2(int, int)` +fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int)` +fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int)` +fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int)` +fail_compilation/diag8101.d(44): `diag8101.f_2(int, int, int, int, int, int)` +fail_compilation/diag8101.d(64): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(66): Error: template `t_0` is not callable using argument types `!()()` +fail_compilation/diag8101.d(47): Candidate is: `t_0(T1)()` +fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` +fail_compilation/diag8101.d(49): Candidates are: `t_1(T1)()` +fail_compilation/diag8101.d(50): `t_1(T1, T2)()` +fail_compilation/diag8101.d(68): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` +fail_compilation/diag8101.d(52): Candidates are: `t_2(T1)()` +fail_compilation/diag8101.d(53): `t_2(T1, T2)()` +fail_compilation/diag8101.d(54): `t_2(T1, T2, T3)()` +fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4)()` +fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5)()` +fail_compilation/diag8101.d(57): `t_2(T1, T2, T3, T4, T5, T6)()` +fail_compilation/diag8101.d(68): ... (1 more, -v to show) ... --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d index e48f569..8066d6e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d @@ -2,13 +2,13 @@ TEST_OUTPUT: --- fail_compilation/diag8648.d(18): Error: undefined identifier `X` -fail_compilation/diag8648.d(29): Error: template `diag8648.foo` is not callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(29): Error: template `foo` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(18): Candidate is: `foo(T, n)(X!(T, n))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(31): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(31): Error: template `bar` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(32): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, f))` +fail_compilation/diag8648.d(32): Error: template `bar` is not callable using argument types `!()(Foo!(int, f))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d index 30589bf..4c63bb2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9004.d(21): Error: template `diag9004.bar` is not callable using argument types `!()(Foo!int, int)` +fail_compilation/diag9004.d(21): Error: template `bar` is not callable using argument types `!()(Foo!int, int)` fail_compilation/diag9004.d(14): Candidate is: `bar(FooT)(FooT foo, FooT.T x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diagin.d b/gcc/testsuite/gdc.test/fail_compilation/diagin.d index 1748e92..6e8a472 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diagin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diagin.d @@ -1,11 +1,12 @@ /* -PERMUTE_ARGS: -preview=in +REQUIRED_ARGS: -preview=in TEST_OUTPUT: --- -fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()` -fail_compilation/diagin.d(14): too few arguments, expected 1, got 0 -fail_compilation/diagin.d(16): Error: template `diagin.foo1` is not callable using argument types `!()(bool[])` -fail_compilation/diagin.d(20): Candidate is: `foo1(T)(in T v, string)` +fail_compilation/diagin.d(15): Error: function `foo` is not callable using argument types `()` +fail_compilation/diagin.d(15): too few arguments, expected 1, got 0 +fail_compilation/diagin.d(20): `diagin.foo(in int)` declared here +fail_compilation/diagin.d(17): Error: template `foo1` is not callable using argument types `!()(bool[])` +fail_compilation/diagin.d(21): Candidate is: `foo1(T)(in T v, string)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/discard_value.d b/gcc/testsuite/gdc.test/fail_compilation/discard_value.d new file mode 100644 index 0000000..7fe30a6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/discard_value.d @@ -0,0 +1,34 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/discard_value.d(24): Error: the result of the equality expression `3 is 3` is discarded +fail_compilation/discard_value.d(25): Error: the result of the equality expression `null !is null` is discarded +fail_compilation/discard_value.d(26): Error: the result of the equality expression `v == 0` is discarded +fail_compilation/discard_value.d(27): Error: the result of the equality expression `v == 0` is discarded +fail_compilation/discard_value.d(28): Error: `!__equals("", "")` has no effect +fail_compilation/discard_value.d(29): Error: the result of the equality expression `"" == ""` is discarded +fail_compilation/discard_value.d(30): Error: the result of the equality expression `fun().i == 4` is discarded +fail_compilation/discard_value.d(30): note that `fun().i` may have a side effect +fail_compilation/discard_value.d(33): Error: the result of the equality expression `slice == slice[0..0]` is discarded +--- +*/ + +struct S { int i; } + +S fun() { return S(42); } + +int v; + +void main() +{ + 3 is 3; + null !is null; + true && v == 0; + true || v == 0; + "" != ""; + "" == ""; // https://issues.dlang.org/show_bug.cgi?id=24359 + fun().i == 4; // https://issues.dlang.org/show_bug.cgi?id=12390 + + int[] slice = [0, 1]; + slice == slice[0 .. 0]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail110.d b/gcc/testsuite/gdc.test/fail_compilation/fail110.d index a13922b..4ba2a8c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail110.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail110.d @@ -1,9 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/fail110.d(16): Error: variable `i` is shadowing variable `fail110.main.i` -fail_compilation/fail110.d(17): Error: variable `i` is shadowing variable `fail110.main.i` -fail_compilation/fail110.d(18): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(19): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here +fail_compilation/fail110.d(20): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here +fail_compilation/fail110.d(21): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d deleted file mode 100644 index 5c852a1..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail12390.d(15): Error: the result of the equality expression `fun().i == 4` is discarded -fail_compilation/fail12390.d(15): note that `fun().i` may have a side effect ---- -*/ - -struct S { int i; } - -S fun() { return S(42); } - -void main() -{ - fun().i == 4; -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d index 711e57f..3b1ab72 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d @@ -14,10 +14,10 @@ fail_compilation/fail12744.d(61): Error: template instance `fail12744.bar12744L! fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `out` fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out` -fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744O)(int)` +fail_compilation/fail12744.d(67): Error: template `bar12744A` is not callable using argument types `!(foo12744O)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy` -fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744L)(int)` +fail_compilation/fail12744.d(68): Error: template `bar12744A` is not callable using argument types `!(foo12744L)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d index 3bc8653..3fa42e6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail136.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation\fail136.d(10): Error: `"\xef\xbb\xbf"` has no effect +fail_compilation/fail136.d(10): Error: `x"EFBBBF"` has no effect --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d index 45fe146..2c2661f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d @@ -4,7 +4,7 @@ TEST_OUTPUT: fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters -fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` is not callable using argument types `!()(int)` +fail_compilation/fail14669.d(17): Error: template `foo2` is not callable using argument types `!()(int)` fail_compilation/fail14669.d(12): Candidate is: `foo2()(auto int a)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail162.d b/gcc/testsuite/gdc.test/fail_compilation/fail162.d index c79f8d8..600e2c9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail162.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail162.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail162.d(25): Error: template `fail162.testHelper` is not callable using argument types `!()(string, string)` +fail_compilation/fail162.d(25): Error: template `testHelper` is not callable using argument types `!()(string, string)` fail_compilation/fail162.d(10): Candidate is: `testHelper(A...)()` fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d index d4da116..2e8e4e6a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d @@ -1,7 +1,7 @@ -/* +/* REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890a.d(8): Error: `void[cast(size_t)4294967295]` size 1 * 4294967295 exceeds 0x7fffffff size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d index f4a5dad..f9cfb45 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d @@ -1,7 +1,7 @@ -/* +/* REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890b.d(8): Error: `void[cast(size_t)4294967294]` size 1 * 4294967294 exceeds 0x7fffffff size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d index ae67443..9c23b78 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d @@ -3,8 +3,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19948.d(15): Error: function `fail19948.func(const(X))` is not callable using argument types `(X)` -fail_compilation/fail19948.d(15): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +fail_compilation/fail19948.d(16): Error: function `func` is not callable using argument types `(X)` +fail_compilation/fail19948.d(16): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +fail_compilation/fail19948.d(19): `fail19948.func(const(X))` declared here --- */ // DISABLED: win32 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d index 8a08844..f04db02 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d @@ -1,8 +1,9 @@ /* REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/fail20183.d(1016): Error: function `fail20183.addr(return ref int b)` is not callable using argument types `(int)` +fail_compilation/fail20183.d(1016): Error: function `addr` is not callable using argument types `(int)` fail_compilation/fail20183.d(1016): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b` +fail_compilation/fail20183.d(1005): `fail20183.addr(return ref int b)` declared here fail_compilation/fail20183.d(1017): Error: address of struct temporary returned by `s()` assigned to longer lived variable `q` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d index d36bb0b..7269f42 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d @@ -3,7 +3,7 @@ REQUIRED_ARGS: -verrors=spec -o- TEST_OUTPUT: --- (spec:1) fail_compilation/fail20730b.d-mixin-43(43): Error: C style cast illegal, use `cast(int)mod` -fail_compilation/fail20730b.d(26): Error: template `fail20730b.atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` +fail_compilation/fail20730b.d(26): Error: template `atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` fail_compilation/fail20730b.d(41): Candidate is: `atomicOp(string op, T, V1)(shared ref T val, V1 mod)` with `op = "+=", T = uint, diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d index 026b7c2..4464222 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d @@ -2,10 +2,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail20800.d(22): Error: function `fail20800.fun(int a)` is not callable using argument types `(string)` -fail_compilation/fail20800.d(22): cannot pass argument `(m()).index()` of type `string` to parameter `int a` ---- +---- +fail_compilation/fail20800.d(23): Error: function `fun` is not callable using argument types `(string)` +fail_compilation/fail20800.d(23): cannot pass argument `(m()).index()` of type `string` to parameter `int a` +fail_compilation/fail20800.d(19): `fail20800.fun(int a)` declared here +---- */ struct RegexMatch diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2195.d b/gcc/testsuite/gdc.test/fail_compilation/fail2195.d index 0eff066..6f6cd53 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail2195.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2195.d @@ -3,7 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail2195.d(16): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable`. Rename the `foreach` variable. +fail_compilation/fail2195.d(17): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable` +fail_compilation/fail2195.d(14): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d index d865fd9..9fb5165 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d @@ -3,8 +3,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy __param_0)` is not callable using argument types `(SystemCopy)` -fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(22): Error: function `fun` is not callable using argument types `(SystemCopy)` +fail_compilation/fail22202.d(22): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(17): `fail22202.fun(SystemCopy __param_0)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail236.d b/gcc/testsuite/gdc.test/fail_compilation/fail236.d index accc0e1..96f0ae6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail236.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail236.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail236.d(14): Error: undefined identifier `x` -fail_compilation/fail236.d(22): Error: template `fail236.Templ2` is not callable using argument types `!()(int)` +fail_compilation/fail236.d(22): Error: template `Templ2` is not callable using argument types `!()(int)` fail_compilation/fail236.d(12): Candidate is: `Templ2(alias a)(x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24301.d b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d new file mode 100644 index 0000000..6ddece6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d @@ -0,0 +1,20 @@ +/+ +TEST_OUTPUT: +--- +fail_compilation/fail24301.d(19): Error: function `fun` is not callable using argument types `(S)` +fail_compilation/fail24301.d(19): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +fail_compilation/fail24301.d(14): `fail24301.fun(S __param_0)` declared here +--- ++/ +struct S +{ + @disable this(ref S); +} + +@safe void fun(S) {} + +@safe void main() +{ + S s; + fun(s); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail263.d b/gcc/testsuite/gdc.test/fail_compilation/fail263.d index 0fa2f86..e57fc50 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail263.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail263.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail263.d(19): Error: function `fail263.f(byte* p)` is not callable using argument types `(const(byte)*)` -fail_compilation/fail263.d(19): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` ---- +---- +fail_compilation/fail263.d(20): Error: function `f` is not callable using argument types `(const(byte)*)` +fail_compilation/fail263.d(20): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` +fail_compilation/fail263.d(14): `fail263.f(byte* p)` declared here +---- */ // https://issues.dlang.org/show_bug.cgi?id=2766 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail322.d b/gcc/testsuite/gdc.test/fail_compilation/fail322.d index 491111f..faaab68 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail322.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail322.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail322.d(13): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` -fail_compilation/fail322.d(13): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` -fail_compilation/fail322.d(15): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(const(char[16]))` -fail_compilation/fail322.d(15): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` ---- +---- +fail_compilation/fail322.d(15): Error: function `digestToString2` is not callable using argument types `(string)` +fail_compilation/fail322.d(15): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` +fail_compilation/fail322.d(20): `fail322.digestToString2(ref char[16] digest)` declared here +fail_compilation/fail322.d(17): Error: function `digestToString2` is not callable using argument types `(const(char[16]))` +fail_compilation/fail322.d(17): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` +fail_compilation/fail322.d(20): `fail322.digestToString2(ref char[16] digest)` declared here +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d index 77e8cd8..de20333 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d @@ -1,14 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/fail332.d(22): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `()` -fail_compilation/fail332.d(22): missing argument for parameter #1: `int __param_0` -fail_compilation/fail332.d(23): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` -fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(string)` -fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` -fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(int, typeof(null))` -fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` +fail_compilation/fail332.d(26): Error: function `foo` is not callable using argument types `()` +fail_compilation/fail332.d(26): missing argument for parameter #1: `int __param_0` +fail_compilation/fail332.d(21): `fail332.foo(int __param_0, ...)` declared here +fail_compilation/fail332.d(27): Error: function `foo` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(27): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` +fail_compilation/fail332.d(21): `fail332.foo(int __param_0, ...)` declared here +fail_compilation/fail332.d(29): Error: function `baz` is not callable using argument types `(string)` +fail_compilation/fail332.d(29): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` +fail_compilation/fail332.d(22): `fail332.baz(int[] __param_0...)` declared here +fail_compilation/fail332.d(30): Error: function `baz` is not callable using argument types `(int, typeof(null))` +fail_compilation/fail332.d(30): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` +fail_compilation/fail332.d(22): `fail332.baz(int[] __param_0...)` declared here --- */ @@ -29,18 +33,24 @@ void test() /* TEST_OUTPUT: --- -fail_compilation/fail332.d(50): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `()` -fail_compilation/fail332.d(50): missing argument for parameter #1: `Object` -fail_compilation/fail332.d(51): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(int)` -fail_compilation/fail332.d(51): cannot pass argument `4` of type `int` to parameter `Object` -fail_compilation/fail332.d(52): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(52): expected 2 variadic argument(s), not 0 -fail_compilation/fail332.d(53): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int)` -fail_compilation/fail332.d(53): expected 2 variadic argument(s), not 1 -fail_compilation/fail332.d(54): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int, string)` -fail_compilation/fail332.d(54): cannot pass argument `""` of type `string` to parameter `int[2]...` -fail_compilation/fail332.d(55): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int, int, int)` -fail_compilation/fail332.d(55): expected 2 variadic argument(s), not 3 +fail_compilation/fail332.d(60): Error: function `bar` is not callable using argument types `()` +fail_compilation/fail332.d(60): missing argument for parameter #1: `Object` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(61): Error: function `bar` is not callable using argument types `(int)` +fail_compilation/fail332.d(61): cannot pass argument `4` of type `int` to parameter `Object` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(62): Error: function `bar` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(62): expected 2 variadic argument(s), not 0 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(63): Error: function `bar` is not callable using argument types `(typeof(null), int)` +fail_compilation/fail332.d(63): expected 2 variadic argument(s), not 1 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(64): Error: function `bar` is not callable using argument types `(typeof(null), int, string)` +fail_compilation/fail332.d(64): cannot pass argument `""` of type `string` to parameter `int[2]...` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(65): Error: function `bar` is not callable using argument types `(typeof(null), int, int, int)` +fail_compilation/fail332.d(65): expected 2 variadic argument(s), not 3 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here --- */ void bar(Object, int[2]...); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d index 030c47c..259a6da 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d @@ -1,7 +1,7 @@ -/* +/* REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail4611.d(15): Error: `Vec[cast(size_t)2147483647]` size 4 * 2147483647 exceeds 0x7fffffff size limit for static array --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail58.d b/gcc/testsuite/gdc.test/fail_compilation/fail58.d index 89b2351..ae70da2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail58.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail58.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail58.d(26): Error: function `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` is not callable using argument types `(string, int)` -fail_compilation/fail58.d(26): cannot pass argument `"123"` of type `string` to parameter `dchar[] pText` -fail_compilation/fail58.d(30): Error: function `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` is not callable using argument types `(string, int)` -fail_compilation/fail58.d(30): cannot pass argument `""` of type `string` to parameter `dchar[] pText` ---- +---- +fail_compilation/fail58.d(28): Error: function `SomeFunc` is not callable using argument types `(string, int)` +fail_compilation/fail58.d(28): cannot pass argument `"123"` of type `string` to parameter `dchar[] pText` +fail_compilation/fail58.d(14): `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` declared here +fail_compilation/fail58.d(32): Error: function `SomeFunc` is not callable using argument types `(string, int)` +fail_compilation/fail58.d(32): cannot pass argument `""` of type `string` to parameter `dchar[] pText` +fail_compilation/fail58.d(14): `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` declared here +---- */ debug import std.stdio; const int anything = -1000; // Line #2 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d index a4844bf..f2abfcc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail8009.d(9): Error: template `fail8009.filter` is not callable using argument types `!()(void)` +fail_compilation/fail8009.d(9): Error: template `filter` is not callable using argument types `!()(void)` fail_compilation/fail8009.d(8): Candidate is: `filter(R)(scope bool delegate(ref BAD!R) func)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail93.d b/gcc/testsuite/gdc.test/fail_compilation/fail93.d index b9ad294..2989395 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail93.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail93.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail93.d(13): Error: variable `i` is shadowing variable `fail93.main.i` +fail_compilation/fail93.d(14): Error: variable `i` is shadowing variable `fail93.main.i` +fail_compilation/fail93.d(13): declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail95.d b/gcc/testsuite/gdc.test/fail_compilation/fail95.d index 7065bc1..0e61336 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail95.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail95.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail95.d(19): Error: template `fail95.A` is not callable using argument types `!()(int)` +fail_compilation/fail95.d(19): Error: template `A` is not callable using argument types `!()(int)` fail_compilation/fail95.d(11): Candidate is: `A(alias T)(T)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d index 3ab4db7..85a146c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269a.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d index 718fa94..e680721 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269b.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d index 1a93831..1fa1567 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269c.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d index bdfabae..3154ea5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269d.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d index d6eed62..4a5757c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269e.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d index b571059..db781e9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d index 348207e..4799fa1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d +++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269g.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -c -o- +// REQUIRED_ARGS: -c -o- /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d index de83db9..95b07e7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d +++ b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d @@ -1,18 +1,41 @@ -/**
-TEST_OUTPUT:
----
-fail_compilation\hexstring.d(16): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])`
-fail_compilation\hexstring.d(17): Error: cannot implicitly convert expression `"\x12?"c` of type `string` to `immutable(ubyte[])`
-fail_compilation\hexstring.d(18): Error: cannot implicitly convert expression `"\x12?"` of type `string` to `immutable(ubyte[])`
-fail_compilation\hexstring.d(15): Error: cannot implicitly convert expression `"\x12?"` of type `string` to `ubyte[]`
----
-*/
-immutable ubyte[] s0 = x"123F";
-static assert(s0[0] == 0x12);
-static assert(s0[1] == 0x3F);
-immutable byte[] s1 = x"123F";
-
-ubyte[] f1 = x"123F";
-immutable ubyte[] f2 = "123F";
-immutable ubyte[] f3 = x"123F"c;
-immutable ubyte[] f4 = cast(string) x"123F";
+/** +TEST_OUTPUT: +--- +fail_compilation/hexstring.d(29): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(33): Error: hex string length 1 must be a multiple of 2 to cast to `immutable(ushort[])` +fail_compilation/hexstring.d(34): Error: hex string length 3 must be a multiple of 4 to cast to `immutable(uint[])` +fail_compilation/hexstring.d(35): Error: hex string length 5 must be a multiple of 8 to cast to `immutable(ulong[])` +fail_compilation/hexstring.d(36): Error: array cast from `wstring` to `immutable(ulong[])` is not supported at compile time +fail_compilation/hexstring.d(36): perhaps remove postfix `w` from hex string +fail_compilation/hexstring.d(37): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(38): Error: array cast from `string` to `immutable(ushort[])` is not supported at compile time +fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string +fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5 +fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"44332211"d` of type `dstring` to `immutable(float[])` +fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` +--- +*/ + +immutable ubyte[] s0 = x"123F"; +static assert(s0[0] == 0x12); +static assert(s0[1] == 0x3F); +immutable byte[] s1 = x"123F"; + +enum E(X) = cast(X[]) x"AABBCCDD"; +static assert(E!int[0] == 0xAABBCCDD); + +ubyte[] f1 = x"123F"; +immutable ubyte[] f2 = "123F"; +immutable ubyte[] f3 = x"123F"c; +immutable ubyte[] f4 = cast(string) x"123F"; + +immutable ushort[] f5 = cast(immutable ushort[]) x"11"; +immutable uint[] f6 = cast(immutable uint[]) x"112233"; +immutable ulong[] f7 = cast(immutable ulong[]) x"1122334455"; +immutable ulong[] f8 = cast(immutable ulong[]) x"11223344"w; +immutable uint[] f9 = cast(immutable uint[]) "ABCD"; +immutable ushort[] f10 = cast(immutable ushort[]) (x"1122" ~ ""); +immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c; +immutable uint[] f12 = x"1122334455"d; +immutable float[] f13 = x"11223344"d; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10599.d b/gcc/testsuite/gdc.test/fail_compilation/ice10599.d index 6e9649c..378894d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10599.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10599.d @@ -1,4 +1,4 @@ -// https://issues.dlang.org/show_bug.cgi?id=10599 +// https://issues.dlang.org/show_bug.cgi?id=10599 // ICE(interpret.c) /* TEST_OUTPUT: diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d index e76d4ac..552a982 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(in uint n)` is not callable using argument types `()` -fail_compilation/ice10922.d(10): too few arguments, expected 1, got 0 +fail_compilation/ice10922.d(11): Error: function `__lambda4` is not callable using argument types `()` +fail_compilation/ice10922.d(11): too few arguments, expected 1, got 0 +fail_compilation/ice10922.d(10): `ice10922.__lambda4(in uint n)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d index 448e629..476c655 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: ---- +---- fail_compilation/ice11856_1.d(18): Error: no property `g` for `A()` of type `A` fail_compilation/ice11856_1.d(18): the following error occured while looking for a UFCS match -fail_compilation/ice11856_1.d(18): Error: template `ice11856_1.g` is not callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(18): Error: template `g` is not callable using argument types `!()(A)` fail_compilation/ice11856_1.d(16): Candidate is: `g(T)(T x)` with `T = A` must satisfy the following constraint: ` is(typeof(x.f()))` ---- +---- */ struct A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d index 2c45c8a..c1b1e38 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d @@ -1,12 +1,14 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice12501.d(31): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` -fail_compilation/ice12501.d(31): expected 1 argument(s), not 2 -fail_compilation/ice12501.d(31): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` -fail_compilation/ice12501.d(31): expected 1 argument(s), not 2 -fail_compilation/ice12501.d(45): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating ---- +---- +fail_compilation/ice12501.d(33): Error: function `foo` is not callable using argument types `(int, int)` +fail_compilation/ice12501.d(33): expected 1 argument(s), not 2 +fail_compilation/ice12501.d(40): `ice12501.foo(int value)` declared here +fail_compilation/ice12501.d(33): Error: function `foo` is not callable using argument types `(int, int)` +fail_compilation/ice12501.d(33): expected 1 argument(s), not 2 +fail_compilation/ice12501.d(40): `ice12501.foo(int value)` declared here +fail_compilation/ice12501.d(47): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating +---- */ struct Tuple(T...) diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d index 151bf17..4b12f8b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` -fail_compilation/ice14130.d(14): Error: template `ice14130.foo` is not callable using argument types `!()(int)` +fail_compilation/ice14130.d(14): Error: template `foo` is not callable using argument types `!()(int)` fail_compilation/ice14130.d(10): Candidate is: `foo(R, F = Undef)(R r, F s = 0)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d index 5d676cd..eeca1b3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: ---- +---- fail_compilation/ice14907.d(14): Error: struct `ice14907.S(int v = S)` recursive template expansion fail_compilation/ice14907.d(19): while looking for match for `S!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(20): while looking for match for `f!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion -fail_compilation/ice14907.d(21): Error: template `ice14907.f` is not callable using argument types `!()()` +fail_compilation/ice14907.d(21): Error: template `f` is not callable using argument types `!()()` fail_compilation/ice14907.d(15): Candidate is: `f(int v = f)()` ---- +---- */ struct S(int v = S) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d index e3b677e..99d2eee 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice14923.d(22): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` -fail_compilation/ice14923.d(22): cannot pass argument `b` of type `ice14923.A` to parameter `C a` -fail_compilation/ice14923.d(22): instantiated from here: `bar!((b) => parse(b))` ---- +---- +fail_compilation/ice14923.d(23): Error: function `parse` is not callable using argument types `(A)` +fail_compilation/ice14923.d(23): cannot pass argument `b` of type `ice14923.A` to parameter `C a` +fail_compilation/ice14923.d(21): `ice14923.parse(C a)` declared here +fail_compilation/ice14923.d(23): instantiated from here: `bar!((b) => parse(b))` +---- */ auto bar(alias fun)() diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d index 90cf03f..5cde816 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d @@ -1,10 +1,11 @@ /* https://issues.dlang.org/show_bug.cgi?id=23097 TEST_OUTPUT: --- -fail_compilation/ice23097.d(12): Error: undefined identifier `ICE` -fail_compilation/ice23097.d(27): Error: template instance `ice23097.ice23097!(S23097)` error instantiating -fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` is not callable using argument types `(S23097)` -fail_compilation/ice23097.d(27): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable +fail_compilation/ice23097.d(13): Error: undefined identifier `ICE` +fail_compilation/ice23097.d(28): Error: template instance `ice23097.ice23097!(S23097)` error instantiating +fail_compilation/ice23097.d(28): Error: function `ice23097` is not callable using argument types `(S23097)` +fail_compilation/ice23097.d(28): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable +fail_compilation/ice23097.d(11): `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` declared here --- */ auto ice23097(I)(I) diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d index 9355a0f..de9fe29 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d @@ -7,7 +7,7 @@ TEST_OUTPUT: --- fail_compilation/ice6538.d(23): Error: template instance `Sym!(super)` expression `super` is not a valid template value argument -fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` is not callable using argument types `!()()` +fail_compilation/ice6538.d(28): Error: template `foo` is not callable using argument types `!()()` fail_compilation/ice6538.d(23): Candidate is: `foo()()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d index c9ab014..1e87f0a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)` +fail_compilation/ice9284.d(14): Error: template `__ctor` is not callable using argument types `!()(int)` fail_compilation/ice9284.d(12): Candidate is: `this()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d index 456d3e12..662038c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` is not callable using argument types `()` -fail_compilation/ice9540.d(35): too few arguments, expected 1, got 0 -fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating ---- +---- +fail_compilation/ice9540.d(36): Error: function `dg` is not callable using argument types `()` +fail_compilation/ice9540.d(36): too few arguments, expected 1, got 0 +fail_compilation/ice9540.d(33): `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` declared here +fail_compilation/ice9540.d(27): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating +---- */ template Tuple(E...) { alias E Tuple; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d b/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d new file mode 100644 index 0000000..53c1450 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/iconv_interface_array.d(48): Error: function `testA` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(48): cannot pass argument `arr` of type `C[4]` to parameter `I1[4] arr` +fail_compilation/iconv_interface_array.d(27): `iconv_interface_array.testA(I1[4] arr)` declared here +fail_compilation/iconv_interface_array.d(49): Error: function `testB` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(49): cannot pass argument `arr` of type `C[4]` to parameter `I2[4] arr` +fail_compilation/iconv_interface_array.d(33): `iconv_interface_array.testB(I2[4] arr)` declared here +fail_compilation/iconv_interface_array.d(50): Error: function `testC` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(50): cannot pass argument `arr` of type `C[4]` to parameter `I3[4] arr` +fail_compilation/iconv_interface_array.d(39): `iconv_interface_array.testC(I3[4] arr)` declared here +--- +*/ + +interface I1 { int a(int); } +interface I2 { int b(int); } +interface I3 { int c(int); } + +class C : I1, I2, I3 +{ + int a(int i) { return 1 * i; } + int b(int i) { return 2 * i; } + int c(int i) { return 3 * i; } +} + +void testA(I1[4] arr) +{ + foreach (uint idx, obj; arr) + assert(obj.a(idx) == 1 * idx); +} + +void testB(I2[4] arr) +{ + foreach (idx, obj; arr) + assert(obj.b(cast(int) idx) == 2 * idx); +} + +void testC(I3[4] arr) +{ + foreach (idx, obj; arr) + assert(obj.c(cast(int) idx) == 3 * idx); +} + +void main() +{ + C[4] arr = [ new C, new C, new C, new C ]; + testA(arr); + testB(arr); + testC(arr); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d b/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d new file mode 100644 index 0000000..c915c44 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d @@ -0,0 +1,13 @@ +/* TEST_OUTPUT: +--- +fail_compilation/interpolatedexpressionsequence_postfix.d(10): Error: String postfixes on interpolated expression sequences are not allowed. +fail_compilation/interpolatedexpressionsequence_postfix.d(11): Error: String postfixes on interpolated expression sequences are not allowed. +fail_compilation/interpolatedexpressionsequence_postfix.d(12): Error: String postfixes on interpolated expression sequences are not allowed. +--- +*/ +void main() { + // all postfixes are banned + auto c = i"foo"c; + auto w = i"foo"w; + auto d = i"foo"d; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d index 5129f30..b634a11 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d +++ b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d @@ -1,22 +1,27 @@ /* TEST_OUTPUT: --- -fail_compilation/named_arguments_error.d(32): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(32): parameter `x` assigned twice -fail_compilation/named_arguments_error.d(33): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(33): argument `4` goes past end of parameter list -fail_compilation/named_arguments_error.d(34): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(34): parameter `y` assigned twice -fail_compilation/named_arguments_error.d(35): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(35): no parameter named `a` -fail_compilation/named_arguments_error.d(36): Error: function `named_arguments_error.g(int x, int y, int z = 3)` is not callable using argument types `(int, int)` -fail_compilation/named_arguments_error.d(36): missing argument for parameter #1: `int x` -fail_compilation/named_arguments_error.d(38): Error: no named argument `element` allowed for array dimension -fail_compilation/named_arguments_error.d(39): Error: no named argument `number` allowed for scalar -fail_compilation/named_arguments_error.d(40): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` -fail_compilation/named_arguments_error.d(41): Error: named arguments with Implicit Function Template Instantiation are not supported yet -fail_compilation/named_arguments_error.d(41): Error: template `named_arguments_error.tempfun` is not callable using argument types `!()(string, int)` -fail_compilation/named_arguments_error.d(45): Candidate is: `tempfun(T, U)(T t, U u)` +fail_compilation/named_arguments_error.d(37): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(37): parameter `x` assigned twice +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(38): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(38): argument `4` goes past end of parameter list +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(39): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(39): parameter `y` assigned twice +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(40): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(40): no parameter named `a` +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(41): Error: function `g` is not callable using argument types `(int, int)` +fail_compilation/named_arguments_error.d(41): missing argument for parameter #1: `int x` +fail_compilation/named_arguments_error.d(33): `named_arguments_error.g(int x, int y, int z = 3)` declared here +fail_compilation/named_arguments_error.d(43): Error: no named argument `element` allowed for array dimension +fail_compilation/named_arguments_error.d(44): Error: no named argument `number` allowed for scalar +fail_compilation/named_arguments_error.d(45): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` +fail_compilation/named_arguments_error.d(46): Error: named arguments with Implicit Function Template Instantiation are not supported yet +fail_compilation/named_arguments_error.d(46): Error: template `tempfun` is not callable using argument types `!()(string, int)` +fail_compilation/named_arguments_error.d(50): Candidate is: `tempfun(T, U)(T t, U u)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d index 5a4b5d9..d967ab5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d +++ b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d @@ -5,7 +5,6 @@ TEST_OUTPUT: --- fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2 fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2 -fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)` --- */ @@ -28,5 +27,5 @@ void test3() void test4() { - pragma(unrecognized, "string"); + pragma(unrecognized, "string"); // permitted, just ignored } diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d index d0e97c8..486dcd5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/previewin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d @@ -1,20 +1,23 @@ /* REQUIRED_ARGS: -preview=in -preview=dip1000 TEST_OUTPUT: ---- -fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` +---- +fail_compilation/previewin.d(4): Error: function `takeFunction` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here +fail_compilation/previewin.d(5): Error: function `takeFunction` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here +fail_compilation/previewin.d(6): Error: function `takeFunction` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `ref` variable `escape` with longer lifetime fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg` fail_compilation/previewin.d(22): perhaps annotate the parameter with `return` ---- +---- */ #line 1 diff --git a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d index fce4ab7..ca78050 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d +++ b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d @@ -4,10 +4,12 @@ fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument t fail_compilation/pull12941.d(101): `pull12941.foo(return ref scope int* p)` and: fail_compilation/pull12941.d(102): `pull12941.foo(return out scope int* p)` -fail_compilation/pull12941.d(111): Error: function `pull12941.bar(return scope int* p)` is not callable using argument types `(int)` +fail_compilation/pull12941.d(111): Error: function `bar` is not callable using argument types `(int)` fail_compilation/pull12941.d(111): cannot pass argument `1` of type `int` to parameter `return scope int* p` -fail_compilation/pull12941.d(112): Error: function `pull12941.abc(return ref int* p)` is not callable using argument types `(int)` +fail_compilation/pull12941.d(104): `pull12941.bar(return scope int* p)` declared here +fail_compilation/pull12941.d(112): Error: function `abc` is not callable using argument types `(int)` fail_compilation/pull12941.d(112): cannot pass rvalue argument `1` of type `int` to parameter `return ref int* p` +fail_compilation/pull12941.d(105): `pull12941.abc(return ref int* p)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d b/gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d new file mode 100644 index 0000000..cb36ed6 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/standalone_modctor.d @@ -0,0 +1,15 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/standalone_modctor.d(11): Error: `@standalone` can only be used on shared static constructors +fail_compilation/standalone_modctor.d(12): Error: a module constructor using `@standalone` must be `@system` or `@trusted` +fail_compilation/standalone_modctor.d(13): Error: a module constructor using `@standalone` must be `@system` or `@trusted` +--- +*/ +import core.attribute : standalone; + +@standalone static this() {} +@standalone shared static this() {} +@standalone shared static this() @safe {} +@standalone shared static this() @trusted {} +@standalone shared static this() @system {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d index 1305bc5..028f8e1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d +++ b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d @@ -2,13 +2,13 @@ REQUIRED_ARGS: -m64 TEST_OUTPUT: --- -fail_compilation/staticarrayoverflow.d(23): Error: static array `S[1879048192]` size overflowed to 7516192768000 +fail_compilation/staticarrayoverflow.d(23): Error: static array `S[cast(size_t)1879048192]` size overflowed to 7516192768000 fail_compilation/staticarrayoverflow.d(23): Error: variable `staticarrayoverflow.y` size overflow -fail_compilation/staticarrayoverflow.d(25): Error: static array `S[8070450532247928832]` size overflowed to 8070450532247928832 +fail_compilation/staticarrayoverflow.d(25): Error: static array `S[cast(size_t)8070450532247928832]` size overflowed to 8070450532247928832 fail_compilation/staticarrayoverflow.d(25): Error: variable `staticarrayoverflow.a` size overflow fail_compilation/staticarrayoverflow.d(26): Error: static array `S[0][18446744073709551615LU]` size overflowed to 18446744073709551615 fail_compilation/staticarrayoverflow.d(26): Error: variable `staticarrayoverflow.b` size overflow -fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][4294967295]` size overflowed to 4294967295 +fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][cast(size_t)4294967295]` size overflowed to 4294967295 fail_compilation/staticarrayoverflow.d(27): Error: variable `staticarrayoverflow.c` size overflow --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19107.d b/gcc/testsuite/gdc.test/fail_compilation/test19107.d index c802122..9a6e335 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19107.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19107.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/imp19661.d imports/test19107a.d imports/test19107b.d TEST_OUTPUT: --- -fail_compilation/test19107.d(24): Error: template `test19107.all` is not callable using argument types `!((c) => c)(string[])` +fail_compilation/test19107.d(24): Error: template `all` is not callable using argument types `!((c) => c)(string[])` fail_compilation/test19107.d(18): Candidate is: `all(alias pred, T)(T t)` with `pred = __lambda2, T = string[]` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19971.d b/gcc/testsuite/gdc.test/fail_compilation/test19971.d index f854362..3d46eeb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19971.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19971.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/test19971.d(15): Error: function `test19971.f(int x)` is not callable using argument types `(string)` -fail_compilation/test19971.d(15): cannot pass argument `"%s"` of type `string` to parameter `int x` -fail_compilation/test19971.d(16): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)` +fail_compilation/test19971.d(16): Error: function `f` is not callable using argument types `(string)` fail_compilation/test19971.d(16): cannot pass argument `"%s"` of type `string` to parameter `int x` +fail_compilation/test19971.d(13): `test19971.f(int x)` declared here +fail_compilation/test19971.d(17): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)` +fail_compilation/test19971.d(17): cannot pass argument `"%s"` of type `string` to parameter `int x` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21008.d b/gcc/testsuite/gdc.test/fail_compilation/test21008.d index 9949107..11cfc39 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21008.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21008.d @@ -4,13 +4,16 @@ TEST_OUTPUT: fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular reference to class `C` fail_compilation/test21008.d(117): Error: calling non-static function `toString` requires an instance of type `Object` fail_compilation/test21008.d(117): Error: calling non-static function `toHash` requires an instance of type `Object` -fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()` +fail_compilation/test21008.d(117): Error: function `opCmp` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 -fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()` +$p:druntime/import/object.d$($n$): `object.Object.opCmp(Object o)` declared here +fail_compilation/test21008.d(117): Error: function `opEquals` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 +$p:druntime/import/object.d$($n$): `object.Object.opEquals(Object o)` declared here fail_compilation/test21008.d(117): Error: `Monitor` has no effect -fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()` +fail_compilation/test21008.d(117): Error: function `factory` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 +$p:druntime/import/object.d$($n$): `object.Object.factory(string classname)` declared here fail_compilation/test21008.d(105): called from here: `handleMiddlewareAnnotation()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21025.d b/gcc/testsuite/gdc.test/fail_compilation/test21025.d index 8564199..6b2496a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21025.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21025.d @@ -6,7 +6,7 @@ TEST_OUTPUT: --- fail_compilation/test21025.d(15): Error: variable `r` cannot be read at compile time fail_compilation/test21025.d(15): called from here: `binaryFun(r, r)` -fail_compilation/test21025.d(24): Error: template `test21025.uniq` is not callable using argument types `!()(void[])` +fail_compilation/test21025.d(24): Error: template `uniq` is not callable using argument types `!()(void[])` fail_compilation/test21025.d(14): Candidate is: `uniq()(int[] r)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21807.d b/gcc/testsuite/gdc.test/fail_compilation/test21807.d index 9f56bf7..aaa56f9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21807.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21807.d @@ -27,8 +27,9 @@ class Foo /* TEST_OUTPUT: --- -fail_compilation/test21807.d(117): Error: function `test21807.addr(return ref int b)` is not callable using argument types `(int)` +fail_compilation/test21807.d(117): Error: function `addr` is not callable using argument types `(int)` fail_compilation/test21807.d(117): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b` +fail_compilation/test21807.d(106): `test21807.addr(return ref int b)` declared here --- */ #line 100 diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24295.d b/gcc/testsuite/gdc.test/fail_compilation/test24295.d new file mode 100644 index 0000000..58b6e92 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24295.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -betterC + +/* +TEST_OUTPUT: +--- +fail_compilation/test24295.d(12): Error: expression `new int[](1$?:32=u|64=LU$)` allocates with the GC and cannot be used with switch `-betterC` +--- +*/ + +void f() +{ + int[] overlaps = new int[1]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24365.d b/gcc/testsuite/gdc.test/fail_compilation/test24365.d new file mode 100644 index 0000000..9ec1e2a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test24365.d @@ -0,0 +1,20 @@ +// https://issues.dlang.org/show_bug.cgi?id=243645 + +/* +TEST_OUTPUT: +--- +fail_compilation/test24365.d(16): Error: `f` cannot be interpreted at compile time, because it has no available source code +fail_compilation/test24365.d(14): compile time context created here +fail_compilation/test24365.d(19): while evaluating: `static assert(r == 2)` +--- +*/ + +void main() +{ + enum r = () { + void f(); + f(); + return 2; + }(); + static assert(r == 2); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ufcs.d b/gcc/testsuite/gdc.test/fail_compilation/ufcs.d index 501ef81..3a92a69 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ufcs.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ufcs.d @@ -1,19 +1,20 @@ /* TEST_OUTPUT: --- -fail_compilation/ufcs.d(25): Error: no property `regularF` for `s` of type `S` -fail_compilation/ufcs.d(25): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(25): Error: function `ufcs.regularF()` is not callable using argument types `(S)` -fail_compilation/ufcs.d(25): expected 0 argument(s), not 1 -fail_compilation/ufcs.d(26): Error: no property `templateF` for `s` of type `S` +fail_compilation/ufcs.d(26): Error: no property `regularF` for `s` of type `S` fail_compilation/ufcs.d(26): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(26): Error: template `ufcs.templateF` is not callable using argument types `!()(S)` -fail_compilation/ufcs.d(31): Candidate is: `templateF()()` -fail_compilation/ufcs.d(27): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(26): Error: function `regularF` is not callable using argument types `(S)` +fail_compilation/ufcs.d(26): expected 0 argument(s), not 1 +fail_compilation/ufcs.d(31): `ufcs.regularF()` declared here +fail_compilation/ufcs.d(27): Error: no property `templateF` for `s` of type `S` fail_compilation/ufcs.d(27): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(27): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` -fail_compilation/ufcs.d(33): Candidates are: `templateO()(int x)` -fail_compilation/ufcs.d(34): `templateO()(float y)` +fail_compilation/ufcs.d(27): Error: template `templateF` is not callable using argument types `!()(S)` +fail_compilation/ufcs.d(32): Candidate is: `templateF()()` +fail_compilation/ufcs.d(28): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(28): the following error occured while looking for a UFCS match +fail_compilation/ufcs.d(28): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` +fail_compilation/ufcs.d(34): Candidates are: `templateO()(int x)` +fail_compilation/ufcs.d(35): `templateO()(float y)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d index eb23558..1a2846a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d @@ -1,10 +1,12 @@ /* TEST_OUTPUT: ---- -fail_compilation/vararg2.d(106): Error: function `vararg2.foo(int x, const return ...)` is not callable using argument types `(double)` +---- +fail_compilation/vararg2.d(106): Error: function `foo` is not callable using argument types `(double)` fail_compilation/vararg2.d(106): cannot pass argument `1.0` of type `double` to parameter `int x` -fail_compilation/vararg2.d(111): Error: function `vararg2.bar(int x, scope shared ...)` is not callable using argument types `(double)` +fail_compilation/vararg2.d(101): `vararg2.foo(int x, const return ...)` declared here +fail_compilation/vararg2.d(111): Error: function `bar` is not callable using argument types `(double)` fail_compilation/vararg2.d(111): cannot pass argument `1.0` of type `double` to parameter `int x` ---- +fail_compilation/vararg2.d(102): `vararg2.bar(int x, scope shared ...)` declared here +---- */ #line 100 diff --git a/gcc/testsuite/gdc.test/runnable/helloUTF8.d b/gcc/testsuite/gdc.test/runnable/helloUTF8.d deleted file mode 100644 index aed6613..0000000 --- a/gcc/testsuite/gdc.test/runnable/helloUTF8.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -PERMUTE_ARGS: -RUN_OUTPUT: ---- -hello world ---- -*/ - -extern(C) int printf(const char *, ...); - -int main(char[][] args) -{ - printf("hello world\n"); - - return 0; -} diff --git a/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d new file mode 100644 index 0000000..4278f7f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d @@ -0,0 +1,250 @@ +module imports.issue18919b; + +import core.stdc.stdio; + +// Remove directories from paths. Used to make the output platform-independent. +string baseName(string path) +{ + foreach_reverse (i, char c; path) + { + if (c == '/' || c == '\\') + return path[i + 1 .. $]; + } + return path; +} +const(char)* baseName(const(char)* path) +{ + for (const(char)* ptr = path; *ptr; ptr++) + { + if (*ptr == '/' || *ptr == '\\') + path = ptr + 1; + } + return path; +} + +void func1(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + file = baseName(file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, cast(int) line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +// https://issues.dlang.org/show_bug.cgi?id=21211 +void func2(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + file = baseName(file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + file, cast(int) line, func, pfunc, mod); +} + +// https://issues.dlang.org/show_bug.cgi?id=18919 +struct Loc3 +{ + string file; + size_t line; + string func; + string pfunc; + string mod; +} +void func3(Loc3 loc = Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +Loc3 defaultLoc3(string file = __FILE__, size_t line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__) +{ + return Loc3(file, line, func, pfunc, mod); +} +void func3b(Loc3 loc = defaultLoc3) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +enum Loc3Mixin = q{Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)}; +void func3c(Loc3 loc = mixin(Loc3Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} +void func3d(Loc3* loc = new Loc3(__FILE__, __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + loc.file = baseName(loc.file); + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +struct Loc4 +{ + const(char)* file; + size_t line; + const(char)* func; + const(char)* pfunc; + const(char)* mod; +} +void func4(Loc4 loc = Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +Loc4 defaultLoc4(const(char)* file = __FILE__.ptr, size_t line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr) +{ + return Loc4(file, line, func, pfunc, mod); +} +void func4b(Loc4 loc = defaultLoc4) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +enum Loc4Mixin = q{Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)}; +void func4c(Loc4 loc = mixin(Loc4Mixin)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} +void func4d(Loc4* loc = new Loc4(__FILE__.ptr, __LINE__, + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)) +{ + loc.file = baseName(loc.file); + printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr, + loc.file, cast(int) loc.line, + loc.func, + loc.pfunc, + loc.mod); +} + +void func5(string file = baseName(__FILE__), int line = __LINE__, + string func = __FUNCTION__, + string pfunc = __PRETTY_FUNCTION__, + string mod = __MODULE__)() +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, + cast(int) func.length, func.ptr, + cast(int) pfunc.length, pfunc.ptr, + cast(int) mod.length, mod.ptr); +} + +void func6(string file = baseName(__FILE__), int line = __LINE__, + const(char)* func = __FUNCTION__.ptr, + const(char)* pfunc = __PRETTY_FUNCTION__.ptr, + const(char)* mod = __MODULE__.ptr)() +{ + printf("%s: %.*s:%d %s %s %s\n", __FUNCTION__.ptr, + cast(int) file.length, file.ptr, line, func, pfunc, mod); +} + +void func7(int expr1 = 1000 + __LINE__ * 2, + string expr2 = "file=" ~ baseName(__FILE__) ~ " func=" ~ __FUNCTION__, + int expr3 = __LINE__ > 5 ? 1 : 2) +{ + printf("%s: expr1=%d, %.*s, expr3=%d\n", __FUNCTION__.ptr, expr1, cast(int) expr2.length, expr2.ptr, expr3); +} + +immutable string[2] constants = ["constant1", "constant2"]; +void func8(int[] expr1 = [__LINE__, __LINE__ + 1000], + int[string] expr2 = [baseName(__FILE__): __LINE__], + string expr3 = constants[__LINE__ > 5], + string expr4 = __FILE__[0 .. __FILE__.length - 2]) +{ + expr4 = baseName(expr4); + printf("%s: expr1=[", __FUNCTION__.ptr); + foreach (i, x; expr1) + printf("%d, ", x); + printf("], expr2=["); + foreach (k, v; expr2) + printf("%.*s: %d, ", cast(int) k.length, k.ptr, v); + printf("], expr3=%.*s", cast(int) expr3.length, expr3.ptr); + printf(", expr4=%.*s\n", cast(int) expr4.length, expr4.ptr); +} + +void func9(void function(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__) + fp = (string file, size_t line, string mod) + { + file = baseName(file); + printf("imports.issue18919b.func9.fp: %.*s:%d %.*s\n", + cast(int) file.length, file.ptr, cast(int) line, + cast(int) mod.length, mod.ptr); + }) +{ + fp(); +} + +void func10(string expr1 = mixin(() { return "\"expr1=" ~ __MODULE__ ~ "\""; } ()), + string expr2 = mixin("\"expr2=" ~ __MODULE__ ~ "\"")) +{ + printf("%s: %.*s, %.*s\n", __FUNCTION__.ptr, + cast(int) expr1.length, expr1.ptr, + cast(int) expr2.length, expr2.ptr); +} + +template ctLoc3(string file, int line, + string func, string pfunc, string mod) +{ + enum Loc3 ctLoc3 = Loc3(file, line, func, pfunc, mod); +} + +void func11(Loc3 loc = ctLoc3!(baseName(__FILE__), __LINE__, + __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)) +{ + printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr, + cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line, + cast(int) loc.func.length, loc.func.ptr, + cast(int) loc.pfunc.length, loc.pfunc.ptr, + cast(int) loc.mod.length, loc.mod.ptr); +} + +void func12(const(char)*[] args = [baseName(__FILE__.ptr), + __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr]) +{ + printf("%s:", __FUNCTION__.ptr); + foreach (arg; args) + printf(" %s", arg); + printf("\n"); +} diff --git a/gcc/testsuite/gdc.test/runnable/imports/standalone_b.d b/gcc/testsuite/gdc.test/runnable/imports/standalone_b.d new file mode 100644 index 0000000..bc5500b --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/standalone_b.d @@ -0,0 +1,11 @@ +module standalone_b; + +import standalone_modctor; +import core.attribute : standalone; + +immutable int* y; + +@standalone @system shared static this() +{ + y = new int(2); +} diff --git a/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d b/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d new file mode 100644 index 0000000..8311507 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d @@ -0,0 +1,51 @@ +import core.interpolation; + +alias AliasSeq(T...) = T; + +string simpleToString(T...)(T thing) { + string s; + foreach(item; thing) + // all the items provided by core.interpolation have + // toString to return an appropriate value + // + // then this particular example only has embedded strings + // and chars, to we can append them directly + static if(__traits(hasMember, item, "toString")) + s ~= item.toString(); + else + s ~= item; + + return s; +} + +void main() { + int a = 1; + string b = "one"; + // parser won't permit alias = i".." directly; i"..." is meant to + // be used as a function/template parameter at this time. + alias expr = AliasSeq!i"$(a) $(b)"; + // elements from the source code are available at compile time, so + // we static assert those, but the values, of course, are different + static assert(expr[0] == InterpolationHeader()); + static assert(expr[1] == InterpolatedExpression!"a"()); + assert(expr[2] == a); // actual value not available at compile time + static assert(expr[3] == InterpolatedLiteral!" "()); + // the parens around the expression are not included + static assert(expr[4] == InterpolatedExpression!"b"()); + assert(expr[5] == b); // actual value not available at compile time + static assert(expr[6] == InterpolationFooter()); + + // it does currently allow `auto` to be used, it creates a value tuple + // you can embed any D expressions inside the parenthesis, and the + // token is not ended until you get the *outer* ) and ". + auto thing = i"$(b) $("$" ~ ')' ~ `"`)"; + assert(simpleToString(thing) == "one $)\""); + + assert(simpleToString(i"$b") == "$b"); // support for $ident removed by popular demand + + // i`` and iq{} should also work + assert(simpleToString(i` $(b) is $(b)!`) == " one is one!"); + assert(simpleToString(iq{ $(b) is $(b)!}) == " one is one!"); + assert(simpleToString(i`\$('$')`) == "\\$"); // no \ escape there + assert(simpleToString(iq{{$('$')}}) == "{$}"); // {} needs to work +} diff --git a/gcc/testsuite/gdc.test/runnable/issue18919.d b/gcc/testsuite/gdc.test/runnable/issue18919.d new file mode 100644 index 0000000..815e018 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/issue18919.d @@ -0,0 +1,47 @@ +/* +EXTRA_SOURCES: imports/issue18919b.d +RUN_OUTPUT: +--- +imports.issue18919b.func1: issue18919.d:29 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func2: issue18919.d:30 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3: issue18919.d:31 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3b: issue18919.d:32 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3c: issue18919.d:33 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func3d: issue18919.d:34 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4: issue18919.d:35 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4b: issue18919.d:36 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4c: issue18919.d:37 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func4d: issue18919.d:38 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func5!("issue18919.d", 39, "issue18919.main", "void issue18919.main()", "issue18919").func5: issue18919.d:39 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func6!("issue18919.d", 40, "issue18919.main", "void issue18919.main()", "issue18919").func6: issue18919.d:40 issue18919.main void issue18919.main() issue18919 +imports.issue18919b.func7: expr1=1082, file=issue18919.d func=issue18919.main, expr3=1 +imports.issue18919b.func8: expr1=[42, 1042, ], expr2=[issue18919.d: 42, ], expr3=constant2, expr4=issue18919 +imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b +imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b +imports.issue18919b.func11: issue18919b.d:233 imports.issue18919b +imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919 +--- +*/ +import imports.issue18919b; + +void main() +{ + func1(); + func2(); + func3(); + func3b(); + func3c(); + func3d(); + func4(); + func4b(); + func4c(); + func4d(); + func5(); + func6(); + func7(); + func8(); + func9(); + func10(); + func11(); + func12(); +} diff --git a/gcc/testsuite/gdc.test/runnable/literal.d b/gcc/testsuite/gdc.test/runnable/literal.d index 99b1777..27b5543 100644 --- a/gcc/testsuite/gdc.test/runnable/literal.d +++ b/gcc/testsuite/gdc.test/runnable/literal.d @@ -241,6 +241,40 @@ void test12950() assert(0b00_00_00_01UL.op12950() == 12951); } +void testHexstring() +{ + static immutable uint[] x = cast(immutable uint[]) x"FFAADDEE"; + static assert(x[0] == 0xFFAADDEE); + assert(x[0] == 0xFFAADDEE); + + static immutable ulong[] y = cast(immutable ulong[]) x"1122334455667788AABBCCDDEEFF0099"; + static assert(y[0] == 0x1122334455667788); + static assert(y[1] == 0xAABBCCDDEEFF0099); + assert(y[0] == 0x1122334455667788); + assert(y[1] == 0xAABBCCDDEEFF0099); + + // Test that mangling of StringExp with size 8 is the same as array literal mangling: + void f(immutable ulong[] a)() {} + static assert(f!y.mangleof == f!([0x1122334455667788, 0xAABBCCDDEEFF0099]).mangleof); + + // Test printing StringExp with size 8 + enum toStr(immutable ulong[] v) = v.stringof; + static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"`); + + // Hex string postfixes + // https://issues.dlang.org/show_bug.cgi?id=24363 + wstring wStr = x"AA BB CC DD"w; + immutable int[] dStr = x"AA BB CC DD"d; + assert(wStr[0] == 0xAABB); + assert(wStr[1] == 0xCCDD); + assert(dStr[0] == 0xAABBCCDD); + + // Test sliceCmpStringWithArray with size 8 + static immutable ulong[] z0 = cast(immutable ulong[]) x"1111 1111 1111 1111 0000 000F 0000 0000"; + static immutable ulong[] z1 = [0x1111_1111_1111_1111, 0x0000_000E_0000_0000]; + static assert(z0 !is z1); +} + /***************************************************/ int main() @@ -249,6 +283,7 @@ int main() test2(); test13907(); test12950(); + testHexstring(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/standalone_modctor.d b/gcc/testsuite/gdc.test/runnable/standalone_modctor.d new file mode 100644 index 0000000..2654407 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/standalone_modctor.d @@ -0,0 +1,19 @@ +// REQUIRED_ARGS: -Irunnable/imports +// EXTRA_SOURCES: imports/standalone_b.d +// PERMUTE_ARGS: -cov + +import standalone_b; +import core.attribute : standalone; + +immutable int* x; + +@standalone @system shared static this() +{ + x = new int(1); +} + +void main() +{ + assert(*x == 1); + assert(*y == 2); +} diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d index 606b70e..e5b25d1 100644 --- a/gcc/testsuite/gdc.test/runnable/staticaa.d +++ b/gcc/testsuite/gdc.test/runnable/staticaa.d @@ -154,6 +154,17 @@ void testLocalStatic() @trusted ///////////////////////////////////////////// +// https://issues.dlang.org/show_bug.cgi?id=24311 +enum E : int[int] { x = [123: 456] } + +void testEnumInit() +{ + E e = E.init; + assert(e[123] == 456); +} + +///////////////////////////////////////////// + void main() { testSimple(); @@ -163,4 +174,5 @@ void main() testClassInit(); testImmutable(); testLocalStatic(); + testEnumInit(); } diff --git a/gcc/testsuite/gdc.test/runnable/test18916.d b/gcc/testsuite/gdc.test/runnable/test18916.d index 0e844ad..f14f32c 100644 --- a/gcc/testsuite/gdc.test/runnable/test18916.d +++ b/gcc/testsuite/gdc.test/runnable/test18916.d @@ -11,9 +11,9 @@ struct Line void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__)) { - assert(line1 == 12); + assert(line1 == 21); assert(line2 == 21); - assert(line3 == 12); + assert(line3 == 21); } void main() diff --git a/gcc/testsuite/gdc.test/runnable/testptrref.d b/gcc/testsuite/gdc.test/runnable/testptrref.d index 7255595..af101b9 100644 --- a/gcc/testsuite/gdc.test/runnable/testptrref.d +++ b/gcc/testsuite/gdc.test/runnable/testptrref.d @@ -3,6 +3,7 @@ version(CRuntime_Microsoft) { extern(C) { + extern __gshared void* __ImageBase; extern __gshared uint _DP_beg; extern __gshared uint _DP_end; extern __gshared uint _TP_beg; @@ -18,8 +19,8 @@ version(CRuntime_Microsoft) { import core.internal.traits : externDFunc; alias findImageSection = externDFunc!("rt.sections_win64.findImageSection", - void[] function(string name) nothrow @nogc); - dataSection = findImageSection(".data"); + void[] function(void* handle, string name) nothrow @nogc); + dataSection = findImageSection(&__ImageBase, ".data"); } void[] tlsRange; diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index aeb2aab..cbcbd1a 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -179,7 +179,7 @@ void test7() void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__) { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -192,7 +192,7 @@ void test8() void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)() { - assert(n1 < n2); + assert(n1 == n2); printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr); } @@ -8032,6 +8032,29 @@ void test18232() } /***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24332 + +void test24332() +{ + class A {} + final class B : A {} + + auto foo(A a) { + return cast(B) a; + } + + auto a = new A(); + auto n = cast(B) a; + assert(n is null); + auto b = cast(A) new B(); + auto c = cast(B) b; + assert(c); + B e; + auto d = cast(B) cast(A) e; + assert(d is null); +} + +/***************************************************/ int main() { @@ -8352,6 +8375,7 @@ int main() test17349(); test17915(); test18232(); + test24332(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/xtestenum.d b/gcc/testsuite/gdc.test/runnable/xtestenum.d index ce77782..4a4edd1 100644 --- a/gcc/testsuite/gdc.test/runnable/xtestenum.d +++ b/gcc/testsuite/gdc.test/runnable/xtestenum.d @@ -156,6 +156,19 @@ class C7379 } /***********************************/ +// https://issues.dlang.org/show_bug.cgi?id=23515 + +enum Easing : void function() +{ + identity1 = (){}, +} + +void test23515() +{ + Easing.identity1(); +} + +/***********************************/ int main() { @@ -166,6 +179,7 @@ int main() test5(); test6(); test7(); + test23515(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp new file mode 100644 index 0000000..2fab9af --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test24292.cpp @@ -0,0 +1,46 @@ +template<class T> +struct List +{ + T* begin; +}; + +struct StructWithDestructor +{ + ~StructWithDestructor(); + + int i; +}; + +struct StructWithCopyCtor +{ + StructWithCopyCtor(); + StructWithCopyCtor(const StructWithCopyCtor &other); + + int i; +}; + +StructWithDestructor::~StructWithDestructor() +{ +} + +StructWithCopyCtor::StructWithCopyCtor() +{ +} + +StructWithCopyCtor::StructWithCopyCtor(const StructWithCopyCtor &other) : i(other.i) +{ +} + +StructWithDestructor getStructWithDestructor() +{ + StructWithDestructor r; + r.i = 12345; + return r; +} + +StructWithCopyCtor getStructWithCopyCtor() +{ + StructWithCopyCtor r; + r.i = 54321; + return r; +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test24292.d b/gcc/testsuite/gdc.test/runnable_cxx/test24292.d new file mode 100644 index 0000000..b71f925 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test24292.d @@ -0,0 +1,50 @@ +// EXTRA_CPP_SOURCES: test24292.cpp + +extern(C++) struct List(T) +{ + // Any of the following static ifs can trigger the problem. + static if (T.sizeof > 4) {} + static if (__traits(isZeroInit, T)) {} + static if (__traits(isPOD, T)) {} + + T* begin; +} + +extern(C++) struct StructWithDestructor +{ + ~this(); + + alias L = List!StructWithDestructor; + int i; +} + +extern(C++) struct StructWithCopyCtor +{ + this(ref const(StructWithCopyCtor)); + + alias L = List!StructWithCopyCtor; + int i; +} + +extern(D) struct StructWithPostblit +{ + this(this) {} + + alias L = List!StructWithPostblit; + int i; +} + +static assert(!__traits(isPOD, StructWithDestructor)); +static assert(!__traits(isPOD, StructWithCopyCtor)); +static assert(!__traits(isPOD, StructWithPostblit)); + +extern(C++) StructWithDestructor getStructWithDestructor(); +extern(C++) StructWithCopyCtor getStructWithCopyCtor(); + +void main() +{ + StructWithDestructor structWithDestructor = getStructWithDestructor(); + assert(structWithDestructor.i == 12345); + StructWithCopyCtor structWithCopyCtor = getStructWithCopyCtor(); + assert(structWithCopyCtor.i == 54321); +} diff --git a/gcc/testsuite/gfortran.dg/asan/asan.exp b/gcc/testsuite/gfortran.dg/asan/asan.exp index 25cd19f..a157638 100644 --- a/gcc/testsuite/gfortran.dg/asan/asan.exp +++ b/gcc/testsuite/gfortran.dg/asan/asan.exp @@ -27,7 +27,8 @@ load_lib asan-dg.exp # Initialize `dg'. dg-init -asan_init +# libasan uses libstdc++ so make sure we provide paths for it. +asan_init 1 # Main loop. if [check_effective_target_fsanitize_address] { diff --git a/gcc/testsuite/gfortran.dg/coarray/caf.exp b/gcc/testsuite/gfortran.dg/coarray/caf.exp index dae46bd..31c13cd 100644 --- a/gcc/testsuite/gfortran.dg/coarray/caf.exp +++ b/gcc/testsuite/gfortran.dg/coarray/caf.exp @@ -70,18 +70,6 @@ proc dg-compile-aux-modules { args } { } } -# Add -latomic only where supported. Assume built-in support elsewhere. -set maybe_atomic_lib "" -if [check_effective_target_libatomic_available] { - if ![is_remote host] { - if [info exists TOOL_OPTIONS] { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]" - } else { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs]]" - } - } -} - # Main loop. foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]] { # If we're only testing specific files and this isn't one of them, skip it. @@ -105,14 +93,14 @@ foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ]] foreach flags $option_list { verbose "Testing $nshort (single), $flags" 1 set gfortran_aux_module_flags "-fcoarray=single $flags" - dg-test $test "-fcoarray=single $flags" $maybe_atomic_lib + dg-test $test "-fcoarray=single $flags" {} cleanup-modules "" } foreach flags $option_list { verbose "Testing $nshort (libcaf_single), $flags" 1 set gfortran_aux_module_flags "-fcoarray=lib $flags -lcaf_single" - dg-test $test "-fcoarray=lib $flags -lcaf_single" $maybe_atomic_lib + dg-test $test "-fcoarray=lib $flags -lcaf_single" {} cleanup-modules "" } } diff --git a/gcc/testsuite/gfortran.dg/dg.exp b/gcc/testsuite/gfortran.dg/dg.exp index f936fd3..7a9cb89 100644 --- a/gcc/testsuite/gfortran.dg/dg.exp +++ b/gcc/testsuite/gfortran.dg/dg.exp @@ -54,27 +54,7 @@ proc dg-compile-aux-modules { args } { } } -# coarray tests might need libatomic. Assume that it is either not needed or -# provided by builtins if it's not available. -set maybe_atomic_lib "" -if [check_effective_target_libatomic_available] { - if ![is_remote host] { - if [info exists TOOL_OPTIONS] { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]" - } else { - set maybe_atomic_lib "[atomic_link_flags [get_multilibs]]" - } - } else { - set maybe_atomic_lib "" - } -} - set all_flags $DEFAULT_FFLAGS -if { $maybe_atomic_lib != "" } { - foreach f $maybe_atomic_lib { - lappend all_flags $f - } -} # Main loop. gfortran-dg-runtest [lsort \ diff --git a/gcc/testsuite/gfortran.dg/fmt_error_10.f b/gcc/testsuite/gfortran.dg/fmt_error_10.f index 6e1a5f6..fc6620a 100644 --- a/gcc/testsuite/gfortran.dg/fmt_error_10.f +++ b/gcc/testsuite/gfortran.dg/fmt_error_10.f @@ -18,7 +18,7 @@ str = '(1pd0.15)' write (line,str,iostat=istat, iomsg=msg) 1.0d0 - if (line.ne."1.000000000000000") STOP 5 + if (line.ne."1.000000000000000D+0") STOP 5 read (*,str,iostat=istat, iomsg=msg) x if (istat.ne.5006 .or. msg(1:10).ne."Zero width") STOP 6 if (x.ne.555.25) STOP 7 diff --git a/gcc/testsuite/gfortran.dg/pr111022.f90 b/gcc/testsuite/gfortran.dg/pr111022.f90 new file mode 100644 index 0000000..eef55ff --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr111022.f90 @@ -0,0 +1,72 @@ +! { dg-do run } +program pr111022 + character(20) :: buffer + write(buffer,"(EN0.3E0)") .6660_4 + if (buffer.ne."666.000E-3") stop 1 + write(buffer,"(EN0.3E0)") 6.660_4 + if (buffer.ne."6.660E+0") stop 2 + write(buffer,"(EN0.3E0)") 66.60_4 + if (buffer.ne."66.600E+0") stop 3 + write(buffer,"(EN0.3E0)") 666.0_4 + if (buffer.ne."666.000E+0") stop 4 + write(buffer,"(EN0.3E0)") 6660.0_4 + if (buffer.ne."6.660E+3") stop 5 + write(buffer,"(EN0.3E0)") 66600.0_4 + if (buffer.ne."66.600E+3") stop 6 + + write(buffer,"(EN0.0E0)") 666.0_4 + if (buffer.ne."666.E+0") stop 7 + write(buffer,"(EN0.0E1)") 666.0_4 + if (buffer.ne."666.E+0") stop 8 + write(buffer,"(EN0.0E2)") 666.0_4 + if (buffer.ne."666.E+00") stop 9 + write(buffer,"(EN0.0E3)") 666.0_4 + if (buffer.ne."666.E+000") stop 10 + write(buffer,"(EN0.0E4)") 666.0_4 + if (buffer.ne."666.E+0000") stop 11 + write(buffer,"(EN0.0E5)") 666.0_4 + if (buffer.ne."666.E+00000") stop 12 + write(buffer,"(EN0.0E6)") 666.0_4 + if (buffer.ne."666.E+000000") stop 13 + + write(buffer,"(ES0.3E0)") .6660_4 + if (buffer.ne."6.660E-1") stop 14 + write(buffer,"(ES0.3E0)") 6.660_4 + if (buffer.ne."6.660E+0") stop 15 + write(buffer,"(ES0.3E0)") 66.60_4 + if (buffer.ne."6.660E+1") stop 16 + write(buffer,"(ES0.3E0)") 666.0_4 + if (buffer.ne."6.660E+2") stop 17 + write(buffer,"(ES0.3E0)") 6660.0_4 + if (buffer.ne."6.660E+3") stop 18 + write(buffer,"(ES0.3E0)") 66600.0_4 + if (buffer.ne."6.660E+4") stop 19 + + write(buffer,"(ES0.0E0)") 666.0_4 + if (buffer.ne."7.E+2") stop 20 + write(buffer,"(ES0.0E1)") 666.0_4 + if (buffer.ne."7.E+2") stop 21 + write(buffer,"(ES0.0E2)") 666.0_4 + if (buffer.ne."7.E+02") stop 22 + write(buffer,"(ES0.0E3)") 666.0_4 + if (buffer.ne."7.E+002") stop 23 + write(buffer,"(ES0.0E4)") 666.0_4 + if (buffer.ne."7.E+0002") stop 24 + write(buffer,"(ES0.0E5)") 666.0_4 + if (buffer.ne."7.E+00002") stop 25 + write(buffer,"(ES0.0E6)") 666.0_4 + if (buffer.ne."7.E+000002") stop 26 + + write(buffer,"(E0.3E0)") .6660_4 + if (buffer.ne."0.666E+0") stop 27 + write(buffer,"(E0.3)") .6660_4 + if (buffer.ne."0.666E+0") stop 28 + write(buffer,"(E0.1E0)") .6660_4 + if (buffer.ne."0.7E+0") stop 29 + write(buffer,"(E0.1)") .6660_4 + if (buffer.ne."0.7E+0") stop 30 + write(buffer,"(E0.5E0)") .6660_4 + if (buffer.ne."0.66600E+0") stop 31 + write(buffer,"(E0.5)") .6660_4 + if (buffer.ne."0.66600E+0") stop 32 +end program pr111022 diff --git a/gcc/testsuite/gfortran.dg/pr96436_4.f90 b/gcc/testsuite/gfortran.dg/pr96436_4.f90 index 335ce5f..7d2cfef 100644 --- a/gcc/testsuite/gfortran.dg/pr96436_4.f90 +++ b/gcc/testsuite/gfortran.dg/pr96436_4.f90 @@ -17,9 +17,9 @@ write(buffer,fmt) ">", 3.0, "<" if (buffer.ne.">0.30E+1<") stop 4 fmt = "(1a1,en0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 5 +if (buffer.ne.">3.00E+0<") stop 5 fmt = "(1a1,es0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 6 +if (buffer.ne.">3.00E+0<") stop 6 end diff --git a/gcc/testsuite/gfortran.dg/pr96436_5.f90 b/gcc/testsuite/gfortran.dg/pr96436_5.f90 index a45df89..3870d98 100644 --- a/gcc/testsuite/gfortran.dg/pr96436_5.f90 +++ b/gcc/testsuite/gfortran.dg/pr96436_5.f90 @@ -17,9 +17,9 @@ write(buffer,fmt) ">", 3.0, "<" if (buffer.ne.">0.30E+1<") stop 4 fmt = "(1a1,en0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 5 +if (buffer.ne.">3.00E+0<") stop 5 fmt = "(1a1,es0.2,1a1)" write(buffer,fmt) ">", 3.0, "<" -if (buffer.ne.">3.00<") stop 6 +if (buffer.ne.">3.00E+0<") stop 6 end diff --git a/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp b/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp index 0c61153..b236078 100644 --- a/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp +++ b/gcc/testsuite/gfortran.dg/ubsan/ubsan.exp @@ -22,10 +22,10 @@ load_lib gfortran-dg.exp load_lib ubsan-dg.exp - # Initialize `dg'. dg-init -ubsan_init +# libubsan uses libstdc++ so make sure we provide paths for it. +ubsan_init 1 # Main loop. if [check_effective_target_fsanitize_undefined] { diff --git a/gcc/testsuite/gfortran.dg/vect/vect-10.f90 b/gcc/testsuite/gfortran.dg/vect/vect-10.f90 new file mode 100644 index 0000000..b85bc27 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/vect/vect-10.f90 @@ -0,0 +1,71 @@ +! { dg-do compile } +! { dg-additional-options "-Ofast -mlsx -fvect-cost-model=dynamic" { target loongarch64*-*-* } } + +MODULE material_mod + +IMPLICIT NONE + +integer, parameter :: dfp = selected_real_kind (13, 99) +integer, parameter :: rfp = dfp + +PUBLIC Mat_updateE, iepx, iepy, iepz + +PRIVATE + +integer, dimension (:, :, :), allocatable :: iepx, iepy, iepz +real (kind = rfp), dimension (:), allocatable :: Dbdx, Dbdy, Dbdz +integer :: imin, jmin, kmin +integer, dimension (6) :: Exsize +integer, dimension (6) :: Eysize +integer, dimension (6) :: Ezsize +integer, dimension (6) :: Hxsize +integer, dimension (6) :: Hysize +integer, dimension (6) :: Hzsize + +CONTAINS + +SUBROUTINE mat_updateE (nx, ny, nz, Hx, Hy, Hz, Ex, Ey, Ez) + +integer, intent (in) :: nx, ny, nz + +real (kind = rfp), intent (inout), & + dimension (Exsize (1) : Exsize (2), Exsize (3) : Exsize (4), Exsize (5) : Exsize (6)) :: Ex +real (kind = rfp), intent (inout), & + dimension (Eysize (1) : Eysize (2), Eysize (3) : Eysize (4), Eysize (5) : Eysize (6)) :: Ey +real (kind = rfp), intent (inout), & + dimension (Ezsize (1) : Ezsize (2), Ezsize (3) : Ezsize (4), Ezsize (5) : Ezsize (6)) :: Ez +real (kind = rfp), intent (in), & + dimension (Hxsize (1) : Hxsize (2), Hxsize (3) : Hxsize (4), Hxsize (5) : Hxsize (6)) :: Hx +real (kind = rfp), intent (in), & + dimension (Hysize (1) : Hysize (2), Hysize (3) : Hysize (4), Hysize (5) : Hysize (6)) :: Hy +real (kind = rfp), intent (in), & + dimension (Hzsize (1) : Hzsize (2), Hzsize (3) : Hzsize (4), Hzsize (5) : Hzsize (6)) :: Hz + +integer :: i, j, k, mp + +do k = kmin, nz + do j = jmin, ny + do i = imin, nx + mp = iepx (i, j, k) + Ex (i, j, k) = Ex (i, j, k) + & + Dbdy (mp) * (Hz (i, j, k ) - Hz (i, j-1, k)) + & + Dbdz (mp) * (Hy (i, j, k-1) - Hy (i, j , k)) + + mp = iepy (i, j, k) + Ey (i, j, k) = Ey (i, j, k) + & + Dbdz (mp) * (Hx (i , j, k) - Hx (i, j, k-1)) + & + Dbdx (mp) * (Hz (i-1, j, k) - Hz (i, j, k )) + + mp = iepz (i, j, k) + Ez (i, j, k) = Ez (i, j, k) + & + Dbdx (mp) * (Hy (i, j , k) - Hy (i-1, j, k)) + & + Dbdy (mp) * (Hx (i, j-1, k) - Hx (i , j, k)) + end do + end do +end do + +END SUBROUTINE mat_updateE + +END MODULE material_mod + +! { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target loongarch64*-*-* } } } diff --git a/gcc/testsuite/gm2/extensions/fail/arith1.mod b/gcc/testsuite/gm2/extensions/fail/arith1.mod new file mode 100644 index 0000000..bdfb2d8 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith1.mod @@ -0,0 +1,36 @@ +MODULE arith1 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c16 := c16 + c8 ; +END testCardinal ; + + +BEGIN + testCardinal +END arith1. diff --git a/gcc/testsuite/gm2/extensions/fail/arith2.mod b/gcc/testsuite/gm2/extensions/fail/arith2.mod new file mode 100644 index 0000000..fc6cb26 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith2.mod @@ -0,0 +1,36 @@ +MODULE arith2 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c64 := c64 + c8 +END testCardinal ; + + +BEGIN + testCardinal +END arith2. diff --git a/gcc/testsuite/gm2/extensions/fail/arith3.mod b/gcc/testsuite/gm2/extensions/fail/arith3.mod new file mode 100644 index 0000000..6d34881 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith3.mod @@ -0,0 +1,36 @@ +MODULE arith3 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c64 := c32 + c64 +END testCardinal ; + + +BEGIN + testCardinal +END arith3. diff --git a/gcc/testsuite/gm2/extensions/fail/arith4.mod b/gcc/testsuite/gm2/extensions/fail/arith4.mod new file mode 100644 index 0000000..8249452 --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arith4.mod @@ -0,0 +1,36 @@ +MODULE arith4 ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; + c64 := 16 * c64 + c32; (* Should fail here. *) +END testCardinal ; + + +BEGIN + testCardinal +END arith4. diff --git a/gcc/testsuite/gm2/extensions/fail/arithpromote.mod b/gcc/testsuite/gm2/extensions/fail/arithpromote.mod new file mode 100644 index 0000000..59738cb --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/arithpromote.mod @@ -0,0 +1,55 @@ +MODULE arithpromote ; + +IMPORT SYSTEM ; +FROM libc IMPORT exit, printf ; +FROM NumberIO IMPORT WriteCard ; +FROM StrIO IMPORT WriteLn ; + + +PROCEDURE assert (computed, result: CARDINAL; message: ARRAY OF CHAR) ; +BEGIN + IF computed # result + THEN + printf (message, computed, result) ; + exit (1) + END +END assert ; + + +PROCEDURE testCardinal ; +VAR + c64: SYSTEM.CARDINAL64 ; + c32: SYSTEM.CARDINAL32 ; + c16: SYSTEM.CARDINAL32 ; + c8 : SYSTEM.CARDINAL8 ; +BEGIN + c8 := 7 ; + c16 := 7000H ; + c32 := 7 ; + c64 := 0000000100000000H ; +(* + assert (c16 + c8, 7007H, "addition between CARDINAL16 and CARDINAL8 fails: %d # %d\n") ; + c64 := 0000000100000000H ; +*) +(* + IF c64 + c8 # 0000000100000007H + THEN + printf ("failure when adding 0000000100000000H + 7\n"); + exit (1) + END +*) +(* + IF c64 + c32 # 0000000100000007H + THEN + printf ("failure when adding 0000000100000000H + 7\n"); + exit (1) + END +*) + c64 := 16 * c64 + c32; (* Should fail here. *) + c64 := c32 + c64 ; +END testCardinal ; + + +BEGIN + testCardinal +END arithpromote. diff --git a/gcc/testsuite/gm2/extensions/fail/extensions-fail.exp b/gcc/testsuite/gm2/extensions/fail/extensions-fail.exp new file mode 100644 index 0000000..3839a0a --- /dev/null +++ b/gcc/testsuite/gm2/extensions/fail/extensions-fail.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2003-2024 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This file was written by Gaius Mulley (gaius.mulley@southwales.ac.uk) +# for GNU Modula-2. + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib gm2-torture.exp + +gm2_init_pim "${srcdir}/gm2/extensions/fail" + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + + gm2-torture-fail $testcase +} diff --git a/gcc/testsuite/gm2/linking/fail/badimp.def b/gcc/testsuite/gm2/linking/fail/badimp.def new file mode 100644 index 0000000..1b31f0b --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/badimp.def @@ -0,0 +1,4 @@ +DEFINITION MODULE badimp ; + + +END badimp. diff --git a/gcc/testsuite/gm2/linking/fail/badimp.mod b/gcc/testsuite/gm2/linking/fail/badimp.mod new file mode 100644 index 0000000..02da928 --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/badimp.mod @@ -0,0 +1,8 @@ +(* { dg-skip-if "" { *-*-* } } *) + +MODULE badimp ; + +(* User forgot the IMPLEMENTATION keyword prior to MODULE. *) + +BEGIN +END badimp. diff --git a/gcc/testsuite/gm2/linking/fail/linking-fail.exp b/gcc/testsuite/gm2/linking/fail/linking-fail.exp new file mode 100644 index 0000000..95e95d6 --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/linking-fail.exp @@ -0,0 +1,38 @@ +# Copyright (C) 2024 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# This file was written by Gaius Mulley (gaius.mulley@southwales.ac.uk) +# for GNU Modula-2. + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib gm2-torture.exp + +gm2_init_pim "${srcdir}/gm2/linking/fail" -fscaffold-main + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + + if { $testcase != "$srcdir/$subdir/badimp.mod" } { + gm2-torture-fail $testcase + } +} diff --git a/gcc/testsuite/gm2/linking/fail/testbadimp.mod b/gcc/testsuite/gm2/linking/fail/testbadimp.mod new file mode 100644 index 0000000..cdea4fc --- /dev/null +++ b/gcc/testsuite/gm2/linking/fail/testbadimp.mod @@ -0,0 +1,6 @@ +MODULE testbadimp ; + +IMPORT badimp ; + +BEGIN +END testbadimp. diff --git a/gcc/testsuite/gm2/pim/pass/stdio.mod b/gcc/testsuite/gm2/pim/pass/teststdio.mod index f121a8c..f67b1c7 100644 --- a/gcc/testsuite/gm2/pim/pass/stdio.mod +++ b/gcc/testsuite/gm2/pim/pass/teststdio.mod @@ -16,7 +16,7 @@ with gm2; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) -MODULE stdio ; (*!m2pim*) +MODULE teststdio ; (*!m2pim*) CONST MaxStack = 40 ; @@ -50,4 +50,4 @@ END PushOutput ; BEGIN StackWPtr := 0 ; PushOutput(write) -END stdio. +END teststdio. diff --git a/gcc/testsuite/gm2/pim/run/pass/builtins.mod b/gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod index 1cf9fb7..2fbea37 100644 --- a/gcc/testsuite/gm2/pim/run/pass/builtins.mod +++ b/gcc/testsuite/gm2/pim/run/pass/testbuiltins.mod @@ -1,4 +1,4 @@ -MODULE builtins ; (*!m2pim+gm2*) +MODULE testbuiltins ; (*!m2pim+gm2*) FROM Builtins IMPORT log10l ; FROM libc IMPORT printf, exit ; @@ -76,4 +76,4 @@ BEGIN code := 0 ; test ; exit (code) -END builtins. +END testbuiltins. diff --git a/gcc/testsuite/gm2/pim/run/pass/math.mod b/gcc/testsuite/gm2/pim/run/pass/testmath.mod index 8eab79d..19caf57 100644 --- a/gcc/testsuite/gm2/pim/run/pass/math.mod +++ b/gcc/testsuite/gm2/pim/run/pass/testmath.mod @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with gm2; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) -MODULE math ; +MODULE testmath ; IMPORT MathLib0, SMathLib0 ; FROM libc IMPORT printf, exit ; @@ -41,4 +41,4 @@ BEGIN s := 5.9 ; printf("value of SMathLib0.entier (10.0 + s) = %d (should be 15)\n", SMathLib0.entier (10.0 + s)) ; Assert(SMathLib0.entier (10.0 + s) = 15, __FILE__, __LINE__) ; -END math. +END testmath. diff --git a/gcc/testsuite/gm2/pim/run/pass/math2.mod b/gcc/testsuite/gm2/pim/run/pass/testmath2.mod index 3dd2709..483372d 100644 --- a/gcc/testsuite/gm2/pim/run/pass/math2.mod +++ b/gcc/testsuite/gm2/pim/run/pass/testmath2.mod @@ -15,7 +15,7 @@ You should have received a copy of the GNU General Public License along with gm2; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *) -MODULE math2 ; +MODULE testmath2 ; IMPORT MathLib0, SMathLib0 ; FROM libc IMPORT printf, exit ; @@ -41,4 +41,4 @@ BEGIN s := 5.9 ; printf("value of SMathLib0.entier (10.0 + s) = %d (should be 15)\n", SMathLib0.entier (10.0 + s)) ; Assert(SMathLib0.entier (s + 10.0) = 15, __FILE__, __LINE__) ; -END math2. +END testmath2. diff --git a/gcc/testsuite/gnat.dg/trampoline3.adb b/gcc/testsuite/gnat.dg/trampoline3.adb index 2805766..10b6e5d 100644 --- a/gcc/testsuite/gnat.dg/trampoline3.adb +++ b/gcc/testsuite/gnat.dg/trampoline3.adb @@ -19,4 +19,4 @@ begin I := P(0); end; --- { dg-final { scan-assembler-not "GNU-stack.*x" } } +-- { dg-final { scan-assembler-not "GNU-stack.*x" { xfail hppa*-*-* } } } diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index d09a31e..14a0a32 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -353,6 +353,13 @@ /* test-setting-alignment.c: This can't be in the testcases array as it is target-specific. */ +/* test-sizeof.c */ +#define create_code create_code_sizeof +#define verify_code verify_code_sizeof +#include "test-sizeof.c" +#undef create_code +#undef verify_code + /* test-string-literal.c */ #define create_code create_code_string_literal #define verify_code verify_code_string_literal @@ -553,6 +560,9 @@ const struct testcase testcases[] = { {"reflection", create_code_reflection , verify_code_reflection }, + {"sizeof", + create_code_sizeof, + verify_code_sizeof}, {"string_literal", create_code_string_literal, verify_code_string_literal}, diff --git a/gcc/testsuite/jit.dg/test-sizeof.c b/gcc/testsuite/jit.dg/test-sizeof.c new file mode 100644 index 0000000..6aef902 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-sizeof.c @@ -0,0 +1,50 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.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: +int +my_sizeof () +{ + return sizeof(int32_t); +} + */ + gcc_jit_type *int32 = + gcc_jit_context_get_int_type (ctxt, 4, 1); + 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, + int_type, + "my_sizeof", + 0, NULL, 0); + + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + + gcc_jit_block_end_with_return(initial, NULL, + gcc_jit_context_new_sizeof(ctxt, int32)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*my_sizeof_type) (); + CHECK_NON_NULL (result); + my_sizeof_type my_sizeof = + (my_sizeof_type)gcc_jit_result_get_code (result, "my_sizeof"); + CHECK_NON_NULL (my_sizeof); + int val = my_sizeof (); + CHECK_VALUE (val, 4); +} diff --git a/gcc/testsuite/lib/asan-dg.exp b/gcc/testsuite/lib/asan-dg.exp index beb49e5..6bd3c21 100644 --- a/gcc/testsuite/lib/asan-dg.exp +++ b/gcc/testsuite/lib/asan-dg.exp @@ -61,7 +61,7 @@ proc asan_include_flags {} { # (originally from g++.exp) # -proc asan_link_flags_1 { paths lib } { +proc asan_link_flags_1 { paths lib need_stdcxx} { global srcdir global ld_library_path global shlib_ext @@ -73,6 +73,10 @@ proc asan_link_flags_1 { paths lib } { set shlib_ext [get_shlib_extension] set ${lib}_saved_library_path $ld_library_path + # Providing -B instead of -L means that it works for targets that use + # spec substitution for handling -static-xxxxx, it also works for targets + # the use the startfile paths to provide a runpath for uninstalled test. + # Each -B option will produce a -L on the link line (for paths that exist). if { $gccpath != "" } { if { [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.a"] || [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.${shlib_ext}"] } { @@ -81,6 +85,12 @@ proc asan_link_flags_1 { paths lib } { append flags " -B${gccpath}/libsanitizer/${lib}/.libs " append ld_library_path ":${gccpath}/libsanitizer/${lib}/.libs" } + # libasan links to libstdc++, so we must include it for C testcases. + if { $need_stdcxx && ( [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] + || [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] ) } { + append flags " -B${gccpath}/libstdc++-v3/src/.libs " + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + } } else { global tool_root_dir @@ -96,8 +106,8 @@ proc asan_link_flags_1 { paths lib } { return "$flags" } -proc asan_link_flags { paths } { - return [asan_link_flags_1 $paths asan] +proc asan_link_flags { paths need_stdcxx } { + return [asan_link_flags_1 $paths asan $need_stdcxx] } # @@ -113,12 +123,13 @@ proc asan_init { args } { setenv ASAN_OPTIONS "color=never" + set needs_cxx [lindex $args 0] set link_flags "" if ![is_remote host] { if [info exists TOOL_OPTIONS] { - set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}] $needs_cxx]" } else { - set link_flags "[asan_link_flags [get_multilibs]]" + set link_flags "[asan_link_flags [get_multilibs] $needs_cxx]" } } diff --git a/gcc/testsuite/lib/gfortran.exp b/gcc/testsuite/lib/gfortran.exp index c3e258b..1ccb81c 100644 --- a/gcc/testsuite/lib/gfortran.exp +++ b/gcc/testsuite/lib/gfortran.exp @@ -79,6 +79,7 @@ proc gfortran_link_flags { paths } { global ld_library_path global GFORTRAN_UNDER_TEST global shlib_ext + global ENABLE_DARWIN_AT_RPATH set gccpath ${paths} set libio_dir "" @@ -87,39 +88,63 @@ proc gfortran_link_flags { paths } { set shlib_ext [get_shlib_extension] verbose "shared lib extension: $shlib_ext" + # We need to add options to locate libgfortran and the dependent libs + # libquadmath (supporting REAL*16) and libatomic (supporting operations + # used by coarrays). Usually '-L' options are added to point to the + # relevant directories for the uninstalled libraries. + + # In cases where libraries are available as both shared and convenience + # some additional checks are made. + + # For some targets -static-xxxx options are handled by specs substitution + # and need a '-B' option rather than '-L'. For Darwin, when embedded + # runpaths are in use (the default for all versions after macOS 10.11), + # '-B' is also needed to provide the runpath. + # When '-B' is used, this results in a '-L' for each path that exists (so + # that appending a '-L' as well is a needless duplicate). There are also + # cases where tools warn for duplicates, leading to spurious fails. + # Therefore the objective of the code below is to add just one '-L' or + # '-B' for each of the libraries. + + set target_wants_B_option 0 + if { [istarget *-*-darwin9* ] || [istarget *-*-darwin\[12\]* ] } { + set target_wants_B_option 1 + } + if { $gccpath != "" } { - if [file exists "${gccpath}/libgfortran/.libs/libgfortran.a"] { - # Some targets use libgfortran.a%s in their specs, so they need a -B option - # for uninstalled testing. - append flags "-B${gccpath}/libgfortran/.libs " - append flags "-L${gccpath}/libgfortran/.libs " - append ld_library_path ":${gccpath}/libgfortran/.libs" - } - if [file exists "${gccpath}/libgfortran/.libs/libgfortran.${shlib_ext}"] { - append flags "-L${gccpath}/libgfortran/.libs " - append ld_library_path ":${gccpath}/libgfortran/.libs" - } if [file exists "${gccpath}/libgfortran/libgforbegin.a"] { append flags "-L${gccpath}/libgfortran " } - if [file exists "${gccpath}/libatomic/.libs/libatomic.${shlib_ext}"] { - append flags "-L${gccpath}/libatomic/.libs " - append ld_library_path ":${gccpath}/libatomic/.libs" + if { [file exists "${gccpath}/libgfortran/.libs/libgfortran.a"] || + [file exists "${gccpath}/libgfortran/.libs/libgfortran.${shlib_ext}"] } { + if { $target_wants_B_option } { + append flags "-B${gccpath}/libgfortran/.libs " + } else { + append flags "-L${gccpath}/libgfortran/.libs " + } + append ld_library_path ":${gccpath}/libgfortran/.libs" } - if [file exists "${gccpath}/libatomic/libatomic.a"] { - append flags "-L${gccpath}/libatomic " + + if { [file exists "${gccpath}/libatomic/.libs/libatomic.a"] || + [file exists "${gccpath}/libatomic/.libs/libatomic.${shlib_ext}"] } { + if { $target_wants_B_option } { + append flags "-B${gccpath}/libatomic/.libs " + } else { + append flags "-L${gccpath}/libatomic/.libs " + } + append ld_library_path ":${gccpath}/libatomic/.libs" } - if [file exists "${gccpath}/libquadmath/.libs/libquadmath.a"] { - # Some targets use libquadmath.a%s in their specs, so they need a -B option - # for uninstalled testing. + + if { [file exists "${gccpath}/libquadmath/.libs/libquadmath.a"] || + [file exists "${gccpath}/libquadmath/.libs/libquadmath.${shlib_ext}"] } { + if { $target_wants_B_option } { append flags "-B${gccpath}/libquadmath/.libs " + } else { append flags "-L${gccpath}/libquadmath/.libs " - append ld_library_path ":${gccpath}/libquadmath/.libs" - } - if [file exists "${gccpath}/libquadmath/.libs/libquadmath.${shlib_ext}"] { - append flags "-L${gccpath}/libquadmath/.libs " - append ld_library_path ":${gccpath}/libquadmath/.libs" + } + append ld_library_path ":${gccpath}/libquadmath/.libs" } + if [file exists "${gccpath}/libiberty/libiberty.a"] { append flags "-L${gccpath}/libiberty " } diff --git a/gcc/testsuite/lib/hwasan-dg.exp b/gcc/testsuite/lib/hwasan-dg.exp index 8d66b4d..33c9a7c 100644 --- a/gcc/testsuite/lib/hwasan-dg.exp +++ b/gcc/testsuite/lib/hwasan-dg.exp @@ -100,8 +100,8 @@ proc hwasan_include_flags {} { # (implementation in asan-dg.exp) # -proc hwasan_link_flags { paths } { - return [asan_link_flags_1 $paths hwasan] +proc hwasan_link_flags { paths needs_cxx } { + return [asan_link_flags_1 $paths hwasan $needs_cxx] } # @@ -114,6 +114,7 @@ proc hwasan_init { args } { global TOOL_OPTIONS global hwasan_saved_TEST_ALWAYS_FLAGS global hwasan_saved_ALWAYS_CXXFLAGS + set needs_cxx [lindex $args 0] setenv HWASAN_OPTIONS "random_tags=0" @@ -126,9 +127,9 @@ proc hwasan_init { args } { set link_flags "" if ![is_remote host] { if [info exists TOOL_OPTIONS] { - set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + set link_flags "[hwasan_link_flags [get_multilibs ${TOOL_OPTIONS}] $needs_cxx]" } else { - set link_flags "[hwasan_link_flags [get_multilibs]]" + set link_flags "[hwasan_link_flags [get_multilibs] $needs_cxx]" } } diff --git a/gcc/testsuite/lib/obj-c++.exp b/gcc/testsuite/lib/obj-c++.exp index 397b70c..854dc26 100644 --- a/gcc/testsuite/lib/obj-c++.exp +++ b/gcc/testsuite/lib/obj-c++.exp @@ -110,34 +110,43 @@ proc obj-c++_link_flags { paths } { set shlib_ext [get_shlib_extension] verbose "shared lib extension: $shlib_ext" + # We need to add options to locate libobjc/libobjc-gnu and libstdc++ + # Usually '-L' options are added to point to the relevant directories for + # the uninstalled libraries. + + # In cases where libraries are available as both shared and convenience + # some additional checks are made. + + # For some targets -static-xxxx options are handled by specs substitution + # and need a '-B' option rather than '-L'. For Darwin, when embedded + # runpaths are in use (the default for all versions after macOS 10.11), + # '-B' is also needed to provide the runpath. + # When '-B' is used, this results in a '-L' for each path that exists (so + # that appending a '-L' as well is a needless duplicate). There are also + # cases where tools warn for duplicates, leading to spurious fails. + # Therefore the objective of the code below is to add just one '-L' or + # '-B' for each of the libraries. + + set target_wants_B_option 0 + if { [istarget *-*-darwin9* ] || [istarget *-*-darwin\[12\]* ] } { + set target_wants_B_option 1 + } + if { $gccpath != "" } { - if [file exists "${gccpath}/lib/libstdc++.a"] { - append ld_library_path ":${gccpath}/lib" - } - if [file exists "${gccpath}/libg++/libg++.a"] { - append flags " -L${gccpath}/libg++ " - append ld_library_path ":${gccpath}/libg++" - } - if [file exists "${gccpath}/libstdc++/libstdc++.a"] { - append flags " -L${gccpath}/libstdc++ " - append ld_library_path ":${gccpath}/libstdc++" - } - if [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] { - # Allow for %s spec substitutions - append flags " -B${gccpath}/libstdc++-v3/src/.libs " - append flags " -L${gccpath}/libstdc++-v3/src/.libs " - append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" - } - # Look for libstdc++.${shlib_ext}. - if [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] { - # Allow for %s spec substitutions - append flags " -B${gccpath}/libstdc++-v3/src/.libs " - append flags " -L${gccpath}/libstdc++-v3/src/.libs " - append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + if { [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] || + [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] } { + if { $target_wants_B_option } { + append flags "-B${gccpath}/libstdc++-v3/src/.libs " + } else { + append flags "-L${gccpath}/libstdc++-v3/src/.libs " + } + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" } + if [file exists "${gccpath}/libiberty/libiberty.a"] { append flags " -L${gccpath}/libiberty " } + if [file exists "${gccpath}/librx/librx.a"] { append flags " -L${gccpath}/librx " } @@ -159,9 +168,11 @@ proc obj-c++_link_flags { paths } { if { $libobjc_dir != "" } { set libobjc_dir [file dirname ${libobjc_dir}] - # Allow for %s spec substitutions - append flags " -B${libobjc_dir} " - append flags " -L${libobjc_dir} " + if { $target_wants_B_option } { + append flags "-B${libobjc_dir} " + } else { + append flags "-L${libobjc_dir} " + } append ld_library_path ":${libobjc_dir}" } append ld_library_path \ @@ -176,7 +187,11 @@ proc obj-c++_link_flags { paths } { } set libstdcpp [lookfor_file ${tool_root_dir} libstdc++]; if { $libstdcpp != "" } { - append flags "-L${libstdcpp} "; + if { $target_wants_B_option } { + append flags "-B${libstdcpp} " + } else { + append flags "-L${libstdcpp} " + } append ld_library_path ":${libstdcpp}" } set libiberty [lookfor_file ${tool_root_dir} libiberty]; diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 8aefb32..b1faaf4 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -1385,6 +1385,13 @@ proc check_effective_target_aarch64_tlsle32 { } { # emitted, 0 otherwise. proc check_effective_target_shared { } { + # Darwin's linker defaults to error on undefined (which makes it look as + # if we do not support shared) but we can tell it to allow the symbols used + # here to be undefined. + set extra_flags "" + if { [istarget *-*-darwin\[912\]*] } { + set extra_flags "-Wl,-U,_foo,-U,_bar" + } # Note that M68K has a multilib that supports -fpic but not # -fPIC, so we need to check both. We test with a program that # requires GOT references, and with a libc symbol that would @@ -1397,7 +1404,7 @@ proc check_effective_target_shared { } { char *baz (void) { return foo () + (char*) malloc (bar); } - } "-shared -fpic"] + } "-shared -fpic $extra_flags"] } # Return 1 if -pie, -fpie and -fPIE are supported, 0 otherwise. @@ -5526,6 +5533,8 @@ foreach { armfunc armflag armdefs } { __ARM_ARCH_8M_BASE__ v8m_main "-march=armv8-m.main+fp -mthumb" __ARM_ARCH_8M_MAIN__ v8_1m_main "-march=armv8.1-m.main+fp -mthumb" __ARM_ARCH_8M_MAIN__ + v8_1m_main_pacbti "-march=armv8.1-m.main+pacbti+fp -mthumb" + "__ARM_ARCH_8M_MAIN__ && __ARM_FEATURE_BTI" v9a "-march=armv9-a+simd" __ARM_ARCH_9A__ } { eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] { proc check_effective_target_arm_arch_FUNC_ok { } { diff --git a/gcc/testsuite/lib/ubsan-dg.exp b/gcc/testsuite/lib/ubsan-dg.exp index 108b998..860e78f 100644 --- a/gcc/testsuite/lib/ubsan-dg.exp +++ b/gcc/testsuite/lib/ubsan-dg.exp @@ -31,7 +31,7 @@ proc check_effective_target_fsanitize_undefined {} { # (originally from g++.exp) # -proc ubsan_link_flags { paths } { +proc ubsan_link_flags { paths needs_cxx } { global srcdir global ld_library_path global shlib_ext @@ -43,15 +43,24 @@ proc ubsan_link_flags { paths } { set shlib_ext [get_shlib_extension] set ubsan_saved_library_path $ld_library_path + # Providing -B instead of -L means that it works for targets that use + # spec substitution for handling -static-xxxxx, it also works for targets + # the use the startfile paths to provide a runpath for uninstalled test. + # Each -B option will produce a -L on the link line (for paths that exist). if { $gccpath != "" } { if { [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.a"] || [file exists "${gccpath}/libsanitizer/ubsan/.libs/libubsan.${shlib_ext}"] } { append flags " -B${gccpath}/libsanitizer/ " append flags " -B${gccpath}/libsanitizer/ubsan/ " - append flags " -L${gccpath}/libsanitizer/ubsan/.libs" + append flags " -B${gccpath}/libsanitizer/ubsan/.libs" append ld_library_path ":${gccpath}/libsanitizer/ubsan/.libs" - append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" } + # libasan links to libstdc++, so we must include it for C testcases. + if { $needs_cxx && ( [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.a"] + || [file exists "${gccpath}/libstdc++-v3/src/.libs/libstdc++.${shlib_ext}"] ) } { + append flags " -B${gccpath}/libstdc++-v3/src/.libs " + append ld_library_path ":${gccpath}/libstdc++-v3/src/.libs" + } } else { global tool_root_dir @@ -79,6 +88,7 @@ proc ubsan_init { args } { global ubsan_saved_ALWAYS_CXXFLAGS global orig_ubsan_options_saved global orig_ubsan_options + set needs_cxx [lindex $args 0] if { $orig_ubsan_options_saved == 0 } { # Save the original environment. @@ -92,9 +102,9 @@ proc ubsan_init { args } { set link_flags "" if ![is_remote host] { if [info exists TOOL_OPTIONS] { - set link_flags "[ubsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]" + set link_flags "[ubsan_link_flags [get_multilibs ${TOOL_OPTIONS}] $needs_cxx]" } else { - set link_flags "[ubsan_link_flags [get_multilibs]]" + set link_flags "[ubsan_link_flags [get_multilibs] $needs_cxx]" } } diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc index 2db26e4..a8d25c2 100644 --- a/gcc/tree-ssa-math-opts.cc +++ b/gcc/tree-ssa-math-opts.cc @@ -2552,12 +2552,48 @@ is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out, if (TREE_CODE (rhs) == SSA_NAME) { + /* Use tree_non_zero_bits to see if this operand is zero_extended + for unsigned widening multiplications or non-negative for + signed widening multiplications. */ + if (TREE_CODE (type) == INTEGER_TYPE + && (TYPE_PRECISION (type) & 1) == 0 + && int_mode_for_size (TYPE_PRECISION (type) / 2, 1).exists ()) + { + unsigned int prec = TYPE_PRECISION (type); + unsigned int hprec = prec / 2; + wide_int bits = wide_int::from (tree_nonzero_bits (rhs), prec, + TYPE_SIGN (TREE_TYPE (rhs))); + if (TYPE_UNSIGNED (type) + && wi::bit_and (bits, wi::mask (hprec, true, prec)) == 0) + { + *type_out = build_nonstandard_integer_type (hprec, true); + /* X & MODE_MASK can be simplified to (T)X. */ + stmt = SSA_NAME_DEF_STMT (rhs); + if (is_gimple_assign (stmt) + && gimple_assign_rhs_code (stmt) == BIT_AND_EXPR + && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST + && wide_int::from (wi::to_wide (gimple_assign_rhs2 (stmt)), + prec, TYPE_SIGN (TREE_TYPE (rhs))) + == wi::mask (hprec, false, prec)) + *new_rhs_out = gimple_assign_rhs1 (stmt); + else + *new_rhs_out = rhs; + return true; + } + else if (!TYPE_UNSIGNED (type) + && wi::bit_and (bits, wi::mask (hprec - 1, true, prec)) == 0) + { + *type_out = build_nonstandard_integer_type (hprec, false); + *new_rhs_out = rhs; + return true; + } + } + stmt = SSA_NAME_DEF_STMT (rhs); if (is_gimple_assign (stmt)) { - if (! widening_mult_conversion_strippable_p (type, stmt)) - rhs1 = rhs; - else + + if (widening_mult_conversion_strippable_p (type, stmt)) { rhs1 = gimple_assign_rhs1 (stmt); @@ -2568,6 +2604,8 @@ is_widening_mult_rhs_p (tree type, tree rhs, tree *type_out, return true; } } + else + rhs1 = rhs; } else rhs1 = rhs; @@ -2828,20 +2866,24 @@ convert_mult_to_widen (gimple *stmt, gimple_stmt_iterator *gsi) return false; if (actual_precision != TYPE_PRECISION (type1) || from_unsigned1 != TYPE_UNSIGNED (type1)) - rhs1 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned1), rhs1); + type1 = build_nonstandard_integer_type (actual_precision, from_unsigned1); + if (!useless_type_conversion_p (type1, TREE_TYPE (rhs1))) + { + if (TREE_CODE (rhs1) == INTEGER_CST) + rhs1 = fold_convert (type1, rhs1); + else + rhs1 = build_and_insert_cast (gsi, loc, type1, rhs1); + } if (actual_precision != TYPE_PRECISION (type2) || from_unsigned2 != TYPE_UNSIGNED (type2)) - rhs2 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned2), rhs2); - - /* Handle constants. */ - if (TREE_CODE (rhs1) == INTEGER_CST) - rhs1 = fold_convert (type1, rhs1); - if (TREE_CODE (rhs2) == INTEGER_CST) - rhs2 = fold_convert (type2, rhs2); + type2 = build_nonstandard_integer_type (actual_precision, from_unsigned2); + if (!useless_type_conversion_p (type2, TREE_TYPE (rhs2))) + { + if (TREE_CODE (rhs2) == INTEGER_CST) + rhs2 = fold_convert (type2, rhs2); + else + rhs2 = build_and_insert_cast (gsi, loc, type2, rhs2); + } gimple_assign_set_rhs1 (stmt, rhs1); gimple_assign_set_rhs2 (stmt, rhs2); @@ -3044,26 +3086,28 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple *stmt, actual_precision = GET_MODE_PRECISION (actual_mode); if (actual_precision != TYPE_PRECISION (type1) || from_unsigned1 != TYPE_UNSIGNED (type1)) - mult_rhs1 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned1), - mult_rhs1); + type1 = build_nonstandard_integer_type (actual_precision, from_unsigned1); + if (!useless_type_conversion_p (type1, TREE_TYPE (mult_rhs1))) + { + if (TREE_CODE (mult_rhs1) == INTEGER_CST) + mult_rhs1 = fold_convert (type1, mult_rhs1); + else + mult_rhs1 = build_and_insert_cast (gsi, loc, type1, mult_rhs1); + } if (actual_precision != TYPE_PRECISION (type2) || from_unsigned2 != TYPE_UNSIGNED (type2)) - mult_rhs2 = build_and_insert_cast (gsi, loc, - build_nonstandard_integer_type - (actual_precision, from_unsigned2), - mult_rhs2); + type2 = build_nonstandard_integer_type (actual_precision, from_unsigned2); + if (!useless_type_conversion_p (type2, TREE_TYPE (mult_rhs2))) + { + if (TREE_CODE (mult_rhs2) == INTEGER_CST) + mult_rhs2 = fold_convert (type2, mult_rhs2); + else + mult_rhs2 = build_and_insert_cast (gsi, loc, type2, mult_rhs2); + } if (!useless_type_conversion_p (type, TREE_TYPE (add_rhs))) add_rhs = build_and_insert_cast (gsi, loc, type, add_rhs); - /* Handle constants. */ - if (TREE_CODE (mult_rhs1) == INTEGER_CST) - mult_rhs1 = fold_convert (type1, mult_rhs1); - if (TREE_CODE (mult_rhs2) == INTEGER_CST) - mult_rhs2 = fold_convert (type2, mult_rhs2); - gimple_assign_set_rhs_with_ops (gsi, wmult_code, mult_rhs1, mult_rhs2, add_rhs); update_stmt (gsi_stmt (*gsi)); diff --git a/gcc/tree-ssa-pre.cc b/gcc/tree-ssa-pre.cc index e72592d..d29214d 100644 --- a/gcc/tree-ssa-pre.cc +++ b/gcc/tree-ssa-pre.cc @@ -4281,6 +4281,20 @@ compute_avail (function *fun) = wide_int_to_tree (ptr_type_node, wi::to_wide (ref1->op2)); } + /* We also need to make sure that the access path + ends in an access of the same size as otherwise + we might assume an access may not trap while in + fact it might. That's independent of whether + TBAA is in effect. */ + if (TYPE_SIZE (ref1->type) != TYPE_SIZE (ref2->type) + && (! TYPE_SIZE (ref1->type) + || ! TYPE_SIZE (ref2->type) + || ! operand_equal_p (TYPE_SIZE (ref1->type), + TYPE_SIZE (ref2->type)))) + { + operands.release (); + continue; + } operands.release (); result = get_or_alloc_expr_for_reference diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index f0fa718..8792cd0 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -2790,25 +2790,29 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, } else { - tree *saved_last_vuse_ptr = data->last_vuse_ptr; - /* Do not update last_vuse_ptr in vn_reference_lookup_2. */ - data->last_vuse_ptr = NULL; tree saved_vuse = vr->vuse; hashval_t saved_hashcode = vr->hashcode; - void *res = vn_reference_lookup_2 (ref, gimple_vuse (def_stmt), - data); + if (vr->vuse) + vr->hashcode = vr->hashcode - SSA_NAME_VERSION (vr->vuse); + vr->vuse = vuse_ssa_val (gimple_vuse (def_stmt)); + if (vr->vuse) + vr->hashcode = vr->hashcode + SSA_NAME_VERSION (vr->vuse); + vn_reference_t vnresult = NULL; + /* Do not use vn_reference_lookup_2 since that might perform + expression hashtable insertion but this lookup crosses + a possible may-alias making such insertion conditionally + invalid. */ + vn_reference_lookup_1 (vr, &vnresult); /* Need to restore vr->vuse and vr->hashcode. */ vr->vuse = saved_vuse; vr->hashcode = saved_hashcode; - data->last_vuse_ptr = saved_last_vuse_ptr; - if (res && res != (void *)-1) + if (vnresult) { - vn_reference_t vnresult = (vn_reference_t) res; if (TREE_CODE (rhs) == SSA_NAME) rhs = SSA_VAL (rhs); if (vnresult->result && operand_equal_p (vnresult->result, rhs, 0)) - return res; + return vnresult; } } } @@ -7719,12 +7723,15 @@ rpo_elim::eliminate_avail (basic_block bb, tree op) if (SSA_NAME_IS_DEFAULT_DEF (valnum)) return valnum; vn_ssa_aux_t valnum_info = VN_INFO (valnum); - /* See above. */ - if (!valnum_info->visited) - return valnum; vn_avail *av = valnum_info->avail; if (!av) - return NULL_TREE; + { + /* See above. But when there's availability info prefer + what we recorded there for example to preserve LC SSA. */ + if (!valnum_info->visited) + return valnum; + return NULL_TREE; + } if (av->location == bb->index) /* On tramp3d 90% of the cases are here. */ return ssa_name (av->leader); @@ -7769,6 +7776,11 @@ rpo_elim::eliminate_avail (basic_block bb, tree op) av = av->next; } while (av); + /* While we prefer avail we have to fallback to using the value + directly if defined outside of the region when none of the + available defs suit. */ + if (!valnum_info->visited) + return valnum; } else if (valnum != VN_TOP) /* valnum is is_gimple_min_invariant. */ diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index f592aeb..e1679632 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -619,10 +619,10 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, return opt_result::success (); } -/* Funcion vect_analyze_early_break_dependences. +/* Function vect_analyze_early_break_dependences. - Examime all the data references in the loop and make sure that if we have - mulitple exits that we are able to safely move stores such that they become + Examine all the data references in the loop and make sure that if we have + multiple exits that we are able to safely move stores such that they become safe for vectorization. The function also calculates the place where to move the instructions to and computes what the new vUSE chain should be. @@ -639,7 +639,7 @@ vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr, - Multiple loads are allowed as long as they don't alias. NOTE: - This implemementation is very conservative. Any overlappig loads/stores + This implementation is very conservative. Any overlapping loads/stores that take place before the early break statement gets rejected aside from WAR dependencies. @@ -668,7 +668,6 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) auto_vec<data_reference *> bases; basic_block dest_bb = NULL; - hash_set <gimple *> visited; class loop *loop = LOOP_VINFO_LOOP (loop_vinfo); class loop *loop_nest = loop_outer (loop); @@ -677,19 +676,34 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) "loop contains multiple exits, analyzing" " statement dependencies.\n"); + if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)) + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "alternate exit has been chosen as main exit.\n"); + /* Since we don't support general control flow, the location we'll move the side-effects to is always the latch connected exit. When we support - general control flow we can do better but for now this is fine. */ - dest_bb = single_pred (loop->latch); + general control flow we can do better but for now this is fine. Move + side-effects to the in-loop destination of the last early exit. For the + PEELED case we move the side-effects to the latch block as this is + guaranteed to be the last block to be executed when a vector iteration + finished. */ + if (LOOP_VINFO_EARLY_BREAKS_VECT_PEELED (loop_vinfo)) + dest_bb = loop->latch; + else + dest_bb = single_pred (loop->latch); + + /* We start looking from dest_bb, for the non-PEELED case we don't want to + move any stores already present, but we do want to read and validate the + loads. */ basic_block bb = dest_bb; + /* We move stores across all loads to the beginning of dest_bb, so + the first block processed below doesn't need dependence checking. */ + bool check_deps = false; + do { - /* If the destination block is also the header then we have nothing to do. */ - if (!single_pred_p (bb)) - continue; - - bb = single_pred (bb); gimple_stmt_iterator gsi = gsi_last_bb (bb); /* Now analyze all the remaining statements and try to determine which @@ -698,8 +712,7 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) { gimple *stmt = gsi_stmt (gsi); gsi_prev (&gsi); - if (!gimple_has_ops (stmt) - || is_gimple_debug (stmt)) + if (is_gimple_debug (stmt)) continue; stmt_vec_info stmt_vinfo = loop_vinfo->lookup_stmt (stmt); @@ -707,47 +720,25 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) if (!dr_ref) continue; - /* We currently only support statically allocated objects due to - not having first-faulting loads support or peeling for - alignment support. Compute the size of the referenced object - (it could be dynamically allocated). */ - tree obj = DR_BASE_ADDRESS (dr_ref); - if (!obj || TREE_CODE (obj) != ADDR_EXPR) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "early breaks only supported on statically" - " allocated objects.\n"); - return opt_result::failure_at (stmt, - "can't safely apply code motion to " - "dependencies of %G to vectorize " - "the early exit.\n", stmt); - } - - tree refop = TREE_OPERAND (obj, 0); - tree refbase = get_base_address (refop); - if (!refbase || !DECL_P (refbase) || !DECL_SIZE (refbase) - || TREE_CODE (DECL_SIZE (refbase)) != INTEGER_CST) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "early breaks only supported on" - " statically allocated objects.\n"); - return opt_result::failure_at (stmt, - "can't safely apply code motion to " - "dependencies of %G to vectorize " - "the early exit.\n", stmt); - } + /* We know everything below dest_bb is safe since we know we + had a full vector iteration when reaching it. Either by + the loop entry / IV exit test being last or because this + is the loop latch itself. */ + if (!check_deps) + continue; /* Check if vector accesses to the object will be within bounds. must be a constant or assume loop will be versioned or niters - bounded by VF so accesses are within range. */ - if (!ref_within_array_bound (stmt, DR_REF (dr_ref))) + bounded by VF so accesses are within range. We only need to check + the reads since writes are moved to a safe place where if we get + there we know they are safe to perform. */ + if (DR_IS_READ (dr_ref) + && !ref_within_array_bound (stmt, DR_REF (dr_ref))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "early breaks not supported: vectorization " - "would %s beyond size of obj.", + "would %s beyond size of obj.\n", DR_IS_READ (dr_ref) ? "read" : "write"); return opt_result::failure_at (stmt, "can't safely apply code motion to " @@ -781,7 +772,11 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) the store. */ for (auto dr_read : bases) - if (dr_may_alias_p (dr_ref, dr_read, loop_nest)) + /* Note we're not passing the DRs in stmt order here + since the DR dependence checking routine does not + envision we're moving stores down. The read-write + order tricks it to avoid applying TBAA. */ + if (dr_may_alias_p (dr_read, dr_ref, loop_nest)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, @@ -814,13 +809,35 @@ vect_analyze_early_break_dependences (loop_vec_info loop_vinfo) "marked statement for vUSE update: %G", stmt); } } + + if (!single_pred_p (bb)) + { + gcc_assert (bb == loop->header); + break; + } + + /* All earlier blocks need dependence checking. */ + check_deps = true; + bb = single_pred (bb); } - while (bb != loop->header); + while (1); /* We don't allow outer -> inner loop transitions which should have been trapped already during loop form analysis. */ gcc_assert (dest_bb->loop_father == loop); + /* Check that the destination block we picked has only one pred. To relax this we + have to take special care when moving the statements. We don't currently support + such control flow however this check is there to simplify how we handle + labels that may be present anywhere in the IL. This check is to ensure that the + labels aren't significant for the CFG. */ + if (!single_pred (dest_bb)) + return opt_result::failure_at (vect_location, + "chosen loop exit block (BB %d) does not have a " + "single predecessor which is currently not " + "supported for early break vectorization.\n", + dest_bb->index); + LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo) = dest_bb; if (!LOOP_VINFO_EARLY_BRK_VUSES (loop_vinfo).is_empty ()) @@ -4325,6 +4342,11 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo, if (!multiple_p (pbitpos, BITS_PER_UNIT)) return false; + /* We need to be able to form an address to the base which for example + isn't possible for hard registers. */ + if (may_be_nonaddressable_p (base)) + return false; + poly_int64 pbytepos = exact_div (pbitpos, BITS_PER_UNIT); if (TREE_CODE (base) == MEM_REF) @@ -5320,7 +5342,7 @@ vect_create_data_ref_ptr (vec_info *vinfo, stmt_vec_info stmt_info, } while (sinfo); } - aggr_ptr_type = build_pointer_type_for_mode (aggr_type, ptr_mode, + aggr_ptr_type = build_pointer_type_for_mode (aggr_type, VOIDmode, need_ref_all); aggr_ptr = vect_get_new_vect_var (aggr_ptr_type, vect_pointer_var, base_name); diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 30b90d9..190df9e 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -11786,7 +11786,7 @@ move_early_exit_stmts (loop_vec_info loop_vinfo) /* Move all stmts that need moving. */ basic_block dest_bb = LOOP_VINFO_EARLY_BRK_DEST_BB (loop_vinfo); - gimple_stmt_iterator dest_gsi = gsi_start_bb (dest_bb); + gimple_stmt_iterator dest_gsi = gsi_after_labels (dest_bb); for (gimple *stmt : LOOP_VINFO_EARLY_BRK_STORES (loop_vinfo)) { @@ -11800,8 +11800,7 @@ move_early_exit_stmts (loop_vec_info loop_vinfo) dump_printf_loc (MSG_NOTE, vect_location, "moving stmt %G", stmt); gimple_stmt_iterator stmt_gsi = gsi_for_stmt (stmt); - gsi_move_before (&stmt_gsi, &dest_gsi); - gsi_prev (&dest_gsi); + gsi_move_before (&stmt_gsi, &dest_gsi, GSI_NEW_STMT); } /* Update all the stmts with their new reaching VUSES. */ diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index 086377a..7cf9504 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -8987,7 +8987,8 @@ vectorizable_slp_permutation_1 (vec_info *vinfo, gimple_stmt_iterator *gsi, { /* Calculate every element of every permute mask vector explicitly, instead of relying on the pattern described above. */ - if (!nunits.is_constant (&npatterns)) + if (!nunits.is_constant (&npatterns) + || !TYPE_VECTOR_SUBPARTS (op_vectype).is_constant ()) return -1; nelts_per_pattern = ncopies = 1; if (loop_vec_info linfo = dyn_cast <loop_vec_info> (vinfo)) diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc index af6c0e0..a8a6443 100644 --- a/gcc/wide-int.cc +++ b/gcc/wide-int.cc @@ -729,20 +729,19 @@ wi::set_bit_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, } } -/* Byte swap the integer represented by XVAL and LEN into VAL. Return +/* Byte swap the integer represented by XVAL and XLEN into VAL. Return the number of blocks in VAL. Both XVAL and VAL have PRECISION bits. */ unsigned int wi::bswap_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, - unsigned int len, unsigned int precision) + unsigned int xlen, unsigned int precision) { - unsigned int i, s; + unsigned int s, len = BLOCKS_NEEDED (precision); /* This is not a well defined operation if the precision is not a multiple of 8. */ gcc_assert ((precision & 0x7) == 0); - for (i = 0; i < len; i++) - val[i] = 0; + memset (val, 0, sizeof (unsigned HOST_WIDE_INT) * len); /* Only swap the bytes that are not the padding. */ for (s = 0; s < precision; s += 8) @@ -753,7 +752,7 @@ wi::bswap_large (HOST_WIDE_INT *val, const HOST_WIDE_INT *xval, unsigned int block = s / HOST_BITS_PER_WIDE_INT; unsigned int offset = s & (HOST_BITS_PER_WIDE_INT - 1); - byte = (safe_uhwi (xval, len, block) >> offset) & 0xff; + byte = (safe_uhwi (xval, xlen, block) >> offset) & 0xff; block = d / HOST_BITS_PER_WIDE_INT; offset = d & (HOST_BITS_PER_WIDE_INT - 1); @@ -1484,8 +1483,8 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val, } /* We do unsigned mul and then correct it. */ - wi_unpack (u, op1val, op1len, half_blocks_needed, prec, SIGNED); - wi_unpack (v, op2val, op2len, half_blocks_needed, prec, SIGNED); + wi_unpack (u, op1val, op1len, half_blocks_needed, prec, UNSIGNED); + wi_unpack (v, op2val, op2len, half_blocks_needed, prec, UNSIGNED); /* The 2 is for a full mult. */ memset (r, 0, half_blocks_needed * 2 @@ -1504,6 +1503,28 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val, r[j + half_blocks_needed] = k; } + unsigned int shift; + if ((high || needs_overflow) && (shift = prec % HOST_BITS_PER_WIDE_INT) != 0) + { + /* The high or needs_overflow code assumes that the high bits + only appear from r[half_blocks_needed] up to + r[half_blocks_needed * 2 - 1]. If prec is not a multiple + of HOST_BITS_PER_WIDE_INT, shift the bits above prec up + to make that code simple. */ + if (shift == HOST_BITS_PER_HALF_WIDE_INT) + memmove (&r[half_blocks_needed], &r[half_blocks_needed - 1], + sizeof (r[0]) * half_blocks_needed); + else + { + unsigned int skip = shift < HOST_BITS_PER_HALF_WIDE_INT; + if (!skip) + shift -= HOST_BITS_PER_HALF_WIDE_INT; + for (i = 2 * half_blocks_needed - 1; i >= half_blocks_needed; i--) + r[i] = ((r[i - skip] << (-shift % HOST_BITS_PER_HALF_WIDE_INT)) + | (r[i - skip - 1] >> shift)); + } + } + /* We did unsigned math above. For signed we must adjust the product (assuming we need to see that). */ if (sgn == SIGNED && (high || needs_overflow)) @@ -1544,8 +1565,12 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val, top = 0; else { - top = r[(half_blocks_needed) - 1]; - top = SIGN_MASK (top << (HOST_BITS_PER_WIDE_INT / 2)); + top = r[half_blocks_needed - 1 + - ((-prec % HOST_BITS_PER_WIDE_INT) + >= HOST_BITS_PER_HALF_WIDE_INT)]; + top = SIGN_MASK (((unsigned HOST_WIDE_INT) top) + << (HOST_BITS_PER_WIDE_INT / 2 + + (-prec % HOST_BITS_PER_HALF_WIDE_INT))); top &= mask; } |