diff options
author | Gaius Mulley <gaius.mulley@southwales.ac.uk> | 2022-05-30 13:57:52 +0100 |
---|---|---|
committer | Gaius Mulley <gaius.mulley@southwales.ac.uk> | 2022-05-30 13:57:52 +0100 |
commit | 9409a75aa98e6365d0e08ddf9022b44c24c5d758 (patch) | |
tree | 049e69dbccb86902537929694b2b6db51a15cc30 /gcc | |
parent | f17a10fdcf2dfb35a106dbd1e6732d1f8adcb7fe (diff) | |
parent | c89298404071e3b42eb7e2bfbdbaa45573538b53 (diff) | |
download | gcc-9409a75aa98e6365d0e08ddf9022b44c24c5d758.zip gcc-9409a75aa98e6365d0e08ddf9022b44c24c5d758.tar.gz gcc-9409a75aa98e6365d0e08ddf9022b44c24c5d758.tar.bz2 |
Merge branch 'master' into devel/modula-2.
Diffstat (limited to 'gcc')
372 files changed, 10004 insertions, 4502 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b91d393..6434f55 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,636 @@ +2022-05-29 Iain Sandoe <iain@sandoe.co.uk> + + PR target/105599 + * config/darwin.h: Move versions-specific handling of multiply_defined + from SUBTARGET_DRIVER_SELF_SPECS to LINK_SPEC. + +2022-05-29 Eric Gallager <egallager@gcc.gnu.org> + + PR other/82383 + * doc/sourcebuild.texi: Add entries for the c++tools, + gotools, libbacktrace, libcc1, libcody, liboffloadmic, + and libsanitizer directories. Remove entry for boehm-gc. + Fix alphabetization for libquadmath. + +2022-05-28 Joel Holdsworth <jholdsworth@nvidia.com> + + * config/avr/avr-mcus.def: Add device definitions. + * doc/avr-mmcu.texi: Corresponding changes. + * config/avr/gen-avr-mmcu-texi.cc: Added support for avr + device prefix. + * config/avr/gen-avr-mmcu-specs.cc: Prevent -mmcu=avr* flags + from leaking into cc1. + +2022-05-28 Vladimir Makarov <vmakarov@gcc.gnu.org> + + PR target/103722 + * config/sh/sh.cc (sh_register_move_cost): Avoid cost "2" (which + is special) for various scenarios. + +2022-05-28 Iain Sandoe <iain@sandoe.co.uk> + + * config/darwin.h (REAL_LIBGCC_SPEC): Update the comment block + describing this macro. + +2022-05-27 Richard Biener <rguenther@suse.de> + + * tree-dfa.cc (get_ref_base_and_extent): Avoid shift. + +2022-05-27 Martin Jambor <mjambor@suse.cz> + + PR ipa/105639 + * ipa-prop.cc (propagate_controlled_uses): Check type of the + constant before adding a LOAD reference. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + * tree-core.h (enum omp_clause_code): Rename OMP_CLAUSE_TO_DECLARE + to OMP_CLAUSE_ENTER. + * tree.h (OMP_CLAUSE_ENTER_TO): Define. + * tree.cc (omp_clause_num_ops, omp_clause_code_name): Rename + OMP_CLAUSE_TO_DECLARE to OMP_CLAUSE_ENTER. + * tree-pretty-print.cc (dump_omp_clause): Handle OMP_CLAUSE_ENTER + instead of OMP_CLAUSE_TO_DECLARE, if OMP_CLAUSE_ENTER_TO, print + "to" instead of "enter". + * tree-nested.cc (convert_nonlocal_omp_clauses, + convert_local_omp_clauses): Handle OMP_CLAUSE_ENTER instead of + OMP_CLAUSE_TO_DECLARE. + +2022-05-27 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105726 + * gimple-ssa-warn-restrict.cc (builtin_memref::set_base_and_offset): + Constrain array-of-flexarray case more. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/105729 + * fold-const.cc (fold_unary_loc): Don't optimize (X &) ((Y *) z + w) + to (X &) z + w if -fsanitize=null during GENERIC folding. + +2022-05-27 Roger Sayle <roger@nextmovesoftware.com> + + * match.pd (match_zero_one_valued_p): New predicate. + (mult @0 @1): Use zero_one_valued_p for optimization to the + expression "bit_and @0 @1". + (bit_and (negate zero_one_valued_p@0) @1): Optimize to MULT_EXPR. + (plus @0 (mult (minus @1 @0) zero_one_valued_p@2)): New transform. + (minus @0 (mult (minus @0 @1) zero_one_valued_p@2)): Likewise. + (bit_xor @0 (mult (bit_xor @0 @1) zero_one_valued_p@2)): Likewise. + Remove three redundant transforms obsoleted by the three above. + +2022-05-27 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386.md (*test<mode>_not): New define_insn_and_split + to split a combined "and;cmp" sequence into "not;test". + +2022-05-27 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.md (bswapsi2): New expansion pattern. + (bswapsi2_internal): Revise the template and condition, and add + detection code for preceding the same insn in order to omit a + "SSAI 8" instruction of the latter. + (bswapdi2): Suppress built-in insn expansion with the corresponding + library call when optimizing for size. + +2022-05-27 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa-protos.h + (xtensa_expand_block_set_unrolled_loop, + xtensa_expand_block_set_small_loop): New prototypes. + * config/xtensa/xtensa.cc (xtensa_sizeof_MOVI, + xtensa_expand_block_set_unrolled_loop, + xtensa_expand_block_set_small_loop): New functions. + * config/xtensa/xtensa.md (setmemsi): New expansion pattern. + * config/xtensa/xtensa.opt (mlongcalls): Add target mask. + +2022-05-26 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.cc (xtensa_expand_block_move): + Make instruction counting more accurate, and simplify emitting insns. + +2022-05-26 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/constraints.md (M, O): Use the macro. + * config/xtensa/predicates.md (addsubx_operand, extui_fldsz_operand, + sext_fldsz_operand): Ditto. + * config/xtensa/xtensa.cc (xtensa_simm8, xtensa_simm8x256, + xtensa_simm12b, xtensa_uimm8, xtensa_uimm8x2, xtensa_uimm8x4, + xtensa_mask_immediate, smalloffset_mem_p, printx, xtensa_call_save_reg, + xtensa_expand_prologue): Ditto. + * config/xtensa/xtensa.h (FUNCTION_ARG_REGNO_P): Ditto. + +2022-05-26 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/predicates.md (extui_fldsz_operand): Simplify. + * config/xtensa/xtensa.cc (xtensa_mask_immediate, print_operand): + Ditto. + +2022-05-25 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-cache.cc: Adjust comments. + * gimple-range-infer.cc: Adjust comments. + * gimple-range-infer.h: Adjust comments. + * gimple-range.cc: Adjust comments. + +2022-05-25 Andrew MacLeod <amacleod@redhat.com> + + * Makefile.in (OBJS): Use gimple-range-infer.o. + * gimple-range-cache.cc (ranger_cache::fill_block_cache): Change msg. + (ranger_cache::range_from_dom): Rename var side_effect to infer. + (ranger_cache::apply_inferred_ranges): Rename from apply_side_effects. + * gimple-range-cache.h: Include gimple-range-infer.h. + (class ranger_cache): Adjust prototypes, use infer_range_manager. + * gimple-range-infer.cc: Rename from gimple-range-side-effects.cc. + (gimple_infer_range::*): Rename from stmt_side_effects. + (infer_range_manager::*): Rename from side_effect_manager. + * gimple-range-side-effect.cc: Rename. + * gimple-range-side-effect.h: Rename. + * gimple-range-infer.h: Rename from gimple-range-side-effects.h. + (class gimple_infer_range): Rename from stmt_side_effects. + (class infer_range_manager): Rename from side_effect_manager. + * gimple-range.cc (gimple_ranger::register_inferred_ranges): Rename + from register_side_effects. + * gimple-range.h (register_inferred_ranges): Adjust prototype. + * range-op.h: Adjust comment. + * tree-vrp.cc (rvrp_folder::pre_fold_bb): Use register_inferred_ranges. + (rvrp_folder::post_fold_bb): Use register_inferred_ranges. + +2022-05-25 Simon Cook <simon.cook@embecosm.com> + + * config/riscv/arch-canonicalize: Only add mafd extension if + base was rv32/rv64g. + +2022-05-25 Tobias Burnus <tobias@codesourcery.com> + + * doc/invoke.texi (AMD GCN Options): Add gfx908/gfx90a. + +2022-05-25 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/105714 + * asan.cc (has_stmt_been_instrumented_p): For assignments which + are both stores and loads, return true only if both destination + and source have been instrumented. + +2022-05-25 Martin Liska <mliska@suse.cz> + Richard Biener <rguenther@suse.de> + + * dbgcnt.def (DEBUG_COUNTER): Add loop_unswitch counter. + * params.opt (max-unswitch-level): Remove. + * doc/invoke.texi (max-unswitch-level): Likewise. + * tree-cfg.cc (gimple_lv_add_condition_to_bb): Support not + gimplified expressions. + * tree-ssa-loop-unswitch.cc (struct unswitch_predicate): New. + (tree_may_unswitch_on): Rename to ... + (find_unswitching_predicates_for_bb): ... this and handle + switch statements. + (get_predicates_for_bb): Likewise. + (set_predicates_for_bb): Likewise. + (init_loop_unswitch_info): Likewise. + (tree_ssa_unswitch_loops): Prepare stuff before calling + tree_unswitch_single_loop. + (tree_unswitch_single_loop): Rework the function using + pre-computed predicates and with a per original loop cost model. + (merge_last): New. + (add_predicate_to_path): Likewise. + (find_range_for_lhs): Likewise. + (simplify_using_entry_checks): Rename to ... + (evaluate_control_stmt_using_entry_checks): ... this, handle + switch statements and improve simplifications using ranger. + (simplify_loop_version): Rework using + evaluate_control_stmt_using_entry_checks. + (evaluate_bbs): New. + (evaluate_loop_insns_for_predicate): Likewise. + (tree_unswitch_loop): Adjust to allow switch statements and + pass in the edge to unswitch. + (clean_up_after_unswitching): New. + (pass_tree_unswitch::execute): Pass down fun. + +2022-05-24 Eugene Rozenfeld <erozen@microsoft.com> + + * tree-vect-loop-manip.cc (vect_do_peeling): Save/restore profile + counts for the epilog loop. + +2022-05-24 Martin Sebor <msebor@redhat.com> + Richard Biener <rguenther@suse.de> + + PR middle-end/105604 + * gimple-ssa-sprintf.cc (set_aggregate_size_and_offset): Add comments. + (get_origin_and_offset_r): Remove null handling. Handle variable array + sizes. + (get_origin_and_offset): Handle null argument here. Simplify. + (alias_offset): Update comment. + * pointer-query.cc (field_at_offset): Update comment. Handle members + of variable-length types. + +2022-05-24 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> + + * target.def (vec_perm_const): Define new parameter op_mode and + update doc. + * doc/tm.texi: Regenerate. + * config/aarch64/aarch64.cc (aarch64_vectorize_vec_perm_const): Adjust + vec_perm_const hook to add new parameter op_mode and return false + if result and operand modes do not match. + * config/arm/arm.cc (arm_vectorize_vec_perm_const): Likewise. + * config/gcn/gcn.cc (gcn_vectorize_vec_perm_const): Likewise. + * config/ia64/ia64.cc (ia64_vectorize_vec_perm_const): Likewise. + * config/mips/mips.cc (mips_vectorize_vec_perm_const): Likewise. + * config/rs6000/rs6000.cc (rs6000_vectorize_vec_perm_const): Likewise + * config/s390/s390.cc (s390_vectorize_vec_perm_const): Likewise. + * config/sparc/sparc.cc (sparc_vectorize_vec_perm_const): Likewise. + * config/i386/i386-expand.cc (ix86_vectorize_vec_perm_const): Likewise. + * config/i386/i386-expand.h (ix86_vectorize_vec_perm_const): Adjust + prototype. + * config/i386/sse.md (ashrv4di3): Adjust call to vec_perm_const hook. + (ashrv2di3): Likewise. + * optabs.cc (expand_vec_perm_const): Likewise. + * optabs-query.h (can_vec_perm_const_p): Adjust prototype. + * optabs-query.cc (can_vec_perm_const_p): Define new parameter + op_mode and pass it to vec_perm_const hook. + (can_mult_highpart_p): Adjust call to can_vec_perm_const_p. + * match.pd (vec_perm X Y CST): Likewise. + * tree-ssa-forwprop.cc (simplify_vector_constructor): Likewise. + * tree-vect-data-refs.cc (vect_grouped_store_supported): Likewise. + (vect_grouped_load_supported): Likewise. + (vect_shift_permute_load_chain): Likewise. + * tree-vect-generic.cc (lower_vec_perm): Likewise. + * tree-vect-loop-manip.cc (interleave_supported_p): Likewise. + * tree-vect-loop.cc (have_whole_vector_shift): Likewise. + * tree-vect-patterns.cc (vect_recog_rotate_pattern): Likewise. + * tree-vect-slp.cc (can_duplicate_and_interleave_p): Likewise. + (vect_transform_slp_perm_load): Likewise. + (vectorizable_slp_permutation): Likewise. + * tree-vect-stmts.cc (perm_mask_for_reverse): Likewise. + (vectorizable_bswap): Likewise. + (scan_store_can_perm_p): Likewise. + (vect_gen_perm_mask_checked): Likewise. + +2022-05-24 H.J. Lu <hjl.tools@gmail.com> + + PR target/104816 + * config/i386/i386.opt: Remove Undocumented. + * doc/invoke.texi: Document -mcet-switch. + +2022-05-24 Andrew Stubbs <ams@codesourcery.com> + + * config.gcc (amdgcn): Accept --with-arch=gfx908 and gfx90a. + * config/gcn/gcn-opts.h (enum gcn_isa): New. + (TARGET_GCN3): Use enum gcn_isa. + (TARGET_GCN3_PLUS): Likewise. + (TARGET_GCN5): Likewise. + (TARGET_GCN5_PLUS): Likewise. + (TARGET_CDNA1): New. + (TARGET_CDNA1_PLUS): New. + (TARGET_CDNA2): New. + (TARGET_CDNA2_PLUS): New. + (TARGET_M0_LDS_LIMIT): New. + (TARGET_PACKED_WORK_ITEMS): New. + * config/gcn/gcn.cc (gcn_isa): Change to enum gcn_isa. + (gcn_option_override): Recognise CDNA ISA variants. + (gcn_omp_device_kind_arch_isa): Support gfx90a. + (gcn_expand_prologue): Make m0 init optional. + Add support for packed work items. + (output_file_start): Support gfx90a. + (gcn_hsa_declare_function_name): Support gfx90a metadata. + * config/gcn/gcn.h (TARGET_CPU_CPP_BUILTINS):Add __CDNA1__ and + __CDNA2__. + * config/gcn/gcn.md (<su>mulsi3_highpart): Use TARGET_GCN5_PLUS. + (<su>mulsi3_highpart_imm): Likewise. + (<su>mulsidi3): Likewise. + (<su>mulsidi3_imm): Likewise. + * config/gcn/gcn.opt (gpu_type): Add gfx90a. + * config/gcn/mkoffload.cc (EF_AMDGPU_MACH_AMDGCN_GFX90a): New. + (main): Support gfx90a. + * config/gcn/t-gcn-hsa: Add gfx90a multilib. + * config/gcn/t-omp-device: Add gfx90a isa. + +2022-05-24 Andrew Stubbs <ams@codesourcery.com> + + * config.in: Regenerate. + * config/gcn/gcn-hsa.h (X_FIJI): Delete. + (X_900): Delete. + (X_906): Delete. + (X_908): Delete. + (S_FIJI): Delete. + (S_900): Delete. + (S_906): Delete. + (S_908): Delete. + (NO_XNACK): New macro. + (NO_SRAM_ECC): New macro. + (SRAMOPT): Keep only v4 variant. + (HSACO3_SELECT_OPT): Delete. + (DRIVER_SELF_SPECS): Delete. + (ASM_SPEC): Remove LLVM 9 support. + * config/gcn/gcn-valu.md + (gather<mode>_insn_2offsets<exec>): Remove assembler bug workaround. + (scatter<mode>_insn_2offsets<exec_scatter>): Likewise. + * config/gcn/gcn.cc (output_file_start): Remove LLVM 9 support. + (print_operand_address): Remove assembler bug workaround. + * config/gcn/mkoffload.cc (EF_AMDGPU_XNACK_V3): Delete. + (EF_AMDGPU_SRAM_ECC_V3): Delete. + (SET_XNACK_ON): Delete v3 variants. + (SET_XNACK_OFF): Delete v3 variants. + (TEST_XNACK): Delete v3 variants. + (SET_SRAM_ECC_ON): Delete v3 variants. + (SET_SRAM_ECC_ANY): Delete v3 variants. + (SET_SRAM_ECC_OFF): Delete v3 variants. + (SET_SRAM_ECC_UNSUPPORTED): Delete v3 variants. + (TEST_SRAM_ECC_ANY): Delete v3 variants. + (TEST_SRAM_ECC_ON): Delete v3 variants. + (copy_early_debug_info): Remove v3 support. + (main): Remove v3 support. + * configure: Regenerate. + * configure.ac: Replace all GCN feature checks with a version check. + +2022-05-24 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386.md (peephole2): Convert xor;neg;adc;neg, + i.e. a double word negation of a zero extended operand, to + neg;sbb. + +2022-05-24 Roger Sayle <roger@nextmovesoftware.com> + + PR tree-optimization/105668 + * config/i386/i386-expand.cc (ix86_expand_sse_movcc): Support + V1TImode, just like V2DImode. + * config/i386/sse.md (vcond_mask_<mode><sseintvecmodelower>): + Use VI_128 mode iterator instead of VI124_128 to include V2DI. + (vcond_mask_v2div2di): Delete. + (vcond_mask_v1tiv1ti): New define_expand. + +2022-05-24 Roger Sayle <roger@nextmovesoftware.com> + + * genpreds.cc (write_lookup_constraint_1): Avoid generating a call + to strncmp for strings of length one. + +2022-05-24 ShiYulong <shiyulong@iscas.ac.cn> + + * config/riscv/predicates.md (imm5_operand): Add a new operand type for + prefetch instructions. + * config/riscv/riscv-builtins.cc (AVAIL): Add new AVAILs for CMO ISA + Extensions. + (RISCV_ATYPE_SI): New. + (RISCV_ATYPE_DI): New. + * config/riscv/riscv-ftypes.def (0): New. + (1): New. + * config/riscv/riscv.md (riscv_clean_<mode>): New. + (riscv_flush_<mode>): New. + (riscv_inval_<mode>): New. + (riscv_zero_<mode>): New. + (prefetch): New. + (riscv_prefetchi_<mode>): New. + * config/riscv/riscv-cmo.def: New file. + +2022-05-24 ShiYulong <shiyulong@iscas.ac.cn> + + * common/config/riscv/riscv-common.cc: Add zicbom, zicboz, zicbop extensions. + * config/riscv/riscv-opts.h (MASK_ZICBOZ): New. + (MASK_ZICBOM): New. + (MASK_ZICBOP): New. + (TARGET_ZICBOZ): New. + (TARGET_ZICBOM): New. + (TARGET_ZICBOP): New. + * config/riscv/riscv.opt (riscv_zicmo_subext): New. + +2022-05-24 David Malcolm <dmalcolm@redhat.com> + + * tree-vect-slp-patterns.cc: Add "final" and "override" to + vect_pattern::build impls as appropriate. + +2022-05-24 David Malcolm <dmalcolm@redhat.com> + + * ipa-cp.cc: Add "final" and "override" to call_summary_base vfunc + implementations, removing redundant "virtual" as appropriate. + * ipa-fnsummary.h: Likewise. + * ipa-modref.cc: Likewise. + * ipa-param-manipulation.cc: Likewise. + * ipa-profile.cc: Likewise. + * ipa-prop.h: Likewise. + * ipa-pure-const.cc: Likewise. + * ipa-reference.cc: Likewise. + * ipa-sra.cc: Likewise. + * symbol-summary.h: Likewise. + * symtab-thunks.cc: Likewise. + +2022-05-24 Martin Liska <mliska@suse.cz> + + Revert: + 2022-05-24 Martin Liska <mliska@suse.cz> + + * expmed.cc (emit_store_flag_1): Mitigate -Wmaybe-uninitialized + warning. + +2022-05-24 Martin Liska <mliska@suse.cz> + + * expmed.cc (emit_store_flag_1): Mitigate -Wmaybe-uninitialized + warning. + +2022-05-24 Bruno Haible <bruno@clisp.org> + + PR other/105527 + * doc/install.texi (Configuration): Add more details about --with-zstd. + Document --with-zstd-include and --with-zstd-lib + +2022-05-24 Richard Biener <rguenther@suse.de> + + PR middle-end/105711 + * expmed.cc (extract_bit_field_as_subreg): Add op0_mode parameter + and use it. + (extract_bit_field_1): Pass down the mode of op0 to + extract_bit_field_as_subreg. + +2022-05-24 Vineet Gupta <vineetg@rivosinc.com> + + * config/riscv/riscv.cc: (struct riscv_tune_param): Add + fmv_cost. + (rocket_tune_info): Add default fmv_cost 8. + (sifive_7_tune_info): Ditto. + (thead_c906_tune_info): Ditto. + (optimize_size_tune_info): Ditto. + (riscv_register_move_cost): Use fmv_cost for int<->fp moves. + +2022-05-24 Jakub Jelinek <jakub@redhat.com> + + PR c/105378 + * omp-builtins.def (BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT): New + builtin. + * gimplify.cc (gimplify_omp_task): Diagnose taskwait with nowait + clause but no depend clauses. + * omp-expand.cc (expand_taskwait_call): Use + BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT rather than + BUILT_IN_GOMP_TASKWAIT_DEPEND if nowait clause is present. + +2022-05-24 Richard Biener <rguenther@suse.de> + + PR tree-optimization/100221 + * tree-ssa-dse.cc (contains_phi_arg): New function. + (dse_classify_store): Postpone PHI defs that feed another PHI in defs. + +2022-05-24 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105629 + * tree-ssa-phiopt.cc (spaceship_replacement): Allow + a sign-extending conversion. + +2022-05-24 Kewen Lin <linkw@linux.ibm.com> + + PR target/105627 + * config/rs6000/rs6000-p8swap.cc (union_defs): Assert def_insn can't + be a debug insn. + (union_uses): Skip debug use_insn. + +2022-05-23 Vineet Gupta <vineetg@rivosinc.com> + + * config/riscv/predicates.md (const_0_operand): Remove + const_double. + * config/riscv/riscv.cc (riscv_rtx_costs): Add check for + CONST_DOUBLE. + * config/riscv/riscv.h (TARGET_SUPPORTS_WIDE_INT): New define. + +2022-05-23 Mayshao <mayshao-oc@zhaoxin.com> + + * common/config/i386/cpuinfo.h (get_zhaoxin_cpu): Detect + the specific type of Zhaoxin CPU, and return Zhaoxin CPU name. + (cpu_indicator_init): Handle Zhaoxin processors. + * common/config/i386/i386-common.cc: Add lujiazui. + * common/config/i386/i386-cpuinfo.h (enum processor_vendor): Add + VENDOR_ZHAOXIN. + (enum processor_types): Add ZHAOXIN_FAM7H. + (enum processor_subtypes): Add ZHAOXIN_FAM7H_LUJIAZUI. + * config.gcc: Add lujiazui. + * config/i386/cpuid.h (signature_SHANGHAI_ebx): Add + Signatures for zhaoxin + (signature_SHANGHAI_ecx): Ditto. + (signature_SHANGHAI_edx): Ditto. + * config/i386/driver-i386.cc (host_detect_local_cpu): Let + -march=native recognize lujiazui processors. + * config/i386/i386-c.cc (ix86_target_macros_internal): Add lujiazui. + * config/i386/i386-options.cc (m_LUJIAZUI): New_definition. + * config/i386/i386.h (enum processor_type): Ditto. + * config/i386/i386.md: Add lujiazui. + * config/i386/x86-tune-costs.h (struct processor_costs): Add + lujiazui costs. + * config/i386/x86-tune-sched.cc (ix86_issue_rate): Add lujiazui. + (ix86_adjust_cost): Ditto. + * config/i386/x86-tune.def (X86_TUNE_SCHEDULE): Add lujiazui Tunnings. + (X86_TUNE_PARTIAL_REG_DEPENDENCY): Ditto. + (X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY): Ditto. + (X86_TUNE_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY): Ditto. + (X86_TUNE_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY): Ditto. + (X86_TUNE_MOVX): Ditto. + (X86_TUNE_MEMORY_MISMATCH_STALL): Ditto. + (X86_TUNE_FUSE_CMP_AND_BRANCH_32): Ditto. + (X86_TUNE_FUSE_CMP_AND_BRANCH_64): Ditto. + (X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS): Ditto. + (X86_TUNE_FUSE_ALU_AND_BRANCH): Ditto. + (X86_TUNE_ACCUMULATE_OUTGOING_ARGS): Ditto. + (X86_TUNE_USE_LEAVE): Ditto. + (X86_TUNE_PUSH_MEMORY): Ditto. + (X86_TUNE_LCP_STALL): Ditto. + (X86_TUNE_USE_INCDEC): Ditto. + (X86_TUNE_INTEGER_DFMODE_MOVES): Ditto. + (X86_TUNE_OPT_AGU): Ditto. + (X86_TUNE_PREFER_KNOWN_REP_MOVSB_STOSB): Ditto. + (X86_TUNE_MISALIGNED_MOVE_STRING_PRO_EPILOGUES): Ditto. + (X86_TUNE_USE_SAHF): Ditto. + (X86_TUNE_USE_BT): Ditto. + (X86_TUNE_AVOID_FALSE_DEP_FOR_BMI): Ditto. + (X86_TUNE_ONE_IF_CONV_INSN): Ditto. + (X86_TUNE_AVOID_MFENCE): Ditto. + (X86_TUNE_EXPAND_ABS): Ditto. + (X86_TUNE_USE_SIMODE_FIOP): Ditto. + (X86_TUNE_USE_FFREEP): Ditto. + (X86_TUNE_EXT_80387_CONSTANTS): Ditto. + (X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL): Ditto. + (X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL): Ditto. + (X86_TUNE_SSE_TYPELESS_STORES): Ditto. + (X86_TUNE_SSE_LOAD0_BY_PXOR): Ditto. + * doc/extend.texi: Add details about lujiazui. + * doc/invoke.texi: Add details about lujiazui. + * config/i386/lujiazui.md: Introduce lujiazui cpu and include new md file. + +2022-05-23 Martin Liska <mliska@suse.cz> + + * config/tilepro/gen-mul-tables.cc (ARRAY_SIZE): Add new macro. + +2022-05-23 Richard Biener <rguenther@suse.de> + + * tree-ssa-forwprop.cc (forward_propagate_into_cond): Remove. + (pass_forwprop::execute): Do not propagate into COND_EXPR conditions. + +2022-05-23 Richard Biener <rguenther@suse.de> + + * gimple-expr.cc (is_gimple_condexpr): Remove. + * gimple-expr.h (is_gimple_condexpr): Likewise. + * gimplify.cc (gimplify_expr): Remove is_gimple_condexpr usage. + * tree-if-conv.cc (set_bb_predicate): Likewie. + (add_to_predicate_list): Likewise. + (gen_phi_arg_condition): Likewise. + (predicate_scalar_phi): Likewise. + (predicate_statements): Likewise. + +2022-05-23 Richard Biener <rguenther@suse.de> + + * gimple-expr.cc (is_gimple_condexpr): Equate to is_gimple_val. + * gimplify.cc (gimplify_pure_cond_expr): Gimplify the condition + as is_gimple_val. + * gimple-fold.cc (valid_gimple_rhs_p): Simplify. + * tree-cfg.cc (verify_gimple_assign_ternary): Likewise. + * gimple-loop-interchange.cc (loop_cand::undo_simple_reduction): + Build the condition of the COND_EXPR separately. + * tree-ssa-loop-im.cc (move_computations_worker): Likewise. + * tree-vect-generic.cc (expand_vector_condition): Likewise. + * tree-vect-loop.cc (vect_create_epilog_for_reduction): + Likewise. + * vr-values.cc (simplify_using_ranges::simplify): Likewise. + * tree-vect-patterns.cc: Add comment indicating we are + building invalid COND_EXPRs and why. + * omp-expand.cc (expand_omp_simd): Gimplify the condition + to the COND_EXPR separately. + (expand_omp_atomic_cas): Note part that should be unreachable + now. + * tree-ssa-forwprop.cc (forward_propagate_into_cond): Adjust + condition for valid replacements. + * tree-if-conv.cc (predicate_bbs): Simulate previous + re-folding of the condition in folded COND_EXPRs which + is necessary because of unfolded GIMPLE_CONDs in the IL + as in for example gcc.dg/fold-bopcond-1.c. + * gimple-range-gori.cc (gori_compute::condexpr_adjust): + Handle that the comparison is now in the def stmt of + the select operand. Required by gcc.dg/pr104526.c. + +2022-05-23 Tobias Burnus <tobias@codesourcery.com> + + PR fortran/104949 + * langhooks-def.h (lhd_omp_array_size): New. + (LANG_HOOKS_OMP_ARRAY_SIZE): Define. + (LANG_HOOKS_DECLS): Add it. + * langhooks.cc (lhd_omp_array_size): New. + * langhooks.h (struct lang_hooks_for_decls): Add hook. + * omp-low.cc (scan_sharing_clauses, lower_omp_target): + Handle GOMP_MAP_FIRSTPRIVATE for array descriptors. + +2022-05-23 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386.cc (ix86_rtx_costs) <case AND>: Split from + XOR/IOR case. Account for two instructions for double-word + operations. In case of vector pandn, account for single + instruction. Likewise for integer andn with TARGET_BMI. + <case NOT>: Vector NOT requires more than 1 instruction (pxor). + <case NEG>: Double-word negation requires 3 instructions. + +2022-05-23 Tsukasa OI <research_trasio@irq.a4lg.com> + + * common/config/riscv/riscv-common.cc (riscv_supported_std_ext): + Fix "K" extension prefix to be placed before "J". + * config/riscv/arch-canonicalize: Likewise. + +2022-05-23 liuhongt <hongtao.liu@intel.com> + + * config/i386/x86-tune-costs.h (skylake_cost): Increase gpr + <-> mask cost from 5 to 6. + (icelake_cost): Ditto. + 2022-05-20 Wilco Dijkstra <wilco.dijkstra@arm.com> * config/aarch64/aarch64.md diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 9cf4f57..158b96c 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220523 +20220530 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 97e5450..731d8dd 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1410,7 +1410,7 @@ OBJS = \ gimple-range-edge.o \ gimple-range-fold.o \ gimple-range-gori.o \ - gimple-range-side-effect.o \ + gimple-range-infer.o \ gimple-range-trace.o \ gimple-ssa-backprop.o \ gimple-ssa-evrp.o \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 0a766f2..1e578c1 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,11 @@ +2022-05-28 Alexandre Oliva <oliva@adacore.com> + + * gcc-interface/Makefile.in (OSCONS_CC): Rename to... + (GCC_FOR_ADA_RTS): ... this. Adjust users. + (gnatlib): Pass it down as CC. + (gnatlib-shared-default): Likewise. + (gnatlib-shared-win32, gnatlib-shared-darwin): Likewise. + 2022-05-19 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/decl.cc (gnat_to_gnu_entity) <E_Constant>: Deal with diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl index ed3d334..8812d15 100644 --- a/gcc/ada/Makefile.rtl +++ b/gcc/ada/Makefile.rtl @@ -749,6 +749,8 @@ GNATRTL_NONTASKING_OBJS= \ s-shasto$(objext) \ s-soflin$(objext) \ s-soliin$(objext) \ + s-spark$(objext) \ + s-spcuop$(objext) \ s-spsufi$(objext) \ s-stache$(objext) \ s-stalib$(objext) \ diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb index 3b55cc9..c70268d 100644 --- a/gcc/ada/bindgen.adb +++ b/gcc/ada/bindgen.adb @@ -311,8 +311,11 @@ package body Bindgen is procedure Gen_CodePeer_Wrapper; -- For CodePeer, generate wrapper which calls user-defined main subprogram + procedure Gen_CUDA_Defs; + -- Generate definitions needed in order to register kernels + procedure Gen_CUDA_Init; - -- When CUDA registration code is needed. + -- Generate calls needed in order to register kernels procedure Gen_Elab_Calls (Elab_Order : Unit_Id_Array); -- Generate sequence of elaboration calls @@ -1115,6 +1118,8 @@ package body Bindgen is WBI (""); end if; + Gen_CUDA_Init; + Gen_Elab_Calls (Elab_Order); if not CodePeer_Mode then @@ -1221,10 +1226,10 @@ package body Bindgen is end Gen_Bind_Env_String; ------------------- - -- Gen_CUDA_Init -- + -- Gen_CUDA_Defs -- ------------------- - procedure Gen_CUDA_Init is + procedure Gen_CUDA_Defs is Unit_Name : constant String := Get_Name_String (Units.Table (First_Unit_Entry).Uname); Unit : constant String := @@ -1237,7 +1242,7 @@ package body Bindgen is WBI (""); WBI (" "); - WBI (" function CUDA_Register_Function"); + WBI (" procedure CUDA_Register_Function"); WBI (" (Fat_Binary_Handle : System.Address;"); WBI (" Func : System.Address;"); WBI (" Kernel_Name : Interfaces.C.Strings.chars_ptr;"); @@ -1247,7 +1252,7 @@ package body Bindgen is WBI (" Nullptr2 : System.Address;"); WBI (" Nullptr3 : System.Address;"); WBI (" Nullptr4 : System.Address;"); - WBI (" Nullptr5 : System.Address) return Boolean;"); + WBI (" Nullptr5 : System.Address);"); WBI (" pragma Import"); WBI (" (Convention => C,"); WBI (" Entity => CUDA_Register_Function,"); @@ -1261,8 +1266,8 @@ package body Bindgen is WBI (" Entity => CUDA_Register_Fat_Binary,"); WBI (" External_Name => ""__cudaRegisterFatBinary"");"); WBI (""); - WBI (" function CUDA_Register_Fat_Binary_End"); - WBI (" (Fat_Binary : System.Address) return Boolean;"); + WBI (" procedure CUDA_Register_Fat_Binary_End"); + WBI (" (Fat_Binary : System.Address);"); WBI (" pragma Import"); WBI (" (Convention => C,"); WBI (" Entity => CUDA_Register_Fat_Binary_End,"); @@ -1287,8 +1292,7 @@ package body Bindgen is WBI (" Fat_Binary'Address,"); WBI (" System.Null_Address);"); WBI (""); - WBI (" Fat_Binary_Handle : System.Address :="); - WBI (" CUDA_Register_Fat_Binary (Wrapper'Address);"); + WBI (" Fat_Binary_Handle : System.Address;"); WBI (""); for K in CUDA_Kernels.First .. CUDA_Kernels.Last loop @@ -1300,9 +1304,9 @@ package body Bindgen is -- K_Symbol is a unique identifier used to derive all symbol names -- related to kernel K. - Kernel_Addr : constant String := Kernel_Symbol & "_Addr"; - -- Kernel_Addr is the name of the symbol representing the address - -- of the host-side procedure of the kernel. The address is + Kernel_Proc : constant String := Kernel_Symbol & "_Proc"; + -- Kernel_Proc is the name of the symbol representing the + -- host-side procedure of the kernel. The address is -- pragma-imported and then used while registering the kernel with -- the CUDA runtime. Kernel_String : constant String := Kernel_Symbol & "_String"; @@ -1315,40 +1319,80 @@ package body Bindgen is begin -- Import host-side kernel address. - WBI (" " & Kernel_Addr & " : constant System.Address;"); + WBI (" procedure " & Kernel_Proc & ";"); WBI (" pragma Import"); WBI (" (Convention => C,"); - WBI (" Entity => " & Kernel_Addr & ","); + WBI (" Entity => " & Kernel_Proc & ","); WBI (" External_Name => """ & Kernel_Name & """);"); WBI (""); -- Generate C-string containing name of kernel. WBI - (" " & Kernel_String & " : Interfaces.C.Strings.Chars_Ptr :="); - WBI (" Interfaces.C.Strings.New_Char_Array (""" - & Kernel_Name - & """);"); + (" " & Kernel_String & " : Interfaces.C.Strings.Chars_Ptr;"); WBI (""); + end; + end loop; + + WBI (""); + end Gen_CUDA_Defs; + + ------------------- + -- Gen_CUDA_Init -- + ------------------- + + procedure Gen_CUDA_Init is + begin + if not Enable_CUDA_Expansion then + return; + end if; + + WBI (" Fat_Binary_Handle :="); + WBI (" CUDA_Register_Fat_Binary (Wrapper'Address);"); + + for K in CUDA_Kernels.First .. CUDA_Kernels.Last loop + declare + K_String : constant String := CUDA_Kernel_Id'Image (K); + N : constant String := + K_String (K_String'First + 1 .. K_String'Last); + Kernel_Symbol : constant String := "Kernel_" & N; + -- K_Symbol is a unique identifier used to derive all symbol names + -- related to kernel K. + + Kernel_Proc : constant String := Kernel_Symbol & "_Proc"; + -- Kernel_Proc is the name of the symbol representing the + -- host-side procedure of the kernel. The address is + -- pragma-imported and then used while registering the kernel with + -- the CUDA runtime. + Kernel_String : constant String := Kernel_Symbol & "_String"; + -- Kernel_String is the name of the C-string containing the name + -- of the kernel. It is used for registering the kernel with the + -- CUDA runtime. + Kernel_Name : constant String := + Get_Name_String (CUDA_Kernels.Table (K).Kernel_Name); + -- Kernel_Name is the name of the kernel, after package expansion. + begin + WBI (" " & Kernel_String & " :="); + WBI (" Interfaces.C.Strings.New_Char_Array (""" + & Kernel_Name + & """);"); -- Generate call to CUDA runtime to register function. - WBI (" CUDA_Register" & N & " : Boolean :="); - WBI (" CUDA_Register_Function ("); - WBI (" Fat_Binary_Handle, "); - WBI (" " & Kernel_Addr & ","); - WBI (" " & Kernel_String & ","); - WBI (" " & Kernel_String & ","); - WBI (" -1,"); - WBI (" System.Null_Address,"); - WBI (" System.Null_Address,"); - WBI (" System.Null_Address,"); - WBI (" System.Null_Address,"); - WBI (" System.Null_Address);"); + WBI (" CUDA_Register_Function ("); + WBI (" Fat_Binary_Handle, "); + WBI (" " & Kernel_Proc & "'Address,"); + WBI (" " & Kernel_String & ","); + WBI (" " & Kernel_String & ","); + WBI (" -1,"); + WBI (" System.Null_Address,"); + WBI (" System.Null_Address,"); + WBI (" System.Null_Address,"); + WBI (" System.Null_Address,"); + WBI (" System.Null_Address);"); WBI (""); end; end loop; - WBI (" CUDA_End : Boolean := "); - WBI (" CUDA_Register_Fat_Binary_End(Fat_Binary_Handle);"); + WBI (" CUDA_Register_Fat_Binary_End (Fat_Binary_Handle);"); end Gen_CUDA_Init; -------------------------- @@ -2619,7 +2663,7 @@ package body Bindgen is Get_Main_Name & """);"); end if; - Gen_CUDA_Init; + Gen_CUDA_Defs; -- Generate version numbers for units, only if needed. Be very safe on -- the condition. diff --git a/gcc/ada/doc/gnat_rm/implementation_advice.rst b/gcc/ada/doc/gnat_rm/implementation_advice.rst index e7649b0..f2f34db 100644 --- a/gcc/ada/doc/gnat_rm/implementation_advice.rst +++ b/gcc/ada/doc/gnat_rm/implementation_advice.rst @@ -353,12 +353,6 @@ then values of the type are implicitly initialized to zero. This happens both for objects of the packed type, and for objects that have a subcomponent of the packed type. - - "An implementation should support Address clauses for imported - subprograms." - -Followed. - .. index:: Address clauses RM 13.3(14-19): Address Clauses diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index 8c4c1f6..0631a53 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -31,9 +31,10 @@ option, to affect all subprograms in a compilation, and with a -- Before returning, Bar scrubs all call-clobbered registers. -For usage and more details on the command-line option, and on the -``zero_call_used_regs`` attribute, see :title:`Using the GNU Compiler -Collection (GCC)`. +For usage and more details on the command-line option, on the +``zero_call_used_regs`` attribute, and on their use with other +programming languages, see :title:`Using the GNU Compiler Collection +(GCC)`. .. Stack Scrubbing: @@ -44,14 +45,17 @@ Stack Scrubbing GNAT can generate code to zero-out stack frames used by subprograms. It can be activated with the :samp:`Machine_Attribute` pragma, on -specific subprograms and variables. +specific subprograms and variables, or their types. (This attribute +always applies to a type, even when it is associated with a subprogram +or a variable.) .. code-block:: ada function Foo returns Integer; pragma Machine_Attribute (Foo, "strub"); -- Foo and its callers are modified so as to scrub the stack - -- space used by Foo after it returns. + -- space used by Foo after it returns. Shorthand for: + -- pragma Machine_Attribute (Foo, "strub", "at-calls"); procedure Bar; pragma Machine_Attribute (Bar, "strub", "internal"); @@ -61,13 +65,16 @@ specific subprograms and variables. Var : Integer; pragma Machine_Attribute (Var, "strub"); -- Reading from Var in a subprogram enables stack scrubbing - -- of the stack space used by the subprogram. + -- of the stack space used by the subprogram. Furthermore, if + -- Var is declared within a subprogram, this also enables + -- scrubbing of the stack space used by that subprogram. There are also :switch:`-fstrub` command-line options to control default settings. For usage and more details on the command-line -option, and on the ``strub`` attribute, see :title:`Using the GNU -Compiler Collection (GCC)`. +option, on the ``strub`` attribute, and their use with other +programming languages, see :title:`Using the GNU Compiler Collection +(GCC)`. Note that Ada secondary stacks are not scrubbed. The restriction ``No_Secondary_Stack`` avoids their use, and thus their accidental @@ -81,16 +88,19 @@ access type designates a non-strub type. .. code-block:: ada - VI : Integer; + VI : aliased Integer; + pragma Machine_Attribute (VI, "strub"); XsVI : access Integer := VI'Access; -- Error. UXsVI : access Integer := VI'Unchecked_Access; -- OK, - -- UXsVI.all does not enable strub in the enclosing subprogram. + -- UXsVI does *not* enable strub in subprograms that + -- dereference it to obtain the UXsVI.all value. type Strub_Int is new Integer; pragma Machine_Attribute (Strub_Int, "strub"); - VSI : Strub_Int; - XsVSI : access Strub_Int := VSI'Access; -- OK. - -- XsVSI.all enables strub in the enclosing subprogram. + VSI : aliased Strub_Int; + XsVSI : access Strub_Int := VSI'Access; -- OK, + -- VSI and XsVSI.all both enable strub in subprograms that + -- read their values. Every access-to-subprogram type, renaming, and overriding and @@ -108,6 +118,9 @@ turned ``callable`` through such an explicit conversion: type TBar_Callable is access procedure; pragma Machine_Attribute (TBar_Callable, "strub", "callable"); + -- The attribute modifies the procedure type, rather than the + -- access type, because of the extra argument after "strub", + -- only applicable to subprogram types. Bar_Callable_Ptr : constant TBar_Callable := TBar_Callable (TBar'(Bar'Access)); @@ -115,6 +128,7 @@ turned ``callable`` through such an explicit conversion: procedure Bar_Callable renames Bar_Callable_Ptr.all; pragma Machine_Attribute (Bar_Callable, "strub", "callable"); + Note that the renaming declaration is expanded to a full subprogram body, it won't be just an alias. Only if it is inlined will it be as efficient as a call by dereferencing the access-to-subprogram constant @@ -162,6 +176,10 @@ respectively. They are separate options, however, because of the significantly different performance impact of the hardening transformations. +For usage and more details on the command-line options, see +:title:`Using the GNU Compiler Collection (GCC)`. These options can +be used with other programming languages supported by GCC. + .. Hardened Booleans: @@ -177,6 +195,7 @@ alternative representations, using representation clauses: for HBool use (16#5a#, 16#a5#); for HBool'Size use 8; + When validity checking is enabled, the compiler will check that variables of such types hold values corresponding to the selected representations. @@ -196,8 +215,14 @@ checked even when compiling with :switch:`-gnatVT`. pragma Machine_Attribute (HBool, "hardbool"); + Note that :switch:`-gnatVn` will disable even ``hardbool`` testing. +Analogous behavior is available as a GCC extension to the C and +Objective C programming languages, through the ``hardbool`` attribute. +For usage and more details on that attribute, see :title:`Using the +GNU Compiler Collection (GCC)`. + .. Control Flow Redundancy: @@ -243,3 +268,7 @@ disabled altogether. The instrumentation for hardening with control flow redundancy can be observed in dump files generated by the command-line option :switch:`-fdump-tree-hardcfr`. + +For more details on the control flow redundancy command-line options, +see :title:`Using the GNU Compiler Collection (GCC)`. These options +can be used with other programming languages supported by GCC. diff --git a/gcc/ada/errout.adb b/gcc/ada/errout.adb index 101aed4..8658c38 100644 --- a/gcc/ada/errout.adb +++ b/gcc/ada/errout.adb @@ -2170,6 +2170,9 @@ package body Errout is -- Do not print continuations messages as children of the current -- message if the current message is a continuation message. + Option : constant String := Get_Warning_Option (E); + -- The option that triggered this message. + -- Start of processing for Output_JSON_Message begin @@ -2197,9 +2200,16 @@ package body Errout is Write_Str ("}"); end if; + Write_Str ("]"); + + -- Print message option, if there is one + if Option /= "" then + Write_Str (",""option"":""" & Option & """"); + end if; + -- Print message content - Write_Str ("],""message"":"""); + Write_Str (",""message"":"""); Write_JSON_Escaped_String (Errors.Table (E).Text); Write_Str (""""); diff --git a/gcc/ada/erroutc.adb b/gcc/ada/erroutc.adb index 866294e..cab7fec 100644 --- a/gcc/ada/erroutc.adb +++ b/gcc/ada/erroutc.adb @@ -359,6 +359,26 @@ package body Erroutc is return Cur_Msg; end Get_Msg_Id; + ------------------------ + -- Get_Warning_Option -- + ------------------------ + + function Get_Warning_Option (Id : Error_Msg_Id) return String is + Warn : constant Boolean := Errors.Table (Id).Warn; + Warn_Chr : constant String (1 .. 2) := Errors.Table (Id).Warn_Chr; + begin + if Warn and then Warn_Chr /= " " and then Warn_Chr (1) /= '?' then + if Warn_Chr = "$ " then + return "-gnatel"; + elsif Warn_Chr (2) = ' ' then + return "-gnatw" & Warn_Chr (1); + else + return "-gnatw" & Warn_Chr; + end if; + end if; + return ""; + end Get_Warning_Option; + --------------------- -- Get_Warning_Tag -- --------------------- @@ -366,22 +386,19 @@ package body Erroutc is function Get_Warning_Tag (Id : Error_Msg_Id) return String is Warn : constant Boolean := Errors.Table (Id).Warn; Warn_Chr : constant String (1 .. 2) := Errors.Table (Id).Warn_Chr; + Option : constant String := Get_Warning_Option (Id); begin - if Warn and then Warn_Chr /= " " then + if Warn then if Warn_Chr = "? " then return "[enabled by default]"; elsif Warn_Chr = "* " then return "[restriction warning]"; - elsif Warn_Chr = "$ " then - return "[-gnatel]"; - elsif Warn_Chr (2) = ' ' then - return "[-gnatw" & Warn_Chr (1) & ']'; - else - return "[-gnatw" & Warn_Chr & ']'; + elsif Option /= "" then + return "[" & Option & "]"; end if; - else - return ""; end if; + + return ""; end Get_Warning_Tag; ------------- diff --git a/gcc/ada/erroutc.ads b/gcc/ada/erroutc.ads index be8755b..7957228 100644 --- a/gcc/ada/erroutc.ads +++ b/gcc/ada/erroutc.ads @@ -493,6 +493,10 @@ package Erroutc is -- Returns the number of warnings in the Errors table that were triggered -- by a Compile_Time_Warning pragma. + function Get_Warning_Option (Id : Error_Msg_Id) return String; + -- Returns the warning switch causing this warning message or an empty + -- string is there is none.. + function Get_Warning_Tag (Id : Error_Msg_Id) return String; -- Given an error message ID, return tag showing warning message class, or -- the null string if this option is not enabled or this is not a warning. diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index 13be987..4828406 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -8474,11 +8474,21 @@ package body Exp_Aggr is Parent_Name : Node_Id; begin - -- Remove the inherited component association from the - -- aggregate and store them in the parent aggregate - First_Comp := First (Component_Associations (N)); Parent_Comps := New_List; + + -- First skip the discriminants + + while Present (First_Comp) + and then Ekind (Entity (First (Choices (First_Comp)))) + = E_Discriminant + loop + Next (First_Comp); + end loop; + + -- Then remove the inherited component association from the + -- aggregate and store them in the parent aggregate + while Present (First_Comp) and then Scope (Original_Record_Component diff --git a/gcc/ada/exp_ch11.adb b/gcc/ada/exp_ch11.adb index c61f154..c60fe34 100644 --- a/gcc/ada/exp_ch11.adb +++ b/gcc/ada/exp_ch11.adb @@ -1350,37 +1350,19 @@ package body Exp_Ch11 is -- in -- raise Constraint_Error; - -- unless the flag Convert_To_Return_False is set, in which case - -- the transformation is to: - - -- do - -- return False; - -- in - -- raise Constraint_Error; - -- The raise constraint error can never be executed. It is just a dummy -- node that can be labeled with an arbitrary type. RCE := Make_Raise_Constraint_Error (Loc, Reason => CE_Explicit_Raise); Set_Etype (RCE, Typ); - if Convert_To_Return_False (N) then - Rewrite (N, - Make_Expression_With_Actions (Loc, - Actions => New_List ( - Make_Simple_Return_Statement (Loc, - Expression => New_Occurrence_Of (Standard_False, Loc))), - Expression => RCE)); - - else - Rewrite (N, - Make_Expression_With_Actions (Loc, - Actions => New_List ( - Make_Raise_Statement (Loc, - Name => Name (N), - Expression => Expression (N))), - Expression => RCE)); - end if; + Rewrite (N, + Make_Expression_With_Actions (Loc, + Actions => New_List ( + Make_Raise_Statement (Loc, + Name => Name (N), + Expression => Expression (N))), + Expression => RCE)); Analyze_And_Resolve (N, Typ); end Expand_N_Raise_Expression; diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index 4216fec..87a84b4 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -6909,9 +6909,9 @@ package body Exp_Ch3 is begin if Is_Concurrent_Type (Base_Typ) then - New_Nodes := Make_DT (Corresponding_Record_Type (Base_Typ), N); + New_Nodes := Make_DT (Corresponding_Record_Type (Base_Typ)); else - New_Nodes := Make_DT (Base_Typ, N); + New_Nodes := Make_DT (Base_Typ); end if; Insert_List_Before (N, New_Nodes); diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 44d1987..7d50727 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -3298,19 +3298,33 @@ package body Exp_Ch6 is Variant_Prag : constant Node_Id := Get_Pragma (Current_Scope, Pragma_Subprogram_Variant); + Pragma_Arg1 : Node_Id; Variant_Proc : Entity_Id; begin if Present (Variant_Prag) and then Is_Checked (Variant_Prag) then - -- Analysis of the pragma rewrites its argument with a reference - -- to the internally generated procedure. + Pragma_Arg1 := + Expression (First (Pragma_Argument_Associations (Variant_Prag))); - Variant_Proc := - Entity - (Expression - (First - (Pragma_Argument_Associations (Variant_Prag)))); + -- If pragma parameter is still an aggregate, it comes from a + -- structural variant, which is not expanded and ignored for + -- run-time execution. + + if Nkind (Pragma_Arg1) = N_Aggregate then + pragma Assert + (Chars + (First + (Choices + (First (Component_Associations (Pragma_Arg1))))) = + Name_Structural); + return; + end if; + + -- Otherwise, analysis of the pragma rewrites its argument with a + -- reference to the internally generated procedure. + + Variant_Proc := Entity (Pragma_Arg1); Insert_Action (Call_Node, Make_Procedure_Call_Statement (Loc, diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb index bb6712d..d611d0e 100644 --- a/gcc/ada/exp_ch7.adb +++ b/gcc/ada/exp_ch7.adb @@ -341,8 +341,8 @@ package body Exp_Ch7 is -- Build_Finalizer. procedure Build_Finalizer_Call (N : Node_Id; Fin_Id : Entity_Id); - -- N is a construct which contains a handled sequence of statements, Fin_Id - -- is the entity of a finalizer. Create an At_End handler which covers the + -- N is a construct that contains a handled sequence of statements, Fin_Id + -- is the entity of a finalizer. Create an At_End handler that covers the -- statements of N and calls Fin_Id. If the handled statement sequence has -- an exception handler, the statements will be wrapped in a block to avoid -- unwanted interaction with the new At_End handler. @@ -3722,7 +3722,7 @@ package body Exp_Ch7 is -- which belongs to a protected type. Loc : constant Source_Ptr := Sloc (N); - HSS : Node_Id; + HSS : Node_Id := Handled_Statement_Sequence (N); begin -- Do not perform this expansion in SPARK mode because we do not create @@ -3732,13 +3732,8 @@ package body Exp_Ch7 is return; end if; - -- The At_End handler should have been assimilated by the finalizer - - HSS := Handled_Statement_Sequence (N); - pragma Assert (No (At_End_Proc (HSS))); - -- If the construct to be cleaned up is a protected subprogram body, the - -- finalizer call needs to be associated with the block which wraps the + -- finalizer call needs to be associated with the block that wraps the -- unprotected version of the subprogram. The following illustrates this -- scenario: @@ -3760,27 +3755,9 @@ package body Exp_Ch7 is if Is_Prot_Body then HSS := Handled_Statement_Sequence (Last (Statements (HSS))); - - -- An At_End handler and regular exception handlers cannot coexist in - -- the same statement sequence. Wrap the original statements in a block. - - elsif Present (Exception_Handlers (HSS)) then - declare - End_Lab : constant Node_Id := End_Label (HSS); - Block : Node_Id; - - begin - Block := - Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS); - - Set_Handled_Statement_Sequence (N, - Make_Handled_Sequence_Of_Statements (Loc, New_List (Block))); - - HSS := Handled_Statement_Sequence (N); - Set_End_Label (HSS, End_Lab); - end; end if; + pragma Assert (No (At_End_Proc (HSS))); Set_At_End_Proc (HSS, New_Occurrence_Of (Fin_Id, Loc)); -- Attach reference to finalizer to tree, for LLVM use @@ -5568,10 +5545,10 @@ package body Exp_Ch7 is procedure Expand_Cleanup_Actions (N : Node_Id) is pragma Assert (Nkind (N) in N_Block_Statement - | N_Entry_Body - | N_Extended_Return_Statement | N_Subprogram_Body - | N_Task_Body); + | N_Task_Body + | N_Entry_Body + | N_Extended_Return_Statement); Scop : constant Entity_Id := Current_Scope; @@ -5639,18 +5616,14 @@ package body Exp_Ch7 is ----------------------- procedure Wrap_HSS_In_Block is - Block : Node_Id; - Block_Id : Entity_Id; - End_Lab : Node_Id; - - begin - -- Preserve end label to provide proper cross-reference information - - End_Lab := End_Label (HSS); - Block := + Block : constant Node_Id := Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS); + Block_Id : constant Entity_Id := + New_Internal_Entity (E_Block, Current_Scope, Loc, 'B'); + End_Lab : constant Node_Id := End_Label (HSS); + -- Preserve end label to provide proper cross-reference information - Block_Id := New_Internal_Entity (E_Block, Current_Scope, Loc, 'B'); + begin Set_Identifier (Block, New_Occurrence_Of (Block_Id, Loc)); Set_Etype (Block_Id, Standard_Void_Type); Set_Block_Node (Block_Id, Identifier (Block)); @@ -5660,14 +5633,11 @@ package body Exp_Ch7 is Set_Is_Finalization_Wrapper (Block); - Set_Handled_Statement_Sequence (N, - Make_Handled_Sequence_Of_Statements (Loc, New_List (Block))); - HSS := Handled_Statement_Sequence (N); - + HSS := Make_Handled_Sequence_Of_Statements (Loc, + Statements => New_List (Block), + End_Label => End_Lab); Set_First_Real_Statement (HSS, Block); - Set_End_Label (HSS, End_Lab); - - -- Comment needed here, see RH for 1.306 ??? + Set_Handled_Statement_Sequence (N, HSS); if Nkind (N) = N_Subprogram_Body then Set_Has_Nested_Block_With_Handler (Scop); @@ -5789,11 +5759,17 @@ package body Exp_Ch7 is Set_Uses_Sec_Stack (Scop, False); end if; - -- If exception handlers are present, wrap the sequence of statements - -- in a block since it is not possible to have exception handlers and - -- an At_End handler in the same construct. + -- If exception handlers are present in a non-subprogram + -- construct, wrap the sequence of statements in a block. + -- Otherwise, code can be moved so that the wrong handlers + -- apply. It is important not to do this for function bodies, + -- because otherwise transient finalizable objects created + -- by a return statement get finalized too late. It is harmless + -- not to do this for procedures. - if Present (Exception_Handlers (HSS)) then + if Present (Exception_Handlers (HSS)) + and then Nkind (N) /= N_Subprogram_Body + then Wrap_HSS_In_Block; -- Ensure that the First_Real_Statement field is set diff --git a/gcc/ada/exp_ch7.ads b/gcc/ada/exp_ch7.ads index 3dbac21..1f1ab16 100644 --- a/gcc/ada/exp_ch7.ads +++ b/gcc/ada/exp_ch7.ads @@ -255,8 +255,8 @@ package Exp_Ch7 is procedure Expand_Cleanup_Actions (N : Node_Id); -- Expand the necessary stuff into a scope to enable finalization of local -- objects and deallocation of transient data when exiting the scope. N is - -- a "scope node" that is to say one of the following: N_Block_Statement, - -- N_Subprogram_Body, N_Task_Body, N_Entry_Body. + -- one of N_Block_Statement, N_Subprogram_Body, N_Task_Body, N_Entry_Body, + -- or N_Extended_Return_Statement. procedure Establish_Transient_Scope (N : Node_Id; diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb index e9967b4..1f43458 100644 --- a/gcc/ada/exp_disp.adb +++ b/gcc/ada/exp_disp.adb @@ -3660,7 +3660,7 @@ package body Exp_Disp is -- replaced by gotos which jump to the end of the routine and restore the -- Ghost mode. - function Make_DT (Typ : Entity_Id; N : Node_Id := Empty) return List_Id is + function Make_DT (Typ : Entity_Id) return List_Id is Loc : constant Source_Ptr := Sloc (Typ); Max_Predef_Prims : constant Int := @@ -3678,23 +3678,6 @@ package body Exp_Disp is -- offset to the components that reference secondary dispatch tables. -- Used to compute the offset of components located at fixed position. - procedure Check_Premature_Freezing - (Subp : Entity_Id; - Tagged_Type : Entity_Id; - Typ : Entity_Id); - -- Verify that all untagged types in the profile of a subprogram are - -- frozen at the point the subprogram is frozen. This enforces the rule - -- on RM 13.14 (14) as modified by AI05-019. At the point a subprogram - -- is frozen, enough must be known about it to build the activation - -- record for it, which requires at least that the size of all - -- parameters be known. Controlling arguments are by-reference, - -- and therefore the rule only applies to untagged types. Typical - -- violation of the rule involves an object declaration that freezes a - -- tagged type, when one of its primitive operations has a type in its - -- profile whose full view has not been analyzed yet. More complex cases - -- involve composite types that have one private unfrozen subcomponent. - -- Move this check to sem??? - procedure Export_DT (Typ : Entity_Id; DT : Entity_Id; Index : Nat := 0); -- Export the dispatch table DT of tagged type Typ. Required to generate -- forward references and statically allocate the table. For primary @@ -3733,103 +3716,6 @@ package body Exp_Disp is function Number_Of_Predefined_Prims (Typ : Entity_Id) return Nat; -- Returns the number of predefined primitives of Typ - ------------------------------ - -- Check_Premature_Freezing -- - ------------------------------ - - procedure Check_Premature_Freezing - (Subp : Entity_Id; - Tagged_Type : Entity_Id; - Typ : Entity_Id) - is - Comp : Entity_Id; - - function Is_Actual_For_Formal_Incomplete_Type - (T : Entity_Id) return Boolean; - -- In Ada 2012, if a nested generic has an incomplete formal type, - -- the actual may be (and usually is) a private type whose completion - -- appears later. It is safe to build the dispatch table in this - -- case, gigi will have full views available. - - ------------------------------------------ - -- Is_Actual_For_Formal_Incomplete_Type -- - ------------------------------------------ - - function Is_Actual_For_Formal_Incomplete_Type - (T : Entity_Id) return Boolean - is - Gen_Par : Entity_Id; - F : Node_Id; - - begin - if not Is_Generic_Instance (Current_Scope) - or else not Used_As_Generic_Actual (T) - then - return False; - else - Gen_Par := Generic_Parent (Parent (Current_Scope)); - end if; - - F := - First - (Generic_Formal_Declarations - (Unit_Declaration_Node (Gen_Par))); - while Present (F) loop - if Ekind (Defining_Identifier (F)) = E_Incomplete_Type then - return True; - end if; - - Next (F); - end loop; - - return False; - end Is_Actual_For_Formal_Incomplete_Type; - - -- Start of processing for Check_Premature_Freezing - - begin - -- Note that if the type is a (subtype of) a generic actual, the - -- actual will have been frozen by the instantiation. - - if Present (N) - and then Is_Private_Type (Typ) - and then No (Full_View (Typ)) - and then not Has_Private_Declaration (Typ) - and then not Is_Generic_Type (Typ) - and then not Is_Tagged_Type (Typ) - and then not Is_Frozen (Typ) - and then not Is_Generic_Actual_Type (Typ) - then - Error_Msg_Sloc := Sloc (Subp); - Error_Msg_NE - ("declaration must appear after completion of type &", N, Typ); - Error_Msg_NE - ("\which is an untagged type in the profile of " - & "primitive operation & declared#", N, Subp); - - else - Comp := Private_Component (Typ); - - if not Is_Tagged_Type (Typ) - and then Present (Comp) - and then not Is_Frozen (Comp) - and then not Has_Private_Declaration (Comp) - and then not Is_Actual_For_Formal_Incomplete_Type (Comp) - then - Error_Msg_Sloc := Sloc (Subp); - Error_Msg_NE - ("declaration must appear after completion of type &", - N, Comp); - Error_Msg_Node_2 := Subp; - Error_Msg_Name_1 := Chars (Tagged_Type); - Error_Msg_NE - ("\which is a component of untagged type& in the profile " - & "of primitive & of type % that is frozen by the " - & "declaration", N, Typ); - end if; - end if; - end Check_Premature_Freezing; - --------------- -- Export_DT -- --------------- @@ -4583,59 +4469,6 @@ package body Exp_Disp is Parent_Typ := Full_View (Parent_Typ); end if; - -- Ensure that all the primitives are frozen. This is only required when - -- building static dispatch tables --- the primitives must be frozen to - -- be referenced (otherwise we have problems with the backend). It is - -- not a requirement with nonstatic dispatch tables because in this case - -- we generate now an empty dispatch table; the extra code required to - -- register the primitives in the slots will be generated later --- when - -- each primitive is frozen (see Freeze_Subprogram). - - if Building_Static_DT (Typ) then - declare - Saved_FLLTT : constant Boolean := - Freezing_Library_Level_Tagged_Type; - - Formal : Entity_Id; - Frnodes : List_Id; - Prim : Entity_Id; - Prim_Elmt : Elmt_Id; - - begin - Freezing_Library_Level_Tagged_Type := True; - - Prim_Elmt := First_Elmt (Primitive_Operations (Typ)); - while Present (Prim_Elmt) loop - Prim := Node (Prim_Elmt); - Frnodes := Freeze_Entity (Prim, Typ); - - -- We disable this check for abstract subprograms, given that - -- they cannot be called directly and thus the state of their - -- untagged formals is of no concern. The RM is unclear in any - -- case concerning the need for this check, and this topic may - -- go back to the ARG. - - if not Is_Abstract_Subprogram (Prim) then - Formal := First_Formal (Prim); - while Present (Formal) loop - Check_Premature_Freezing (Prim, Typ, Etype (Formal)); - Next_Formal (Formal); - end loop; - - Check_Premature_Freezing (Prim, Typ, Etype (Prim)); - end if; - - if Present (Frnodes) then - Append_List_To (Result, Frnodes); - end if; - - Next_Elmt (Prim_Elmt); - end loop; - - Freezing_Library_Level_Tagged_Type := Saved_FLLTT; - end; - end if; - if not Is_Interface (Typ) and then Has_Interfaces (Typ) then declare Cannot_Have_Null_Disc : Boolean := False; diff --git a/gcc/ada/exp_disp.ads b/gcc/ada/exp_disp.ads index cbb5ba6..96eae30 100644 --- a/gcc/ada/exp_disp.ads +++ b/gcc/ada/exp_disp.ads @@ -168,11 +168,9 @@ package Exp_Disp is -- Generate checks required on dispatching calls function Building_Static_DT (Typ : Entity_Id) return Boolean; - pragma Inline (Building_Static_DT); -- Returns true when building statically allocated dispatch tables function Building_Static_Secondary_DT (Typ : Entity_Id) return Boolean; - pragma Inline (Building_Static_Secondary_DT); -- Returns true when building statically allocated secondary dispatch -- tables @@ -187,7 +185,6 @@ package Exp_Disp is function Convert_Tag_To_Interface (Typ : Entity_Id; Expr : Node_Id) return Node_Id; - pragma Inline (Convert_Tag_To_Interface); -- This function is used in class-wide interface conversions; the expanded -- code generated to convert a tagged object to a class-wide interface type -- involves referencing the tag component containing the secondary dispatch @@ -256,11 +253,8 @@ package Exp_Disp is function Is_Expanded_Dispatching_Call (N : Node_Id) return Boolean; -- Returns true if N is the expanded code of a dispatching call - function Make_DT (Typ : Entity_Id; N : Node_Id := Empty) return List_Id; - -- Expand the declarations for the Dispatch Table. The node N is the - -- declaration that forces the generation of the table. It is used to place - -- error messages when the declaration leads to the freezing of a given - -- primitive operation that has an incomplete non- tagged formal. + function Make_DT (Typ : Entity_Id) return List_Id; + -- Expand the declarations for the Dispatch Table of Typ function Make_Disp_Asynchronous_Select_Body (Typ : Entity_Id) return Node_Id; diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb index 4ff7036..f4ebf30 100644 --- a/gcc/ada/freeze.adb +++ b/gcc/ada/freeze.adb @@ -789,7 +789,7 @@ package body Freeze is then Error_Msg_Sloc := Sloc (Addr); Error_Msg_NE - ("??constant& may be modified via address clause#", + ("?o?constant& may be modified via address clause#", Decl, O_Ent); end if; end; @@ -4631,9 +4631,7 @@ package body Freeze is Result := No_List; return False; - elsif not After_Last_Declaration - and then not Freezing_Library_Level_Tagged_Type - then + elsif not After_Last_Declaration then Error_Msg_NE ("type & must be fully defined before this point", N, @@ -4751,17 +4749,6 @@ package body Freeze is if Is_Access_Type (F_Type) then F_Type := Designated_Type (F_Type); end if; - - -- If the formal is an anonymous_access_to_subprogram - -- freeze the subprogram type as well, to prevent - -- scope anomalies in gigi, because there is no other - -- clear point at which it could be frozen. - - if Is_Itype (Etype (Formal)) - and then Ekind (F_Type) = E_Subprogram_Type - then - Freeze_And_Append (F_Type, N, Result); - end if; end if; Next_Formal (Formal); @@ -6490,9 +6477,10 @@ package body Freeze is -- In Ada 2012, freezing a subprogram does not always freeze the -- corresponding profile (see AI05-019). An attribute reference - -- is not a freezing point of the profile. Flag Do_Freeze_Profile + -- is not a freezing point of the profile. Similarly, we do not + -- freeze the profile of primitives of a library-level tagged type + -- when we are building its dispatch table. Flag Do_Freeze_Profile -- indicates whether the profile should be frozen now. - -- Other constructs that should not freeze ??? -- This processing doesn't apply to internal entities (see below) @@ -10650,11 +10638,11 @@ package body Freeze is if Present (Old) then Error_Msg_Node_2 := Old; Error_Msg_N - ("default initialization of & may modify &??", + ("default initialization of & may modify &?o?", Nam); else Error_Msg_N - ("default initialization of & may modify overlaid storage??", + ("default initialization of & may modify overlaid storage?o?", Nam); end if; diff --git a/gcc/ada/freeze.ads b/gcc/ada/freeze.ads index 749fb79..bef4e14 100644 --- a/gcc/ada/freeze.ads +++ b/gcc/ada/freeze.ads @@ -120,12 +120,6 @@ package Freeze is -- where the freeze node is preallocated at the point of declaration, so -- that the First_Subtype_Link field can be set. - Freezing_Library_Level_Tagged_Type : Boolean := False; - -- Flag used to indicate that we are freezing the primitives of a library - -- level tagged type. Used to disable checks on premature freezing. - -- More documentation needed??? why is this flag needed? what are these - -- checks? why do they need disabling in some cases? - ----------------- -- Subprograms -- ----------------- diff --git a/gcc/ada/frontend.adb b/gcc/ada/frontend.adb index c60234d..12c91b1 100644 --- a/gcc/ada/frontend.adb +++ b/gcc/ada/frontend.adb @@ -38,7 +38,6 @@ with Ghost; use Ghost; with Inline; use Inline; with Lib; use Lib; with Lib.Load; use Lib.Load; -with Lib.Xref; with Live; use Live; with Namet; use Namet; with Nlists; use Nlists; @@ -481,7 +480,6 @@ begin -- Output waiting warning messages - Lib.Xref.Process_Deferred_References; Sem_Warn.Output_Non_Modified_In_Out_Warnings; Sem_Warn.Output_Unreferenced_Messages; Sem_Warn.Check_Unused_Withs; diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in index 1e9801a..8c34f42 100644 --- a/gcc/ada/gcc-interface/Makefile.in +++ b/gcc/ada/gcc-interface/Makefile.in @@ -588,9 +588,9 @@ install-gnatlib: ../stamp-gnatlib-$(RTSDIR) install-gcc-specs touch ../stamp-gnatlib1-$(RTSDIR) # GCC_FOR_TARGET has paths relative to the gcc directory, so we need to adjust -# for running it from ada/rts +# for running it from ada/rts. -OSCONS_CC=$(subst ./xgcc,../../xgcc,$(subst -B./, -B../../,$(GCC_FOR_TARGET))) +GCC_FOR_ADA_RTS=$(subst ./xgcc,../../xgcc,$(subst -B./, -B../../,$(GCC_FOR_TARGET))) # The main ada source directory must be on the include path for #include "..." # because s-oscons-tmplt.c requires adaint.h, gsocket.h, and any file included @@ -598,9 +598,9 @@ OSCONS_CC=$(subst ./xgcc,../../xgcc,$(subst -B./, -B../../,$(GCC_FOR_TARGET))) # ada/types.h does not conflict with a same-named system header (VxWorks # has a <types.h> header). -OSCONS_CPP=$(OSCONS_CC) $(GNATLIBCFLAGS_FOR_C) -E -C \ +OSCONS_CPP=$(GCC_FOR_ADA_RTS) $(GNATLIBCFLAGS_FOR_C) -E -C \ -DTARGET=\"$(target_noncanonical)\" -iquote $(fsrcpfx)ada $(fsrcpfx)ada/s-oscons-tmplt.c > s-oscons-tmplt.i -OSCONS_EXTRACT=$(OSCONS_CC) $(GNATLIBCFLAGS_FOR_C) -S s-oscons-tmplt.i +OSCONS_EXTRACT=$(GCC_FOR_ADA_RTS) $(GNATLIBCFLAGS_FOR_C) -S s-oscons-tmplt.i # Note: if you need to build with a non-GNU compiler, you could adapt the # following definitions (written for VMS DEC-C) @@ -629,8 +629,7 @@ gnatlib: ../stamp-gnatlib1-$(RTSDIR) ../stamp-gnatlib2-$(RTSDIR) $(RTSDIR)/s-osc test -f $(RTSDIR)/s-oscons.ads || exit 1 # C files $(MAKE) -C $(RTSDIR) \ - CC="`echo \"$(GCC_FOR_TARGET)\" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'`" \ + CC="$(GCC_FOR_ADA_RTS)" \ INCLUDES="$(INCLUDES_FOR_SUBDIR) -I./../.." \ CFLAGS="$(GNATLIBCFLAGS_FOR_C)" \ FORCE_DEBUG_ADAFLAGS="$(FORCE_DEBUG_ADAFLAGS)" \ @@ -638,8 +637,7 @@ gnatlib: ../stamp-gnatlib1-$(RTSDIR) ../stamp-gnatlib2-$(RTSDIR) $(RTSDIR)/s-osc -f ../Makefile $(LIBGNAT_OBJS) $(EXTRA_ADALIB_OBJS) # Ada files $(MAKE) -C $(RTSDIR) \ - CC="`echo \"$(GCC_FOR_TARGET)\" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'`" \ + CC="$(GCC_FOR_ADA_RTS)" \ ADA_INCLUDES="" \ CFLAGS="$(GNATLIBCFLAGS)" \ ADAFLAGS="$(GNATLIBFLAGS)" \ @@ -672,15 +670,13 @@ gnatlib-shared-default: LN_S="$(LN_S)" \ gnatlib $(RM) $(RTSDIR)/libgna*$(soext) - cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -shared $(GNATLIBCFLAGS) \ + cd $(RTSDIR); $(GCC_FOR_ADA_RTS) -shared $(GNATLIBCFLAGS) \ $(PICFLAG_FOR_TARGET) \ -o libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) \ $(SO_OPTS)libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(MISCLIB) -lm - cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -shared $(GNATLIBCFLAGS) \ + cd $(RTSDIR); $(GCC_FOR_ADA_RTS) -shared $(GNATLIBCFLAGS) \ $(PICFLAG_FOR_TARGET) \ -o libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_TASKING_OBJS) \ @@ -764,14 +760,12 @@ gnatlib-shared-win32: $(RM) $(RTSDIR)/libgna*$(soext) $(CP) $(RTSDIR)/libgnat$(arext) $(RTSDIR)/libgnat_pic$(arext) $(CP) $(RTSDIR)/libgnarl$(arext) $(RTSDIR)/libgnarl_pic$(arext) - cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -shared -shared-libgcc \ + cd $(RTSDIR); $(GCC_FOR_ADA_RTS) -shared -shared-libgcc \ $(PICFLAG_FOR_TARGET) \ -o libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) \ $(SO_OPTS)libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) $(MISCLIB) - cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -shared -shared-libgcc \ + cd $(RTSDIR); $(GCC_FOR_ADA_RTS) -shared -shared-libgcc \ $(PICFLAG_FOR_TARGET) \ -o libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_TASKING_OBJS) \ @@ -790,15 +784,13 @@ gnatlib-shared-darwin: $(RM) $(RTSDIR)/libgnat$(soext) $(RTSDIR)/libgnarl$(soext) $(CP) $(RTSDIR)/libgnat$(arext) $(RTSDIR)/libgnat_pic$(arext) $(CP) $(RTSDIR)/libgnarl$(arext) $(RTSDIR)/libgnarl_pic$(arext) - cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -dynamiclib $(PICFLAG_FOR_TARGET) \ + cd $(RTSDIR); $(GCC_FOR_ADA_RTS) -dynamiclib $(PICFLAG_FOR_TARGET) \ -o libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) \ $(SO_OPTS) \ -Wl,-install_name,@rpath/libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(MISCLIB) - cd $(RTSDIR); `echo "$(GCC_FOR_TARGET)" \ - | sed -e 's,\./xgcc,../../xgcc,' -e 's,-B\./,-B../../,'` -dynamiclib $(PICFLAG_FOR_TARGET) \ + cd $(RTSDIR); $(GCC_FOR_ADA_RTS) -dynamiclib $(PICFLAG_FOR_TARGET) \ -o libgnarl$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_TASKING_OBJS) \ $(SO_OPTS) \ diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads index 878755b..e188a6d 100644 --- a/gcc/ada/gen_il-fields.ads +++ b/gcc/ada/gen_il-fields.ads @@ -118,7 +118,6 @@ package Gen_IL.Fields is Contract_Test_Cases, Controlling_Argument, Conversion_OK, - Convert_To_Return_False, Corresponding_Aspect, Corresponding_Body, Corresponding_Entry_Body, diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb index 96e1c76..dd730f4 100644 --- a/gcc/ada/gen_il-gen-gen_nodes.adb +++ b/gcc/ada/gen_il-gen-gen_nodes.adb @@ -523,8 +523,7 @@ begin -- Gen_IL.Gen.Gen_Nodes Cc (N_Raise_Expression, N_Subexpr, (Sy (Name, Node_Id, Default_Empty), - Sy (Expression, Node_Id, Default_Empty), - Sm (Convert_To_Return_False, Flag))); + Sy (Expression, Node_Id, Default_Empty))); Cc (N_Range, N_Subexpr, (Sy (Low_Bound, Node_Id), diff --git a/gcc/ada/gnat1drv.adb b/gcc/ada/gnat1drv.adb index 49ddf03..5c6fd92a 100644 --- a/gcc/ada/gnat1drv.adb +++ b/gcc/ada/gnat1drv.adb @@ -180,6 +180,7 @@ procedure Gnat1drv is -- Set all flags required when generating C code if Generate_C_Code then + CCG_Mode := True; Modify_Tree_For_C := True; Transform_Function_Array := True; Unnest_Subprogram_Mode := True; diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index bf7c532..1fa93a3 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -21,7 +21,7 @@ @copying @quotation -GNAT Reference Manual , Apr 22, 2022 +GNAT Reference Manual , May 24, 2022 AdaCore @@ -14333,14 +14333,6 @@ then values of the type are implicitly initialized to zero. This happens both for objects of the packed type, and for objects that have a subcomponent of the packed type. -@quotation - -“An implementation should support Address clauses for imported -subprograms.” -@end quotation - -Followed. - @geindex Address clauses @node RM 13 3 14-19 Address Clauses,RM 13 3 29-35 Alignment Clauses,RM 13 2 6-8 Packed Types,Implementation Advice @@ -28920,8 +28912,9 @@ pragma Machine_Attribute (Bar, "zero_call_used_regs", "all"); -- Before returning, Bar scrubs all call-clobbered registers. @end example -For usage and more details on the command-line option, and on the -@code{zero_call_used_regs} attribute, see @cite{Using the GNU Compiler Collection (GCC)}. +For usage and more details on the command-line option, on the +@code{zero_call_used_regs} attribute, and on their use with other +programming languages, see @cite{Using the GNU Compiler Collection (GCC)}. @c Stack Scrubbing: @@ -28933,13 +28926,16 @@ For usage and more details on the command-line option, and on the GNAT can generate code to zero-out stack frames used by subprograms. It can be activated with the @code{Machine_Attribute} pragma, on -specific subprograms and variables. +specific subprograms and variables, or their types. (This attribute +always applies to a type, even when it is associated with a subprogram +or a variable.) @example function Foo returns Integer; pragma Machine_Attribute (Foo, "strub"); -- Foo and its callers are modified so as to scrub the stack --- space used by Foo after it returns. +-- space used by Foo after it returns. Shorthand for: +-- pragma Machine_Attribute (Foo, "strub", "at-calls"); procedure Bar; pragma Machine_Attribute (Bar, "strub", "internal"); @@ -28949,12 +28945,15 @@ pragma Machine_Attribute (Bar, "strub", "internal"); Var : Integer; pragma Machine_Attribute (Var, "strub"); -- Reading from Var in a subprogram enables stack scrubbing --- of the stack space used by the subprogram. +-- of the stack space used by the subprogram. Furthermore, if +-- Var is declared within a subprogram, this also enables +-- scrubbing of the stack space used by that subprogram. @end example There are also @code{-fstrub} command-line options to control default settings. For usage and more details on the command-line -option, and on the @code{strub} attribute, see @cite{Using the GNU Compiler Collection (GCC)}. +option, on the @code{strub} attribute, and their use with other +programming languages, see @cite{Using the GNU Compiler Collection (GCC)}. Note that Ada secondary stacks are not scrubbed. The restriction @code{No_Secondary_Stack} avoids their use, and thus their accidental @@ -28967,16 +28966,19 @@ there is no way to express an access-to-strub type otherwise. access type designates a non-strub type. @example -VI : Integer; +VI : aliased Integer; +pragma Machine_Attribute (VI, "strub"); XsVI : access Integer := VI'Access; -- Error. UXsVI : access Integer := VI'Unchecked_Access; -- OK, --- UXsVI.all does not enable strub in the enclosing subprogram. +-- UXsVI does *not* enable strub in subprograms that +-- dereference it to obtain the UXsVI.all value. type Strub_Int is new Integer; pragma Machine_Attribute (Strub_Int, "strub"); -VSI : Strub_Int; -XsVSI : access Strub_Int := VSI'Access; -- OK. --- XsVSI.all enables strub in the enclosing subprogram. +VSI : aliased Strub_Int; +XsVSI : access Strub_Int := VSI'Access; -- OK, +-- VSI and XsVSI.all both enable strub in subprograms that +-- read their values. @end example Every access-to-subprogram type, renaming, and overriding and @@ -28993,6 +28995,9 @@ type TBar is access procedure; type TBar_Callable is access procedure; pragma Machine_Attribute (TBar_Callable, "strub", "callable"); +-- The attribute modifies the procedure type, rather than the +-- access type, because of the extra argument after "strub", +-- only applicable to subprogram types. Bar_Callable_Ptr : constant TBar_Callable := TBar_Callable (TBar'(Bar'Access)); @@ -29049,6 +29054,10 @@ respectively. They are separate options, however, because of the significantly different performance impact of the hardening transformations. +For usage and more details on the command-line options, see +@cite{Using the GNU Compiler Collection (GCC)}. These options can +be used with other programming languages supported by GCC. + @c Hardened Booleans: @node Hardened Booleans,Control Flow Redundancy,Hardened Conditionals,Security Hardening Features @@ -29086,6 +29095,10 @@ pragma Machine_Attribute (HBool, "hardbool"); Note that @code{-gnatVn} will disable even @code{hardbool} testing. +Analogous behavior is available as a GCC extension to the C and +Objective C programming languages, through the @code{hardbool} attribute. +For usage and more details on that attribute, see @cite{Using the GNU Compiler Collection (GCC)}. + @c Control Flow Redundancy: @node Control Flow Redundancy,,Hardened Booleans,Security Hardening Features @@ -29133,6 +29146,10 @@ The instrumentation for hardening with control flow redundancy can be observed in dump files generated by the command-line option @code{-fdump-tree-hardcfr}. +For more details on the control flow redundancy command-line options, +see @cite{Using the GNU Compiler Collection (GCC)}. These options +can be used with other programming languages supported by GCC. + @node Obsolescent Features,Compatibility and Porting Guide,Security Hardening Features,Top @anchor{gnat_rm/obsolescent_features doc}@anchor{447}@anchor{gnat_rm/obsolescent_features id1}@anchor{448}@anchor{gnat_rm/obsolescent_features obsolescent-features}@anchor{16} @chapter Obsolescent Features diff --git a/gcc/ada/inline.adb b/gcc/ada/inline.adb index cc10c29..00c1e03 100644 --- a/gcc/ada/inline.adb +++ b/gcc/ada/inline.adb @@ -2804,8 +2804,8 @@ package body Inline is elsif Ineffective_Inline_Warnings then Error_Msg_Unit_1 := Bname; Error_Msg_N - ("unable to inline subprograms defined in $??", P); - Error_Msg_N ("\body not found??", P); + ("unable to inline subprograms defined in $?p?", P); + Error_Msg_N ("\body not found?p?", P); return; end if; end if; diff --git a/gcc/ada/lib-xref.adb b/gcc/ada/lib-xref.adb index 919e41f..a4ff69a 100644 --- a/gcc/ada/lib-xref.adb +++ b/gcc/ada/lib-xref.adb @@ -57,14 +57,6 @@ package body Lib.Xref is -- Declarations -- ------------------ - package Deferred_References is new Table.Table ( - Table_Component_Type => Deferred_Reference_Entry, - Table_Index_Type => Int, - Table_Low_Bound => 0, - Table_Initial => 512, - Table_Increment => 200, - Table_Name => "Name_Deferred_References"); - -- The Xref table is used to record references. The Loc field is set -- to No_Location for a definition entry. @@ -211,21 +203,6 @@ package body Lib.Xref is end if; end Add_Entry; - --------------------- - -- Defer_Reference -- - --------------------- - - procedure Defer_Reference (Deferred_Reference : Deferred_Reference_Entry) is - begin - -- If Get_Ignore_Errors, then we are in Preanalyze_Without_Errors, and - -- we should not record cross references, because that will cause - -- duplicates when we call Analyze. - - if not Get_Ignore_Errors then - Deferred_References.Append (Deferred_Reference); - end if; - end Defer_Reference; - ----------- -- Equal -- ----------- @@ -1291,21 +1268,6 @@ package body Lib.Xref is return E; end Get_Key; - ---------------------------- - -- Has_Deferred_Reference -- - ---------------------------- - - function Has_Deferred_Reference (Ent : Entity_Id) return Boolean is - begin - for J in Deferred_References.First .. Deferred_References.Last loop - if Deferred_References.Table (J).E = Ent then - return True; - end if; - end loop; - - return False; - end Has_Deferred_Reference; - ---------- -- Hash -- ---------- @@ -2753,33 +2715,6 @@ package body Lib.Xref is end Output_Refs; end Output_References; - --------------------------------- - -- Process_Deferred_References -- - --------------------------------- - - procedure Process_Deferred_References is - begin - for J in Deferred_References.First .. Deferred_References.Last loop - declare - D : Deferred_Reference_Entry renames Deferred_References.Table (J); - - begin - case Known_To_Be_Assigned (D.N) is - when True => - Generate_Reference (D.E, D.N, 'm'); - - when False => - Generate_Reference (D.E, D.N, 'r'); - - end case; - end; - end loop; - - -- Clear processed entries from table - - Deferred_References.Init; - end Process_Deferred_References; - -- Start of elaboration for Lib.Xref begin diff --git a/gcc/ada/lib-xref.ads b/gcc/ada/lib-xref.ads index 729acd3..977446a 100644 --- a/gcc/ada/lib-xref.ads +++ b/gcc/ada/lib-xref.ads @@ -578,40 +578,6 @@ package Lib.Xref is -- Export at line 4, that its body is exported to C, and that the link name -- as given in the pragma is "here". - ------------------------- - -- Deferred_References -- - ------------------------- - - -- Normally we generate references as we go along, but as discussed in - -- Sem_Util.Is_LHS, and Sem_Ch8.Find_Direct_Name/Find_Selected_Component, - -- we have one case where that is tricky, which is when we have something - -- like X.A := 3, where we don't know until we know the type of X whether - -- this is a reference (if X is an access type, so what we really have is - -- X.all.A := 3) or a modification, where X is not an access type. - - -- What we do in such cases is to gather nodes, where we would have liked - -- to call Generate_Reference but we couldn't because we didn't know enough - -- into a table, then we deal with generating references later on when we - -- have sufficient information to do it right. - - type Deferred_Reference_Entry is record - E : Entity_Id; - N : Node_Id; - end record; - -- One entry, E, N are as required for Generate_Reference call - - procedure Defer_Reference (Deferred_Reference : Deferred_Reference_Entry); - -- Add one entry to the deferred reference table - - procedure Process_Deferred_References; - -- This procedure is called from Frontend to process these table entries. - -- It is also called from Sem_Warn. - - function Has_Deferred_Reference (Ent : Entity_Id) return Boolean; - -- Determine whether arbitrary entity Ent has a pending reference in order - -- to suppress premature warnings about useless assignments. See comments - -- in Analyze_Assignment in sem_ch5.adb. - ----------------------------- -- SPARK Xrefs Information -- ----------------------------- diff --git a/gcc/ada/libgnat/a-cfdlli.ads b/gcc/ada/libgnat/a-cfdlli.ads index 521f4bf..ff7d2d8 100644 --- a/gcc/ada/libgnat/a-cfdlli.ads +++ b/gcc/ada/libgnat/a-cfdlli.ads @@ -543,15 +543,7 @@ is Lst => Length (Container), Item => New_Item)) - -- Container contains Count times New_Item at the end - - and M.Constant_Range - (Container => Model (Container), - Fst => Length (Container)'Old + 1, - Lst => Length (Container), - Item => New_Item) - - -- A Count cursors have been inserted at the end of Container + -- Count cursors have been inserted at the end of Container and P_Positions_Truncated (Positions (Container)'Old, diff --git a/gcc/ada/libgnat/a-cofuma.adb b/gcc/ada/libgnat/a-cofuma.adb index 080229d..0fcdbdc 100644 --- a/gcc/ada/libgnat/a-cofuma.adb +++ b/gcc/ada/libgnat/a-cofuma.adb @@ -130,6 +130,13 @@ package body Ada.Containers.Functional_Maps with SPARK_Mode => Off is return True; end Elements_Equal_Except; + --------------- + -- Empty_Map -- + --------------- + + function Empty_Map return Map is + ((others => <>)); + --------- -- Get -- --------- diff --git a/gcc/ada/libgnat/a-cofuma.ads b/gcc/ada/libgnat/a-cofuma.ads index 3f61b63..f240e1e 100644 --- a/gcc/ada/libgnat/a-cofuma.ads +++ b/gcc/ada/libgnat/a-cofuma.ads @@ -243,6 +243,14 @@ package Ada.Containers.Functional_Maps with SPARK_Mode is and Container <= Add'Result and Keys_Included_Except (Add'Result, Container, New_Key); + function Empty_Map return Map with + -- Return an empty Map + + Global => null, + Post => + Length (Empty_Map'Result) = 0 + and Is_Empty (Empty_Map'Result); + function Remove (Container : Map; Key : Key_Type) return Map diff --git a/gcc/ada/libgnat/a-cofuse.adb b/gcc/ada/libgnat/a-cofuse.adb index 0157988..77adb1d 100644 --- a/gcc/ada/libgnat/a-cofuse.adb +++ b/gcc/ada/libgnat/a-cofuse.adb @@ -63,6 +63,13 @@ package body Ada.Containers.Functional_Sets with SPARK_Mode => Off is function Contains (Container : Set; Item : Element_Type) return Boolean is (Find (Container.Content, Item) > 0); + --------------- + -- Empty_Set -- + --------------- + + function Empty_Set return Set is + ((others => <>)); + --------------------- -- Included_Except -- --------------------- diff --git a/gcc/ada/libgnat/a-cofuse.ads b/gcc/ada/libgnat/a-cofuse.ads index db88b9a..6cd340b 100644 --- a/gcc/ada/libgnat/a-cofuse.ads +++ b/gcc/ada/libgnat/a-cofuse.ads @@ -215,6 +215,12 @@ package Ada.Containers.Functional_Sets with SPARK_Mode is and Container <= Add'Result and Included_Except (Add'Result, Container, Item); + function Empty_Set return Set with + -- Return a new empty set + + Global => null, + Post => Is_Empty (Empty_Set'Result); + function Remove (Container : Set; Item : Element_Type) return Set with -- Return a new set containing all the elements of Container except E diff --git a/gcc/ada/libgnat/a-cofuve.adb b/gcc/ada/libgnat/a-cofuve.adb index 06075b1..0d91da5 100644 --- a/gcc/ada/libgnat/a-cofuve.adb +++ b/gcc/ada/libgnat/a-cofuve.adb @@ -118,6 +118,13 @@ package body Ada.Containers.Functional_Vectors with SPARK_Mode => Off is return False; end Contains; + -------------------- + -- Empty_Sequence -- + -------------------- + + function Empty_Sequence return Sequence is + ((others => <>)); + ------------------ -- Equal_Except -- ------------------ diff --git a/gcc/ada/libgnat/a-cofuve.ads b/gcc/ada/libgnat/a-cofuve.ads index ce3a3a4..f926a96 100644 --- a/gcc/ada/libgnat/a-cofuve.ads +++ b/gcc/ada/libgnat/a-cofuve.ads @@ -343,6 +343,12 @@ package Ada.Containers.Functional_Vectors with SPARK_Mode is -- i.e. it does not contain pointers that could be used to alias mutable -- data). + function Empty_Sequence return Sequence with + -- Return an empty Sequence + + Global => null, + Post => Length (Empty_Sequence'Result) = 0; + --------------------------- -- Iteration Primitives -- --------------------------- diff --git a/gcc/ada/libgnat/s-aridou.adb b/gcc/ada/libgnat/s-aridou.adb index d214968..259c0ac 100644 --- a/gcc/ada/libgnat/s-aridou.adb +++ b/gcc/ada/libgnat/s-aridou.adb @@ -30,6 +30,7 @@ ------------------------------------------------------------------------------ with Ada.Unchecked_Conversion; +with System.SPARK.Cut_Operations; use System.SPARK.Cut_Operations; package body System.Arith_Double with SPARK_Mode @@ -1822,6 +1823,31 @@ is Big_Q : Big_Integer with Ghost; Inter : Natural with Ghost; + -- Local ghost functions + + function Is_Mult_Decomposition + (D1, D2, D3, D4 : Big_Integer) + return Boolean + is + (Mult = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * D1 + + Big_2xxSingle * Big_2xxSingle * D2 + + Big_2xxSingle * D3 + + D4) + with Ghost; + + function Is_Scaled_Mult_Decomposition + (D1, D2, D3, D4 : Big_Integer) + return Boolean + is + (Mult * Big_2xx (Scale) + = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * D1 + + Big_2xxSingle * Big_2xxSingle * D2 + + Big_2xxSingle * D3 + + D4) + with + Ghost, + Pre => Scale < Double_Size; + -- Local lemmas procedure Prove_Dividend_Scaling @@ -1829,24 +1855,19 @@ is Ghost, Pre => D'Initialized and then Scale <= Single_Size - and then Mult = - Big_2xxSingle - * Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) - + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4))) + and then Is_Mult_Decomposition (Big (Double_Uns (D (1))), + Big (Double_Uns (D (2))), + Big (Double_Uns (D (3))), + Big (Double_Uns (D (4)))) and then Big (D (1) & D (2)) * Big_2xx (Scale) < Big_2xxDouble and then T1 = Shift_Left (D (1) & D (2), Scale) and then T2 = Shift_Left (Double_Uns (D (3)), Scale) and then T3 = Shift_Left (Double_Uns (D (4)), Scale), - Post => Mult * Big_2xx (Scale) = - Big_2xxSingle - * Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T1))) - + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T1) or - Hi (T2))) - + Big_2xxSingle * Big (Double_Uns (Lo (T2) or - Hi (T3))) - + Big (Double_Uns (Lo (T3))); + Post => Is_Scaled_Mult_Decomposition + (Big (Double_Uns (Hi (T1))), + Big (Double_Uns (Lo (T1) or Hi (T2))), + Big (Double_Uns (Lo (T2) or Hi (T3))), + Big (Double_Uns (Lo (T3)))); -- Proves the scaling of the 4-digit dividend actually multiplies it by -- 2**Scale. @@ -2030,21 +2051,32 @@ is ---------------------------- procedure Prove_Dividend_Scaling is + Big_D12 : constant Big_Integer := + Big_2xx (Scale) * Big (D (1) & D (2)); + Big_T1 : constant Big_Integer := Big (T1); + Big_D3 : constant Big_Integer := + Big_2xx (Scale) * Big (Double_Uns (D (3))); + Big_T2 : constant Big_Integer := Big (T2); + Big_D4 : constant Big_Integer := + Big_2xx (Scale) * Big (Double_Uns (D (4))); + Big_T3 : constant Big_Integer := Big (T3); + begin Lemma_Shift_Left (D (1) & D (2), Scale); + pragma Assert (By (Big_2xxSingle * Big_2xx (Scale) <= Big_2xxDouble, + Big_2xx (Scale) <= Big_2xxSingle)); + Lemma_Lt_Mult (Big (Double_Uns (D (3))), Big_2xxSingle, + Big_2xx (Scale), Big_2xxDouble); Lemma_Shift_Left (Double_Uns (D (3)), Scale); + Lemma_Lt_Mult (Big (Double_Uns (D (4))), Big_2xxSingle, + Big_2xx (Scale), Big_2xxDouble); Lemma_Shift_Left (Double_Uns (D (4)), Scale); Lemma_Hi_Lo (D (1) & D (2), D (1), D (2)); pragma Assert (Mult * Big_2xx (Scale) = - Big_2xxSingle - * Big_2xxSingle * Big_2xx (Scale) * Big (D (1) & D (2)) - + Big_2xxSingle * Big_2xx (Scale) * Big (Double_Uns (D (3))) - + Big_2xx (Scale) * Big (Double_Uns (D (4)))); + Big_2xxSingle * Big_2xxSingle * Big_D12 + + Big_2xxSingle * Big_D3 + + Big_D4); pragma Assert (Big_2xx (Scale) > 0); - Lemma_Lt_Mult (Big (Double_Uns (D (3))), Big_2xxSingle, - Big_2xx (Scale), Big_2xxDouble); - Lemma_Lt_Mult (Big (Double_Uns (D (4))), Big_2xxSingle, - Big_2xx (Scale), Big_2xxDouble); declare Two_xx_Scale : constant Double_Uns := Double_Uns'(2 ** Scale); D12 : constant Double_Uns := D (1) & D (2); @@ -2053,43 +2085,120 @@ is pragma Assert (Big (Two_xx_Scale) * Big (D12) < Big_2xxDouble); Lemma_Mult_Commutation (Two_xx_Scale, D12, T1); end; - declare - Big_D12 : constant Big_Integer := - Big_2xx (Scale) * Big (D (1) & D (2)); - Big_T1 : constant Big_Integer := Big (T1); - begin - pragma Assert (Big_D12 = Big_T1); - pragma Assert (Big_2xxSingle * Big_2xxSingle * Big_D12 - = Big_2xxSingle * Big_2xxSingle * Big_T1); - end; + pragma Assert (Big_D12 = Big_T1); + pragma Assert (Big_2xxSingle * Big_2xxSingle * Big_D12 + = Big_2xxSingle * Big_2xxSingle * Big_T1); Lemma_Mult_Commutation (2 ** Scale, Double_Uns (D (3)), T2); - declare - Big_D3 : constant Big_Integer := - Big_2xx (Scale) * Big (Double_Uns (D (3))); - Big_T2 : constant Big_Integer := Big (T2); - begin - pragma Assert (Big_D3 = Big_T2); - pragma Assert (Big_2xxSingle * Big_D3 = Big_2xxSingle * Big_T2); - end; + pragma Assert (Big_D3 = Big_T2); + pragma Assert (Big_2xxSingle * Big_D3 = Big_2xxSingle * Big_T2); Lemma_Mult_Commutation (2 ** Scale, Double_Uns (D (4)), T3); - declare - Big_D4 : constant Big_Integer := - Big_2xx (Scale) * Big (Double_Uns (D (4))); - Big_T3 : constant Big_Integer := Big (T3); - begin - pragma Assert (Big_D4 = Big_T3); - end; - pragma Assert (Mult * Big_2xx (Scale) = - Big_2xxSingle * Big_2xxSingle * Big (T1) - + Big_2xxSingle * Big (T2) - + Big (T3)); + pragma Assert (Big_D4 = Big_T3); + pragma Assert + (By (Is_Scaled_Mult_Decomposition (0, Big_T1, Big_T2, Big_T3), + By (Big_2xxSingle * Big_2xxSingle * Big_D12 = + Big_2xxSingle * Big_2xxSingle * Big_T1, + Big_D12 = Big_T1) + and then + By (Big_2xxSingle * Big_D3 = Big_2xxSingle * Big_T2, + Big_D3 = Big_T2) + and then + Big_D4 = Big_T3)); Lemma_Hi_Lo (T1, Hi (T1), Lo (T1)); Lemma_Hi_Lo (T2, Hi (T2), Lo (T2)); Lemma_Hi_Lo (T3, Hi (T3), Lo (T3)); + Lemma_Mult_Distribution (Big_2xxSingle * Big_2xxSingle, + Big_2xxSingle * Big (Double_Uns (Hi (T1))), + Big (Double_Uns (Lo (T1)))); + Lemma_Mult_Distribution (Big_2xxSingle, + Big_2xxSingle * Big (Double_Uns (Hi (T2))), + Big (Double_Uns (Lo (T2)))); + Lemma_Mult_Distribution (Big_2xxSingle * Big_2xxSingle, + Big (Double_Uns (Lo (T1))), + Big (Double_Uns (Hi (T2)))); + Lemma_Mult_Distribution (Big_2xxSingle, + Big (Double_Uns (Lo (T2))), + Big (Double_Uns (Hi (T3)))); + pragma Assert + (By (Is_Scaled_Mult_Decomposition + (Big (Double_Uns (Hi (T1))), + Big (Double_Uns (Lo (T1))) + Big (Double_Uns (Hi (T2))), + Big (Double_Uns (Lo (T2))) + Big (Double_Uns (Hi (T3))), + Big (Double_Uns (Lo (T3)))), + -- Start from stating equality between the expanded values of + -- the right-hand side in the known and desired assertions over + -- Is_Scaled_Mult_Decomposition. + By (Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * + Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big_2xxSingle * + (Big (Double_Uns (Lo (T1))) + Big (Double_Uns (Hi (T2)))) + + Big_2xxSingle * + (Big (Double_Uns (Lo (T2))) + Big (Double_Uns (Hi (T3)))) + + Big (Double_Uns (Lo (T3))) = + Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * 0 + + Big_2xxSingle * Big_2xxSingle * Big_T1 + + Big_2xxSingle * Big_T2 + + Big_T3, + -- Now list all known equalities that contribute + Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * + Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big_2xxSingle * + (Big (Double_Uns (Lo (T1))) + Big (Double_Uns (Hi (T2)))) + + Big_2xxSingle * + (Big (Double_Uns (Lo (T2))) + Big (Double_Uns (Hi (T3)))) + + Big (Double_Uns (Lo (T3))) = + Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * + Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big_2xxSingle * Big (Double_Uns (Lo (T2))) + + Big_2xxSingle * Big (Double_Uns (Hi (T3))) + + Big (Double_Uns (Lo (T3))) + and then + By (Big_2xxSingle * Big_2xxSingle * Big (T1) + = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T1))), + Big_2xxSingle * Big_2xxSingle * Big (T1) + = Big_2xxSingle * Big_2xxSingle + * (Big_2xxSingle * Big (Double_Uns (Hi (T1))) + + Big (Double_Uns (Lo (T1))))) + and then + By (Big_2xxSingle * Big (T2) + = Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big_2xxSingle * Big (Double_Uns (Lo (T2))), + Big_2xxSingle * Big (T2) + = Big_2xxSingle * (Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big (Double_Uns (Lo (T2))))) + and then + Big (T3) = Big_2xxSingle * Big (Double_Uns (Hi (T3))) + + Big (Double_Uns (Lo (T3)))))); + Lemma_Mult_Distribution (Big_2xxSingle * Big_2xxSingle, + Big (Double_Uns (Lo (T1))), + Big (Double_Uns (Hi (T2)))); pragma Assert (Double_Uns (Lo (T1) or Hi (T2)) = Double_Uns (Lo (T1)) + Double_Uns (Hi (T2))); pragma Assert (Double_Uns (Lo (T2) or Hi (T3)) = Double_Uns (Lo (T2)) + Double_Uns (Hi (T3))); + Lemma_Add_Commutation (Double_Uns (Lo (T1)), Hi (T2)); + Lemma_Add_Commutation (Double_Uns (Lo (T2)), Hi (T3)); + pragma Assert + (By (Is_Scaled_Mult_Decomposition + (Big (Double_Uns (Hi (T1))), + Big (Double_Uns (Lo (T1) or Hi (T2))), + Big (Double_Uns (Lo (T2) or Hi (T3))), + Big (Double_Uns (Lo (T3)))), + By (Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Lo (T1) or Hi (T2))) = + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T2))), + Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Lo (T1)) + Double_Uns (Hi (T2))) = + Big_2xxSingle * Big_2xxSingle + * (Big (Double_Uns (Lo (T1))) + Big (Double_Uns (Hi (T2))))) + and then + Big_2xxSingle * Big (Double_Uns (Lo (T2) or Hi (T3))) = + Big_2xxSingle * Big (Double_Uns (Lo (T2))) + + Big_2xxSingle * Big (Double_Uns (Hi (T3))))); end Prove_Dividend_Scaling; -------------------------- @@ -2299,24 +2408,58 @@ is Lemma_Abs_Commutation (X); Lemma_Abs_Commutation (Y); Lemma_Mult_Decomposition (Mult, Xu, Yu, Xhi, Xlo, Yhi, Ylo); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)), + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (Double_Uns'(Xlo * Yhi)), + D4 => Big (Double_Uns'(Xlo * Ylo)))); T1 := Xlo * Ylo; D (4) := Lo (T1); D (3) := Hi (T1); Lemma_Hi_Lo (T1, D (3), D (4)); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)), + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (Double_Uns'(Xlo * Yhi)) + + Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); if Yhi /= 0 then T1 := Xlo * Yhi; Lemma_Hi_Lo (T1, Hi (T1), Lo (T1)); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (Hi (T1))), + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (Double_Uns (Lo (T1))) + + Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); T2 := D (3) + Lo (T1); + Lemma_Add_Commutation (Double_Uns (Lo (T1)), D (3)); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (Hi (T1))), + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (T2), + D4 => Big (Double_Uns (D (4))))); Lemma_Mult_Distribution (Big_2xxSingle, Big (Double_Uns (D (3))), Big (Double_Uns (Lo (T1)))); Lemma_Hi_Lo (T2, Hi (T2), Lo (T2)); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (Hi (T1))) + + Big (Double_Uns (Hi (T2))), + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (Double_Uns (Lo (T2))), + D4 => Big (Double_Uns (D (4))))); D (3) := Lo (T2); D (2) := Hi (T1) + Hi (T2); @@ -2326,31 +2469,131 @@ is pragma Assert (Big (Double_Uns (Hi (T1))) + Big (Double_Uns (Hi (T2))) = Big (Double_Uns (D (2)))); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (D (2))), + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); if Xhi /= 0 then T1 := Xhi * Ylo; Lemma_Hi_Lo (T1, Hi (T1), Lo (T1)); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (D (2))) + + Big (Double_Uns (Hi (T1))), + D3 => Big (Double_Uns (Lo (T1))) + Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + (By (Big_2xxSingle * Big (T1) = + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big (Double_Uns (Lo (T1))), + Big_2xxSingle * Big (T1) = + Big_2xxSingle * (Big_2xxSingle * Big (Double_Uns (Hi (T1))) + + Big (Double_Uns (Lo (T1)))))))); T2 := D (3) + Lo (T1); + Lemma_Add_Commutation (Double_Uns (D (3)), Lo (T1)); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (D (2))) + + Big (Double_Uns (Hi (T1))), + D3 => Big (T2), + D4 => Big (Double_Uns (D (4))))); Lemma_Hi_Lo (T2, Hi (T2), Lo (T2)); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (Double_Uns (D (2))) + + Big (Double_Uns (Hi (T1))) + Big (Double_Uns (Hi (T2))), + D3 => Big (Double_Uns (Lo (T2))), + D4 => Big (Double_Uns (D (4)))), + By (Big_2xxSingle * Big (T2) = + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big_2xxSingle * Big (Double_Uns (Lo (T2))), + Big_2xxSingle * + (Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big (Double_Uns (Lo (T2)))) + = Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big_2xxSingle * Big (Double_Uns (Lo (T2)))))); D (3) := Lo (T2); T3 := D (2) + Hi (T1); + Lemma_Add_Commutation (Double_Uns (D (2)), Hi (T1)); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns'(Xhi * Yhi)) + Big (T3) + + Big (Double_Uns (Hi (T2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); Lemma_Add_Commutation (T3, Hi (T2)); T3 := T3 + Hi (T2); T2 := Double_Uns'(Xhi * Yhi); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (T2) + Big (T3), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); Lemma_Hi_Lo (T2, Hi (T2), Lo (T2)); - Lemma_Add_Commutation (T3, Lo (T2)); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => Big (Double_Uns (Hi (T2))), + D2 => Big (Double_Uns (Lo (T2))) + Big (T3), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + By (Big_2xxSingle * Big_2xxSingle * Big (T2) = + Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Hi (T2))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T2))), + Big_2xxSingle * Big_2xxSingle * + (Big_2xxSingle * Big (Double_Uns (Hi (T2))) + + Big (Double_Uns (Lo (T2)))) + = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Hi (T2))) + + Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Lo (T2)))))); T1 := T3 + Lo (T2); D (2) := Lo (T1); - Lemma_Hi_Lo (T1, Hi (T1), D (2)); + Lemma_Add_Commutation (T3, Lo (T2)); + pragma Assert + (Is_Mult_Decomposition + (D1 => Big (Double_Uns (Hi (T2))), + D2 => Big (T1), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); + Lemma_Hi_Lo (T1, Hi (T1), Lo (T1)); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => Big (Double_Uns (Hi (T2))) + Big (Double_Uns (Hi (T1))), + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + By (Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T1))) = + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))), + D (2) = Lo (T1)) + and then + By (Big_2xxSingle * Big_2xxSingle * Big (T1) = + Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Lo (T1))), + Big_2xxSingle * Big_2xxSingle * + (Big_2xxSingle * Big (Double_Uns (Hi (T1))) + + Big (Double_Uns (Lo (T1)))) + = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Lo (T1)))))); D (1) := Hi (T2) + Hi (T1); @@ -2361,32 +2604,71 @@ is (Big (Double_Uns (Hi (T2))) + Big (Double_Uns (Hi (T1))) = Big (Double_Uns (D (1)))); - pragma Assert (Mult = - Big_2xxSingle - * Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) - + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4)))); - + pragma Assert + (By (Is_Mult_Decomposition + (D1 => Big (Double_Uns (D (1))), + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * + Big (Double_Uns (D (1))) + = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle * + (Big (Double_Uns (Hi (T2)) + Double_Uns (Hi (T1)))))); else D (1) := 0; - end if; - pragma Assert (Mult = - Big_2xxSingle - * Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) - + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4)))); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => Big (Double_Uns (D (1))), + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + Big (Double_Uns'(Xhi * Yhi)) = 0 + and then Big (Double_Uns'(Xhi * Ylo)) = 0 + and then Big (Double_Uns (D (1))) = 0)); + end if; + pragma Assert + (Is_Mult_Decomposition (D1 => Big (Double_Uns (D (1))), + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); else + pragma Assert + (By (Is_Mult_Decomposition + (D1 => 0, + D2 => 0, + D3 => Big (Double_Uns'(Xhi * Ylo)) + Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + Big (Double_Uns'(Xhi * Yhi)) = 0 + and then Big (Double_Uns'(Xlo * Yhi)) = 0)); + if Xhi /= 0 then T1 := Xhi * Ylo; Lemma_Hi_Lo (T1, Hi (T1), Lo (T1)); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns (Hi (T1))), + D3 => Big (Double_Uns (Lo (T1))) + Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + Big_2xxSingle * Big (Double_Uns'(Xhi * Ylo)) = + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (Hi (T1))) + + Big_2xxSingle * Big (Double_Uns (Lo (T1))))); T2 := D (3) + Lo (T1); + Lemma_Add_Commutation (Double_Uns (Lo (T1)), D (3)); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns (Hi (T1))), + D3 => Big (T2), + D4 => Big (Double_Uns (D (4)))), + Big_2xxSingle * Big (T2) = + Big_2xxSingle * + (Big (Double_Uns (Lo (T1))) + Big (Double_Uns (D (3)))))); Lemma_Mult_Distribution (Big_2xxSingle, Big (Double_Uns (D (3))), Big (Double_Uns (Lo (T1)))); @@ -2401,28 +2683,32 @@ is pragma Assert (Big (Double_Uns (Hi (T1))) + Big (Double_Uns (Hi (T2))) = Big (Double_Uns (D (2)))); - pragma Assert (Mult = - Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4)))); + pragma Assert + (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); else D (2) := 0; - pragma Assert (Mult = - Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4)))); + pragma Assert + (By (Is_Mult_Decomposition + (D1 => 0, + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4)))), + Big (Double_Uns'(Xhi * Ylo)) = 0 + and then Big (Double_Uns (D (2))) = 0)); end if; D (1) := 0; end if; - pragma Assert (Mult = - Big_2xxSingle - * Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) - + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4)))); + pragma Assert (Is_Mult_Decomposition (D1 => Big (Double_Uns (D (1))), + D2 => Big (Double_Uns (D (2))), + D3 => Big (Double_Uns (D (3))), + D4 => Big (Double_Uns (D (4))))); -- Now it is time for the dreaded multiple precision division. First an -- easy case, check for the simple case of a one digit divisor. @@ -2627,17 +2913,49 @@ is D (3) := Lo (T2) or Hi (T3); D (4) := Lo (T3); - pragma Assert (Mult * Big_2xx (Scale) = - Big_2xxSingle - * Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) - + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) - + Big_2xxSingle * Big (Double_Uns (D (3))) - + Big (Double_Uns (D (4)))); - Lemma_Substitution (Big_2xxDouble * Big (Zu), Big_2xxDouble, Big (Zu), - Big (Double_Uns'(abs Z)) * Big_2xx (Scale), 0); - Lemma_Lt_Mult (Mult, Big_2xxDouble * Big (Double_Uns'(abs Z)), - Big_2xx (Scale), Big_2xxDouble * Big (Zu)); - Lemma_Div_Lt (Mult * Big_2xx (Scale), Big (Zu), Big_2xxDouble); + pragma Assert (Big (Double_Uns (Hi (T1))) = Big (Double_Uns (D (1)))); + pragma Assert + (Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (Hi (T1))) + = Big_2xxSingle * Big_2xxSingle * Big_2xxSingle + * Big (Double_Uns (D (1)))); + + pragma Assert + (Is_Scaled_Mult_Decomposition + (Big (Double_Uns (D (1))), + Big (Double_Uns (D (2))), + Big (Double_Uns (D (3))), + Big (Double_Uns (D (4))))); + pragma Assert + (By (Is_Scaled_Mult_Decomposition + (0, + 0, + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) + + Big_2xxSingle * Big (Double_Uns (D (2))) + + Big (Double_Uns (D (3))), + Big (Double_Uns (D (4)))), + Big_2xxSingle * + (Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) + + Big_2xxSingle * Big (Double_Uns (D (2))) + + Big (Double_Uns (D (3)))) + + Big (Double_Uns (D (4))) = + Big_2xxSingle * + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) + + Big_2xxSingle * Big (Double_Uns (D (3))) + + Big (Double_Uns (D (4))) + and then + (By (Mult * Big_2xx (Scale) = + Big_2xxSingle * + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))) + + Big_2xxSingle * Big (Double_Uns (D (3))) + + Big (Double_Uns (D (4))), + Is_Scaled_Mult_Decomposition + (Big (Double_Uns (D (1))), + Big (Double_Uns (D (2))), + Big (Double_Uns (D (3))), + Big (Double_Uns (D (4)))))))); Lemma_Substitution (Mult * Big_2xx (Scale), Big_2xxSingle, Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) @@ -2645,8 +2963,38 @@ is + Big (Double_Uns (D (3))), Big3 (D (1), D (2), D (3)), Big (Double_Uns (D (4)))); + Lemma_Substitution (Big_2xxDouble * Big (Zu), Big_2xxDouble, Big (Zu), + Big (Double_Uns'(abs Z)) * Big_2xx (Scale), 0); + Lemma_Lt_Mult (Mult, Big_2xxDouble * Big (Double_Uns'(abs Z)), + Big_2xx (Scale), Big_2xxDouble * Big (Zu)); + Lemma_Div_Lt (Mult * Big_2xx (Scale), Big (Zu), Big_2xxDouble); Lemma_Concat_Definition (D (1), D (2)); Lemma_Double_Big_2xxSingle; + pragma Assert + (Big_2xxSingle * + (Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) + + Big_2xxSingle * Big (Double_Uns (D (2))) + + Big (Double_Uns (D (3)))) + + Big (Double_Uns (D (4))) + = Big_2xxSingle * Big_2xxSingle * + (Big_2xxSingle * Big (Double_Uns (D (1))) + + Big (Double_Uns (D (2)))) + + Big_2xxSingle * Big (Double_Uns (D (3))) + + Big (Double_Uns (D (4)))); + pragma Assert + (By (Is_Scaled_Mult_Decomposition + (0, + Big_2xxSingle * Big (Double_Uns (D (1))) + + Big (Double_Uns (D (2))), + 0, + Big_2xxSingle * Big (Double_Uns (D (3))) + + Big (Double_Uns (D (4)))), + Big_2xxSingle * Big_2xxSingle * + (Big_2xxSingle * Big (Double_Uns (D (1))) + + Big (Double_Uns (D (2)))) = + Big_2xxSingle * + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (1))) + + Big_2xxSingle * Big_2xxSingle * Big (Double_Uns (D (2))))); Lemma_Substitution (Mult * Big_2xx (Scale), Big_2xxSingle * Big_2xxSingle, Big_2xxSingle * Big (Double_Uns (D (1))) diff --git a/gcc/ada/libgnat/s-arit32.adb b/gcc/ada/libgnat/s-arit32.adb index baec78a..3d500ac 100644 --- a/gcc/ada/libgnat/s-arit32.adb +++ b/gcc/ada/libgnat/s-arit32.adb @@ -474,6 +474,7 @@ is D := Uns64 (Xu) * Uns64 (Yu); + Lemma_Abs_Mult_Commutation (Big (X), Big (Y)); pragma Assert (Mult = Big (D)); Lemma_Hi_Lo (D, Hi (D), Lo (D)); pragma Assert (Mult = Big_2xx32 * Big (Hi (D)) + Big (Lo (D))); @@ -508,7 +509,6 @@ is Lemma_Abs_Div_Commutation (Big (X) * Big (Y), Big (Z)); Lemma_Abs_Rem_Commutation (Big (X) * Big (Y), Big (Z)); - Lemma_Abs_Mult_Commutation (Big (X), Big (Y)); Lemma_Abs_Commutation (X); Lemma_Abs_Commutation (Y); Lemma_Abs_Commutation (Z); diff --git a/gcc/ada/libgnat/s-dwalin.adb b/gcc/ada/libgnat/s-dwalin.adb index 5a0a2f6..e1e55f3 100644 --- a/gcc/ada/libgnat/s-dwalin.adb +++ b/gcc/ada/libgnat/s-dwalin.adb @@ -44,6 +44,8 @@ with System.Storage_Elements; use System.Storage_Elements; package body System.Dwarf_Lines is + subtype Offset is Object_Reader.Offset; + function Get_Load_Displacement (C : Dwarf_Context) return Storage_Offset; -- Return the displacement between the load address present in the binary -- and the run-time address at which it is loaded (i.e. non-zero for PIE). diff --git a/gcc/ada/libgnat/s-gearop.adb b/gcc/ada/libgnat/s-gearop.adb index 32c67c3..78f4ba8 100644 --- a/gcc/ada/libgnat/s-gearop.adb +++ b/gcc/ada/libgnat/s-gearop.adb @@ -32,7 +32,8 @@ -- Preconditions, postconditions, ghost code, loop invariants and assertions -- in this unit are meant for analysis only, not for run-time checking, as it -- would be too costly otherwise. This is enforced by setting the assertion --- policy to Ignore. +-- policy to Ignore, here for non-generic code, and inside the generic for +-- generic code. pragma Assertion_Policy (Pre => Ignore, Post => Ignore, @@ -72,6 +73,12 @@ is -------------- function Diagonal (A : Matrix) return Vector is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); + N : constant Natural := Natural'Min (A'Length (1), A'Length (2)); begin return R : Vector (A'First (1) .. A'First (1) + (N - 1)) @@ -126,6 +133,11 @@ is --------------------- procedure Back_Substitute (M, N : in out Matrix) is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); pragma Assert (M'First (1) = N'First (1) and then M'Last (1) = N'Last (1)); @@ -215,6 +227,11 @@ is N : in out Matrix; Det : out Scalar) is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); pragma Assert (M'First (1) = N'First (1) and then M'Last (1) = N'Last (1)); @@ -460,6 +477,11 @@ is ------------- function L2_Norm (X : X_Vector) return Result_Real'Base is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); Sum : Result_Real'Base := 0.0; begin @@ -479,6 +501,11 @@ is ---------------------------------- function Matrix_Elementwise_Operation (X : X_Matrix) return Result_Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Result_Matrix (X'Range (1), X'Range (2)) with Relaxed_Initialization @@ -524,6 +551,11 @@ is (Left : Left_Matrix; Right : Right_Matrix) return Result_Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Result_Matrix (Left'Range (1), Left'Range (2)) with Relaxed_Initialization @@ -570,6 +602,11 @@ is Y : Y_Matrix; Z : Z_Scalar) return Result_Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Result_Matrix (X'Range (1), X'Range (2)) with Relaxed_Initialization @@ -657,6 +694,11 @@ is (Left : Left_Matrix; Right : Right_Scalar) return Result_Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Result_Matrix (Left'Range (1), Left'Range (2)) with Relaxed_Initialization @@ -705,6 +747,11 @@ is (Left : Left_Scalar; Right : Right_Matrix) return Result_Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Result_Matrix (Right'Range (1), Right'Range (2)) with Relaxed_Initialization @@ -811,6 +858,11 @@ is (Left : Left_Matrix; Right : Right_Matrix) return Result_Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Result_Matrix (Left'Range (1), Right'Range (2)) with Relaxed_Initialization @@ -856,6 +908,11 @@ is ---------------------------- function Matrix_Vector_Solution (A : Matrix; X : Vector) return Vector is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); procedure Ignore (M : Matrix) with @@ -917,6 +974,11 @@ is ---------------------------- function Matrix_Matrix_Solution (A, X : Matrix) return Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); procedure Ignore (M : Matrix) with @@ -1035,6 +1097,11 @@ is (Left : Left_Vector; Right : Right_Vector) return Matrix is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin return R : Matrix (Left'Range, Right'Range) with Relaxed_Initialization @@ -1078,6 +1145,11 @@ is --------------- procedure Transpose (A : Matrix; R : out Matrix) is + pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); begin for J in R'Range (1) loop for K in R'Range (2) loop diff --git a/gcc/ada/libgnat/s-gearop.ads b/gcc/ada/libgnat/s-gearop.ads index 15e1174..f5ee8bc 100644 --- a/gcc/ada/libgnat/s-gearop.ads +++ b/gcc/ada/libgnat/s-gearop.ads @@ -36,16 +36,10 @@ -- overflows in arithmetic operations passed on as formal generic subprogram -- parameters. --- Preconditions in this unit are meant for analysis only, not for run-time --- checking, so that the expected exceptions are raised. This is enforced --- by setting the corresponding assertion policy to Ignore. Postconditions --- and contract cases should not be executed at runtime as well, in order --- not to slow down the execution of these functions. - -pragma Assertion_Policy (Pre => Ignore, - Post => Ignore, - Contract_Cases => Ignore, - Ghost => Ignore); +-- Preconditions in this unit are meant mostly for analysis, but will be +-- activated at runtime depending on the assertion policy for preconditions at +-- the program point of instantiation. These preconditions are simply checking +-- bounds, so should not impact running time. package System.Generic_Array_Operations with SPARK_Mode diff --git a/gcc/ada/libgnat/s-spark.ads b/gcc/ada/libgnat/s-spark.ads new file mode 100644 index 0000000..25a18a4 --- /dev/null +++ b/gcc/ada/libgnat/s-spark.ads @@ -0,0 +1,36 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- S Y S T E M . S P A R K -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2022, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +package System.SPARK with + SPARK_Mode, + Pure +is +end System.SPARK; diff --git a/gcc/ada/libgnat/s-spcuop.adb b/gcc/ada/libgnat/s-spcuop.adb new file mode 100644 index 0000000..d91f897 --- /dev/null +++ b/gcc/ada/libgnat/s-spcuop.adb @@ -0,0 +1,42 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- S Y S T E M . S P A R K . C U T _ O P E R A T I O N S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2022, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +package body System.SPARK.Cut_Operations with + SPARK_Mode => Off +is + + function By (Consequence, Premise : Boolean) return Boolean is + (Premise and then Consequence); + + function So (Premise, Consequence : Boolean) return Boolean is + (Premise and then Consequence); + +end System.SPARK.Cut_Operations; diff --git a/gcc/ada/libgnat/s-spcuop.ads b/gcc/ada/libgnat/s-spcuop.ads new file mode 100644 index 0000000..39a61c9 --- /dev/null +++ b/gcc/ada/libgnat/s-spcuop.ads @@ -0,0 +1,59 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- S Y S T E M . S P A R K . C U T _ O P E R A T I O N S -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2022, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- By and So are connectors used to manually help the proof of assertions by +-- introducing intermediate steps. They can only be used inside pragmas +-- Assert or Assert_And_Cut. They are handled in the following way: +-- +-- * If A and B are two boolean expressions, proving By (A, B) requires +-- proving B, the premise, and then A assuming B, the side-condition. When +-- By (A, B) is assumed on the other hand, we only assume A. B is used +-- for the proof, but is not visible afterward. +-- +-- * If A and B are two boolean expressions, proving So (A, B) requires +-- proving A, the premise, and then B assuming A, the side-condition. When +-- So (A, B) is assumed both A and B are assumed to be true. + +package System.SPARK.Cut_Operations with + SPARK_Mode, + Pure, + Annotate => (GNATprove, Terminating) +is + + function By (Consequence, Premise : Boolean) return Boolean with + Ghost, + Global => null; + + function So (Premise, Consequence : Boolean) return Boolean with + Ghost, + Global => null; + +end System.SPARK.Cut_Operations; diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads index 2ce24ee..c2abbce 100644 --- a/gcc/ada/opt.ads +++ b/gcc/ada/opt.ads @@ -262,6 +262,9 @@ package Opt is -- Set to True to build, bind and link all the sources of a project file -- (switch -B) + CCG_Mode : Boolean := False; + -- Set to True when running as CCG (either via -gnatceg or via -emit-c) + Check_Aliasing_Of_Parameters : Boolean := False; -- GNAT -- Set to True to detect whether subprogram parameters and function results diff --git a/gcc/ada/osint.adb b/gcc/ada/osint.adb index a38ad78..eeedfcb 100644 --- a/gcc/ada/osint.adb +++ b/gcc/ada/osint.adb @@ -1886,13 +1886,13 @@ package body Osint is end if; declare - Full_Name : String (1 .. Dir_Name'Length + Name'Length + 1); + Full_Name : + constant String (1 .. Dir_Name'Length + Name'Length + 1) := + Dir_Name.all & Name & ASCII.NUL; + -- Use explicit bounds, because Dir_Name might be a substring whose + -- 'First is not 1. begin - Full_Name (1 .. Dir_Name'Length) := Dir_Name.all; - Full_Name (Dir_Name'Length + 1 .. Full_Name'Last - 1) := Name; - Full_Name (Full_Name'Last) := ASCII.NUL; - Attr.all := Unknown_Attributes; if not Is_Regular_File (Full_Name'Address, Attr) then diff --git a/gcc/ada/par-ch6.adb b/gcc/ada/par-ch6.adb index 2832fd4..95fa937 100644 --- a/gcc/ada/par-ch6.adb +++ b/gcc/ada/par-ch6.adb @@ -1656,6 +1656,28 @@ package body Ch6 is P_Aspect_Specifications (Specification_Node, False); + -- Set the aspect specifications for previous Ids + + if Has_Aspects (Specification_Node) + and then Prev_Ids (Specification_Node) + then + -- Loop through each previous id + + declare + Prev_Id : Node_Id := Prev (Specification_Node); + begin + loop + Set_Aspect_Specifications + (Prev_Id, Aspect_Specifications (Specification_Node)); + + -- Exit when we reach the first parameter in the list + + exit when not Prev_Ids (Prev_Id); + Prev_Id := Prev (Prev_Id); + end loop; + end; + end if; + if Token = Tok_Right_Paren then Scan; -- past right paren exit Specification_Loop; diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index 7b05cdc..e6e06f6 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -12144,11 +12144,15 @@ package body Sem_Attr is elsif Scope (Subp_Id) /= Current_Scope then null; + -- Dispatch tables are not a freeze point either + + elsif Nkind (Parent (N)) = N_Unchecked_Type_Conversion + and then Is_Dispatch_Table_Entity (Etype (Parent (N))) + then + null; + -- Analyze the body of the expression function to freeze - -- the expression. This takes care of the case where the - -- 'Access is part of dispatch table initialization and - -- the generated body of the expression function has not - -- been analyzed yet. + -- the expression. else Analyze (Subp_Body); diff --git a/gcc/ada/sem_ch11.adb b/gcc/ada/sem_ch11.adb index 034d4cd..a15fd09 100644 --- a/gcc/ada/sem_ch11.adb +++ b/gcc/ada/sem_ch11.adb @@ -432,8 +432,7 @@ package body Sem_Ch11 is -- If the current scope is a subprogram, entry or task body or declare -- block then this is the right place to check for hanging useless -- assignments from the statement sequence. Skip this in the body of a - -- postcondition, since in that case there are no source references, and - -- we need to preserve deferred references from the enclosing scope. + -- postcondition, since in that case there are no source references. if (Is_Subprogram_Or_Entry (Current_Scope) and then Chars (Current_Scope) /= Name_uPostconditions) diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb index 11abdd8..fdc767e 100644 --- a/gcc/ada/sem_ch13.adb +++ b/gcc/ada/sem_ch13.adb @@ -180,7 +180,8 @@ package body Sem_Ch13 is function Is_Predicate_Static (Expr : Node_Id; - Nam : Name_Id) return Boolean; + Nam : Name_Id; + Warn : Boolean := True) return Boolean; -- Given predicate expression Expr, tests if Expr is predicate-static in -- the sense of the rules in (RM 3.2.4 (15-24)). Occurrences of the type -- name in the predicate expression have been replaced by references to @@ -205,6 +206,11 @@ package body Sem_Ch13 is -- -- We can't allow this, otherwise we have predicate-static applying to a -- larger class than static expressions, which was never intended. + -- + -- The Warn parameter is True iff this is not a recursive call. This + -- parameter is used to avoid generating warnings for subexpressions and + -- for cases where the predicate expression (as originally written by + -- the user, before any transformations) is a Boolean literal. procedure New_Put_Image_Subprogram (N : Node_Id; @@ -6699,7 +6705,7 @@ package body Sem_Ch13 is and then not Overlays_Constant (U_Ent) and then Address_Clause_Overlay_Warnings then - Error_Msg_N ("??constant overlays a variable", Expr); + Error_Msg_N ("?o?constant overlays a variable", Expr); -- Imported variables can have an address clause, but then -- the import is pretty meaningless except to suppress @@ -14000,7 +14006,8 @@ package body Sem_Ch13 is function Is_Predicate_Static (Expr : Node_Id; - Nam : Name_Id) return Boolean + Nam : Name_Id; + Warn : Boolean := True) return Boolean is function All_Static_Case_Alternatives (L : List_Id) return Boolean; -- Given a list of case expression alternatives, returns True if all @@ -14050,13 +14057,42 @@ package body Sem_Ch13 is begin return (Nkind (N) = N_Identifier and then Chars (N) = Nam - and then Paren_Count (N) = 0) - or else Nkind (N) = N_Function_Call; + and then Paren_Count (N) = 0); end Is_Type_Ref; + -- helper function for recursive calls + function Is_Predicate_Static_Aux (Expr : Node_Id) return Boolean is + (Is_Predicate_Static (Expr, Nam, Warn => False)); + -- Start of processing for Is_Predicate_Static begin + -- Handle cases like + -- subtype S is Integer with Static_Predicate => + -- (Some_Integer_Variable in Integer) and then (S /= 0); + -- where the predicate (which should be rejected) might have been + -- transformed into just "(S /= 0)", which would appear to be + -- a predicate-static expression (and therefore legal). + + if Original_Node (Expr) /= Expr then + + -- Emit warnings for predicates that are always True or always False + -- and were not originally expressed as Boolean literals. + + return Result : constant Boolean := + Is_Predicate_Static_Aux (Original_Node (Expr)) + do + if Result and then Warn and then Is_Entity_Name (Expr) then + if Entity (Expr) = Standard_True then + Error_Msg_N ("predicate is redundant (always True)?", Expr); + elsif Entity (Expr) = Standard_False then + Error_Msg_N + ("predicate is unsatisfiable (always False)?", Expr); + end if; + end if; + end return; + end if; + -- Predicate_Static means one of the following holds. Numbers are the -- corresponding paragraph numbers in (RM 3.2.4(16-22)). @@ -14070,6 +14106,7 @@ package body Sem_Ch13 is -- for a static membership test. elsif Nkind (Expr) in N_Membership_Test + and then Is_Type_Ref (Left_Opnd (Expr)) and then All_Membership_Choices_Static (Expr) then return True; @@ -14115,11 +14152,11 @@ package body Sem_Ch13 is -- operand is predicate-static. elsif (Nkind (Expr) in N_Op_And | N_Op_Or | N_Op_Xor - and then Is_Predicate_Static (Left_Opnd (Expr), Nam) - and then Is_Predicate_Static (Right_Opnd (Expr), Nam)) + and then Is_Predicate_Static_Aux (Left_Opnd (Expr)) + and then Is_Predicate_Static_Aux (Right_Opnd (Expr))) or else (Nkind (Expr) = N_Op_Not - and then Is_Predicate_Static (Right_Opnd (Expr), Nam)) + and then Is_Predicate_Static_Aux (Right_Opnd (Expr))) then return True; @@ -14127,8 +14164,8 @@ package body Sem_Ch13 is -- predicate-static. elsif Nkind (Expr) in N_Short_Circuit - and then Is_Predicate_Static (Left_Opnd (Expr), Nam) - and then Is_Predicate_Static (Right_Opnd (Expr), Nam) + and then Is_Predicate_Static_Aux (Left_Opnd (Expr)) + and then Is_Predicate_Static_Aux (Right_Opnd (Expr)) then return True; @@ -14159,12 +14196,6 @@ package body Sem_Ch13 is then return True; - elsif Is_Entity_Name (Expr) - and then Entity (Expr) = Standard_True - then - Error_Msg_N ("predicate is redundant (always True)?", Expr); - return True; - -- That's an exhaustive list of tests, all other cases are not -- predicate-static, so we return False. diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index e6d34c3..66315ad 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -1207,21 +1207,12 @@ package body Sem_Ch5 is -- There may have been a previous reference to a component of -- the variable, which in general removes the Last_Assignment -- field of the variable to indicate a relevant use of the - -- previous assignment. However, if the assignment is to a - -- subcomponent the reference may not have registered, because - -- it is not possible to determine whether the context is an - -- assignment. In those cases we generate a Deferred_Reference, - -- to be used at the end of compilation to generate the right - -- kind of reference, and we suppress a potential warning for - -- a useless assignment, which might be premature. This may - -- lose a warning in rare cases, but seems preferable to a - -- misleading warning. + -- previous assignment. if Warn_On_Modified_Unread and then Is_Assignable (Ent) and then Comes_From_Source (N) and then In_Extended_Main_Source_Unit (Ent) - and then not Has_Deferred_Reference (Ent) and then not Has_Target_Names (N) then Warn_On_Useless_Assignment (Ent, N); diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb index a537358..8ca2974 100644 --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -2063,6 +2063,11 @@ package body Sem_Ch6 is Analyze_Generic_Subprogram_Body (Null_Body, Prev); Is_Completion := True; + -- Mark the newly generated subprogram body as trivial + + Set_Is_Trivial_Subprogram + (Defining_Unit_Name (Specification (Null_Body))); + goto Leave; else @@ -12303,7 +12308,34 @@ package body Sem_Ch6 is -- Work done in Override_Dispatching_Operation, so -- nothing else needs to be done here. - null; + -- ??? Special case to keep supporting the hiding + -- of the predefined "=" operator for a nonlimited + -- tagged type by a user-defined "=" operator for + -- its class-wide type when the type is private. + + if Chars (E) = Name_Op_Eq then + declare + Typ : constant Entity_Id + := Etype (First_Entity (E)); + H : Entity_Id := Homonym (E); + + begin + while Present (H) + and then Scope (H) = Scope (E) + loop + if Is_User_Defined_Equality (H) + and then Is_Immediately_Visible (H) + and then Etype (First_Entity (H)) + = Class_Wide_Type (Typ) + then + Remove_Entity_And_Homonym (E); + exit; + end if; + + H := Homonym (H); + end loop; + end; + end if; end if; else diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb index c43686b..03aecc0 100644 --- a/gcc/ada/sem_ch7.adb +++ b/gcc/ada/sem_ch7.adb @@ -409,7 +409,7 @@ package body Sem_Ch7 is -- should occur, so we need to catch all cases where the -- subprogram may be inlined by the client. - if not Generate_C_Code + if not CCG_Mode and then (Is_Inlined (Decl_Id) or else Has_Pragma_Inline (Decl_Id)) then @@ -431,7 +431,7 @@ package body Sem_Ch7 is -- unless we generate C code since inlining is then -- handled by the C compiler. - if not Generate_C_Code + if not CCG_Mode and then (Is_Inlined (Decl_Id) or else Has_Pragma_Inline (Decl_Id)) then diff --git a/gcc/ada/sem_disp.adb b/gcc/ada/sem_disp.adb index 0372ff8..3e75a47 100644 --- a/gcc/ada/sem_disp.adb +++ b/gcc/ada/sem_disp.adb @@ -1207,7 +1207,7 @@ package body Sem_Disp is Error_Msg_Name_2 := Chars (E); Error_Msg_Sloc := Sloc (E); Error_Msg_N - ("?j?primitive of type % defined after private extension " + ("?.j?primitive of type % defined after private extension " & "% #?", Prim); Error_Msg_Name_1 := Chars (Prim); Error_Msg_Name_2 := Chars (E); diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb index 068402a..0d5befc 100644 --- a/gcc/ada/sem_elab.adb +++ b/gcc/ada/sem_elab.adb @@ -4958,7 +4958,7 @@ package body Sem_Elab is then Error_Msg_Name_1 := Attribute_Name (Attr); Error_Msg_NE - ("??% attribute of & before body seen", Attr, Subp_Id); + ("?.f?% attribute of & before body seen", Attr, Subp_Id); Error_Msg_N ("\possible Program_Error on later references", Attr); Output_Active_Scenarios (Attr, New_In_State); diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb index 930980e..4ffb64c 100644 --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -11211,22 +11211,6 @@ package body Sem_Res is else T := Etype (P); - - -- If the prefix is an entity it may have a deferred reference set - -- during analysis of the selected component. After resolution we - -- can transform it into a proper reference. This prevents spurious - -- warnings on useless assignments when the same selected component - -- is the actual for an out parameter in a subsequent call. - - if Is_Entity_Name (P) - and then Has_Deferred_Reference (Entity (P)) - then - if Known_To_Be_Assigned (N) then - Generate_Reference (Entity (P), P, 'm'); - else - Generate_Reference (Entity (P), P, 'r'); - end if; - end if; end if; -- Set flag for expander if discriminant check required on a component diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index 0a80915..7cfd5f4 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -9309,8 +9309,8 @@ package body Sem_Util is return; -- An actual that is the prefix in a prefixed call may have - -- been rewritten in the call, after the deferred reference - -- was collected. Check if sloc and kinds and names match. + -- been rewritten in the call. Check if sloc and kinds and + -- names match. elsif Sloc (Actual) = Sloc (N) and then Nkind (Actual) = N_Identifier @@ -25893,7 +25893,7 @@ package body Sem_Util is Error_Msg_Sloc := Sloc (Addr); Error_Msg_NE - ("??constant& may be modified via address clause#", + ("?o?constant& may be modified via address clause#", N, O_Ent); end; end if; diff --git a/gcc/ada/sem_warn.adb b/gcc/ada/sem_warn.adb index c8d00a5..2512357 100644 --- a/gcc/ada/sem_warn.adb +++ b/gcc/ada/sem_warn.adb @@ -31,7 +31,6 @@ with Einfo.Utils; use Einfo.Utils; with Errout; use Errout; with Exp_Code; use Exp_Code; with Lib; use Lib; -with Lib.Xref; use Lib.Xref; with Namet; use Namet; with Nlists; use Nlists; with Opt; use Opt; @@ -1132,8 +1131,6 @@ package body Sem_Warn is -- Start of processing for Check_References begin - Process_Deferred_References; - -- No messages if warnings are suppressed, or if we have detected any -- real errors so far (this last check avoids junk messages resulting -- from errors, e.g. a subunit that is not loaded). @@ -2762,8 +2759,6 @@ package body Sem_Warn is return; end if; - Process_Deferred_References; - -- Flag any unused with clauses. For a subunit, check only the units -- in its context, not those of the parent, which may be needed by other -- subunits. We will get the full warnings when we compile the parent, @@ -4600,7 +4595,7 @@ package body Sem_Warn is then if Warn_On_All_Unread_Out_Parameters then Error_Msg_NE - ("?m?& modified by call, but value might not " + ("?.o?& modified by call, but value might not " & "be referenced", LA, Ent); end if; else @@ -4703,8 +4698,6 @@ package body Sem_Warn is Ent : Entity_Id; begin - Process_Deferred_References; - if Warn_On_Modified_Unread and then In_Extended_Main_Source_Unit (E) then diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index e3e06ee..da42ae5 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -1005,12 +1005,6 @@ package Sinfo is -- direct conversion of the underlying integer result, with no regard to -- the small operand. - -- Convert_To_Return_False - -- Present in N_Raise_Expression nodes that appear in the body of the - -- special predicateM function used to test a predicate in the context - -- of a membership test, where raise expression results in returning a - -- value of False rather than raising an exception. - -- Corresponding_Aspect -- Present in N_Pragma node. Used to point back to the source aspect from -- the corresponding pragma. This field is Empty for source pragmas. @@ -6932,7 +6926,6 @@ package Sinfo is -- Sloc points to RAISE -- Name (always present) -- Expression (set to Empty if no expression present) - -- Convert_To_Return_False -- plus fields for expression ------------------------------- diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index fa3c231..6bceab8 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,14 @@ +2022-05-23 David Malcolm <dmalcolm@redhat.com> + + * call-info.cc: Add "final" and "override" to all vfunc + implementations that were missing them, as appropriate. + * engine.cc: Likewise. + * region-model.cc: Likewise. + * sm-malloc.cc: Likewise. + * supergraph.h: Likewise. + * svalue.cc: Likewise. + * varargs.cc: Likewise. + 2022-05-20 David Malcolm <dmalcolm@redhat.com> * analyzer-pass.cc: Replace uses of "FINAL" and "OVERRIDE" with diff --git a/gcc/asan.cc b/gcc/asan.cc index 4b583e5..15b2cf8 100644 --- a/gcc/asan.cc +++ b/gcc/asan.cc @@ -1285,7 +1285,20 @@ has_stmt_been_instrumented_p (gimple *stmt) if (get_mem_ref_of_assignment (as_a <gassign *> (stmt), &r, &r_is_store)) - return has_mem_ref_been_instrumented (&r); + { + if (!has_mem_ref_been_instrumented (&r)) + return false; + if (r_is_store && gimple_assign_load_p (stmt)) + { + asan_mem_ref src; + asan_mem_ref_init (&src, NULL, 1); + src.start = gimple_assign_rhs1 (stmt); + src.access_size = int_size_in_bytes (TREE_TYPE (src.start)); + if (!has_mem_ref_been_instrumented (&src)) + return false; + } + return true; + } } else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) { diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 2f3071c..2c0d86f 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2022-05-27 Marek Polacek <polacek@redhat.com> + + PR c/90658 + * c-attribs.cc (get_priority): Check FUNCTION_DECL. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + * c-pragma.h (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_ENTER. + 2022-05-20 David Malcolm <dmalcolm@redhat.com> * c-format.cc: Replace uses of "FINAL" and "OVERRIDE" with "final" diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 4dc68db..c8d9672 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -1895,7 +1895,7 @@ get_priority (tree args, bool is_destructor) } arg = TREE_VALUE (args); - if (TREE_CODE (arg) == IDENTIFIER_NODE) + if (TREE_CODE (arg) == IDENTIFIER_NODE || TREE_CODE (arg) == FUNCTION_DECL) goto invalid; if (arg == error_mark_node) return DEFAULT_INIT_PRIORITY; diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 54864c2..d5d4fe3 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -90,7 +90,7 @@ enum pragma_kind { /* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, 4.0, 4.5, 5.0, - and 5.1. Used internally by both C and C++ parsers. */ + 5.1 and 5.2. Used internally by both C and C++ parsers. */ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_NONE = 0, @@ -108,6 +108,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_DEVICE, PRAGMA_OMP_CLAUSE_DEVICE_TYPE, PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, + PRAGMA_OMP_CLAUSE_ENTER, PRAGMA_OMP_CLAUSE_FILTER, PRAGMA_OMP_CLAUSE_FINAL, PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 00e236c..1de21db 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,41 @@ +2022-05-28 Jakub Jelinek <jakub@redhat.com> + + * c-parser.cc (c_parser_omp_declare_target): If OMP_CLAUSE_LINK was + seen first, use "%<to%>" or "%<enter%>" depending on + OMP_CLAUSE_ENTER_TO of the current clause, otherwise use + "%<to%> or %<enter%>" wording. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + * c-parser.cc (c_parser_omp_clause_name): Parse enter clause. + (c_parser_omp_all_clauses): For to clause on declare target, use + OMP_CLAUSE_ENTER clause with OMP_CLAUSE_ENTER_TO instead of + OMP_CLAUSE_TO_DECLARE clause. Handle PRAGMA_OMP_CLAUSE_ENTER. + (OMP_DECLARE_TARGET_CLAUSE_MASK): Add enter clause. + (c_parser_omp_declare_target): Use OMP_CLAUSE_ENTER instead of + OMP_CLAUSE_TO_DECLARE. + * c-typeck.cc (c_finish_omp_clauses): Handle OMP_CLAUSE_ENTER instead + of OMP_CLAUSE_TO_DECLARE, to OMP_CLAUSE_ENTER_TO use "to" as clause + name in diagnostics instead of + omp_clause_code_name[OMP_CLAUSE_CODE (c)]. + +2022-05-25 Jakub Jelinek <jakub@redhat.com> + + PR c/91134 + * c-tree.h (build_component_ref): Add ARROW_LOC location_t argument. + * c-typeck.cc (build_component_ref): Likewise. If DATUM is + INDIRECT_REF and ARROW_LOC isn't UNKNOWN_LOCATION, print a different + diagnostic and fixit hint if DATUM has pointer type. + * c-parser.cc (c_parser_postfix_expression, + c_parser_omp_variable_list): Adjust build_component_ref callers. + * gimple-parser.cc (c_parser_gimple_postfix_expression_after_primary): + Likewise. + +2022-05-24 Jakub Jelinek <jakub@redhat.com> + + PR c/105378 + * c-parser.cc (OMP_TASKWAIT_CLAUSE_MASK): Add nowait clause. + 2022-05-18 Marek Polacek <polacek@redhat.com> PR c/105131 diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 8df8f60..7cc4d93c 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -9235,8 +9235,9 @@ c_parser_postfix_expression (c_parser *parser) if (c_parser_next_token_is (parser, CPP_NAME)) { c_token *comp_tok = c_parser_peek_token (parser); - offsetof_ref = build_component_ref - (loc, offsetof_ref, comp_tok->value, comp_tok->location); + offsetof_ref + = build_component_ref (loc, offsetof_ref, comp_tok->value, + comp_tok->location, UNKNOWN_LOCATION); c_parser_consume_token (parser); while (c_parser_next_token_is (parser, CPP_DOT) || c_parser_next_token_is (parser, @@ -9263,9 +9264,11 @@ c_parser_postfix_expression (c_parser *parser) break; } c_token *comp_tok = c_parser_peek_token (parser); - offsetof_ref = build_component_ref - (loc, offsetof_ref, comp_tok->value, - comp_tok->location); + offsetof_ref + = build_component_ref (loc, offsetof_ref, + comp_tok->value, + comp_tok->location, + UNKNOWN_LOCATION); c_parser_consume_token (parser); } else @@ -10612,7 +10615,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, finish = c_parser_peek_token (parser)->get_finish (); c_parser_consume_token (parser); expr.value = build_component_ref (op_loc, expr.value, ident, - comp_loc); + comp_loc, UNKNOWN_LOCATION); set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) @@ -10652,7 +10655,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser, build_indirect_ref (op_loc, expr.value, RO_ARROW), - ident, comp_loc); + ident, comp_loc, + expr.get_location ()); set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) @@ -12767,6 +12771,10 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("dist_schedule", p)) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; + case 'e': + if (!strcmp ("enter", p)) + result = PRAGMA_OMP_CLAUSE_ENTER; + break; case 'f': if (!strcmp ("filter", p)) result = PRAGMA_OMP_CLAUSE_FILTER; @@ -13171,6 +13179,7 @@ c_parser_omp_variable_list (c_parser *parser, && c_parser_next_token_is (parser, CPP_DEREF))) { location_t op_loc = c_parser_peek_token (parser)->location; + location_t arrow_loc = UNKNOWN_LOCATION; if (c_parser_next_token_is (parser, CPP_DEREF)) { c_expr t_expr; @@ -13181,6 +13190,7 @@ c_parser_omp_variable_list (c_parser *parser, t_expr = convert_lvalue_to_rvalue (op_loc, t_expr, true, false); t = build_indirect_ref (op_loc, t_expr.value, RO_ARROW); + arrow_loc = t_expr.get_location (); } c_parser_consume_token (parser); if (!c_parser_next_token_is (parser, CPP_NAME)) @@ -13194,7 +13204,8 @@ c_parser_omp_variable_list (c_parser *parser, tree ident = comp_tok->value; location_t comp_loc = comp_tok->location; c_parser_consume_token (parser); - t = build_component_ref (op_loc, t, ident, comp_loc); + t = build_component_ref (op_loc, t, ident, comp_loc, + arrow_loc); } /* FALLTHROUGH */ case OMP_CLAUSE_AFFINITY: @@ -17048,9 +17059,13 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, break; case PRAGMA_OMP_CLAUSE_TO: if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) - clauses - = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, - clauses); + { + tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ENTER, + clauses); + for (tree c = nl; c != clauses; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ENTER_TO (c) = 1; + clauses = nl; + } else clauses = c_parser_omp_clause_to (parser, clauses); c_name = "to"; @@ -17151,6 +17166,12 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses); c_name = "simd"; break; + case PRAGMA_OMP_CLAUSE_ENTER: + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ENTER, + clauses); + c_name = "enter"; + break; default: c_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -20453,7 +20474,8 @@ c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) */ #define OMP_TASKWAIT_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static void c_parser_omp_taskwait (c_parser *parser) @@ -21998,6 +22020,7 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms, #define OMP_DECLARE_TARGET_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ENTER) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)) @@ -22012,7 +22035,7 @@ c_parser_omp_declare_target (c_parser *parser) "#pragma omp declare target"); else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) { - clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ENTER, clauses); clauses = c_finish_omp_clauses (clauses, C_ORT_OMP); c_parser_skip_to_pragma_eol (parser); @@ -22044,9 +22067,14 @@ c_parser_omp_declare_target (c_parser *parser) id = get_identifier ("omp declare target"); if (at2) { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD specified both in declare target %<link%> and %<to%>" - " clauses", t); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target %<link%> and %qs" + " clauses", t, OMP_CLAUSE_ENTER_TO (c) ? "to" : "enter"); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target %<link%> and " + "%<to%> or %<enter%> clauses", t); continue; } if (!at1) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 2bcb966..3b322ad 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -699,7 +699,8 @@ extern struct c_expr convert_lvalue_to_rvalue (location_t, struct c_expr, extern tree decl_constant_value_1 (tree, bool); extern void mark_exp_read (tree); extern tree composite_type (tree, tree); -extern tree build_component_ref (location_t, tree, tree, location_t); +extern tree build_component_ref (location_t, tree, tree, location_t, + location_t); extern tree build_array_ref (location_t, tree, tree); extern tree build_external_ref (location_t, tree, bool, tree *); extern void pop_maybe_used (bool); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 4f3611f..21a93c3 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -2457,11 +2457,12 @@ should_suggest_deref_p (tree datum_type) /* Make an expression to refer to the COMPONENT field of structure or union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the location of the COMPONENT_REF. COMPONENT_LOC is the location - of COMPONENT. */ + of COMPONENT. ARROW_LOC is the location of the first -> operand if + it is from -> operator. */ tree build_component_ref (location_t loc, tree datum, tree component, - location_t component_loc) + location_t component_loc, location_t arrow_loc) { tree type = TREE_TYPE (datum); enum tree_code code = TREE_CODE (type); @@ -2577,11 +2578,23 @@ build_component_ref (location_t loc, tree datum, tree component, /* Special-case the error message for "ptr.field" for the case where the user has confused "." vs "->". */ rich_location richloc (line_table, loc); - /* "loc" should be the "." token. */ - richloc.add_fixit_replace ("->"); - error_at (&richloc, - "%qE is a pointer; did you mean to use %<->%>?", - datum); + if (TREE_CODE (datum) == INDIRECT_REF && arrow_loc != UNKNOWN_LOCATION) + { + richloc.add_fixit_insert_before (arrow_loc, "(*"); + richloc.add_fixit_insert_after (arrow_loc, ")"); + error_at (&richloc, + "%qE is a pointer to pointer; did you mean to dereference " + "it before applying %<->%> to it?", + TREE_OPERAND (datum, 0)); + } + else + { + /* "loc" should be the "." token. */ + richloc.add_fixit_replace ("->"); + error_at (&richloc, + "%qE is a pointer; did you mean to use %<->%>?", + datum); + } return error_mark_node; } else if (code != ERROR_MARK) @@ -15235,37 +15248,40 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; - case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_ENTER: case OMP_CLAUSE_LINK: t = OMP_CLAUSE_DECL (c); + const char *cname; + cname = omp_clause_code_name[OMP_CLAUSE_CODE (c)]; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER + && OMP_CLAUSE_ENTER_TO (c)) + cname = "to"; if (TREE_CODE (t) == FUNCTION_DECL - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) ; else if (!VAR_P (t)) { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) error_at (OMP_CLAUSE_LOCATION (c), "%qE is neither a variable nor a function name in " - "clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + "clause %qs", t, cname); else error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + "%qE is not a variable in clause %qs", t, cname); remove = true; } else if (DECL_THREAD_LOCAL_P (t)) { error_at (OMP_CLAUSE_LOCATION (c), "%qD is threadprivate variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + cname); remove = true; } else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD does not have a mappable type in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + cname); remove = true; } if (remove) diff --git a/gcc/c/gimple-parser.cc b/gcc/c/gimple-parser.cc index d1afd42..b909eac 100644 --- a/gcc/c/gimple-parser.cc +++ b/gcc/c/gimple-parser.cc @@ -1800,7 +1800,7 @@ c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser, finish = c_parser_peek_token (parser)->get_finish (); c_parser_consume_token (parser); expr.value = build_component_ref (op_loc, expr.value, ident, - comp_loc); + comp_loc, UNKNOWN_LOCATION); set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) @@ -1848,7 +1848,8 @@ c_parser_gimple_postfix_expression_after_primary (gimple_parser &parser, expr.value = build_component_ref (op_loc, build_simple_mem_ref_loc (op_loc, expr.value), - ident, comp_loc); + ident, comp_loc, + expr.get_location ()); set_c_expr_source_range (&expr, start, finish); expr.original_code = ERROR_MARK; if (TREE_CODE (expr.value) != COMPONENT_REF) diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index 0b0ec2c..0e5be2c 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -165,6 +165,10 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zksh", ISA_SPEC_CLASS_NONE, 1, 0}, {"zkt", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zicboz",ISA_SPEC_CLASS_NONE, 1, 0}, + {"zicbom",ISA_SPEC_CLASS_NONE, 1, 0}, + {"zicbop",ISA_SPEC_CLASS_NONE, 1, 0}, + {"zk", ISA_SPEC_CLASS_NONE, 1, 0}, {"zkn", ISA_SPEC_CLASS_NONE, 1, 0}, {"zks", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -1110,6 +1114,10 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zksh", &gcc_options::x_riscv_zk_subext, MASK_ZKSH}, {"zkt", &gcc_options::x_riscv_zk_subext, MASK_ZKT}, + {"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}, + {"zve32x", &gcc_options::x_target_flags, MASK_VECTOR}, {"zve32f", &gcc_options::x_target_flags, MASK_VECTOR}, {"zve64x", &gcc_options::x_target_flags, MASK_VECTOR}, diff --git a/gcc/config.gcc b/gcc/config.gcc index 600ac35..cdbefb5 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -4522,7 +4522,7 @@ case "${target}" in for which in arch tune; do eval "val=\$with_$which" case ${val} in - "" | fiji | gfx900 | gfx906 ) + "" | fiji | gfx900 | gfx906 | gfx908 | gfx90a) # OK ;; *) diff --git a/gcc/config.in b/gcc/config.in index 64c27c9..6a4f885 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1331,13 +1331,6 @@ #endif -/* Define if your Arm assembler permits context-specific feature extensions. - */ -#ifndef USED_FOR_TARGET -#undef HAVE_GAS_ARM_EXTENDED_ARCH -#endif - - /* Define if your assembler supports .balign and .p2align. */ #ifndef USED_FOR_TARGET #undef HAVE_GAS_BALIGN_AND_P2ALIGN @@ -1457,72 +1450,6 @@ #endif -/* Define if your assembler has fixed global_load functions. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_ASM_GLOBAL_LOAD_FIXED -#endif - - -/* Define if your assembler expects amdgcn_target gfx908+xnack syntax. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_ASM_V3_SYNTAX -#endif - - -/* Define if your assembler expects amdgcn_target gfx908:xnack+ syntax. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_ASM_V4_SYNTAX -#endif - - -/* Define if your assembler allows -mattr=+sramecc for fiji. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_SRAM_ECC_FIJI -#endif - - -/* Define if your assembler allows -mattr=+sramecc for gfx900. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_SRAM_ECC_GFX900 -#endif - - -/* Define if your assembler allows -mattr=+sramecc for gfx906. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_SRAM_ECC_GFX906 -#endif - - -/* Define if your assembler allows -mattr=+sramecc for gfx908. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_SRAM_ECC_GFX908 -#endif - - -/* Define if your assembler allows -mattr=+xnack for fiji. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_XNACK_FIJI -#endif - - -/* Define if your assembler allows -mattr=+xnack for gfx900. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_XNACK_GFX900 -#endif - - -/* Define if your assembler allows -mattr=+xnack for gfx906. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_XNACK_GFX906 -#endif - - -/* Define if your assembler allows -mattr=+xnack for gfx908. */ -#ifndef USED_FOR_TARGET -#undef HAVE_GCN_XNACK_GFX908 -#endif - - /* Define to 1 if you have the `getchar_unlocked' function. */ #ifndef USED_FOR_TARGET #undef HAVE_GETCHAR_UNLOCKED @@ -2208,6 +2135,12 @@ #endif +/* Define which stat syscall is able to handle 64bit indodes. */ +#ifndef USED_FOR_TARGET +#undef HOST_STAT_FOR_64BIT_INODES +#endif + + /* Define as const if the declaration of iconv() needs const. */ #ifndef USED_FOR_TARGET #undef ICONV_CONST diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index ba5b6be..d4c575c 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -24115,9 +24115,13 @@ aarch64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */ static bool -aarch64_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel) +aarch64_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + struct expand_vec_perm_d d; /* Check whether the mask can be applied to a single vector. */ diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc index 2afe044..7ecf7b7 100644 --- a/gcc/config/arm/arm.cc +++ b/gcc/config/arm/arm.cc @@ -296,8 +296,8 @@ static int arm_cortex_a5_branch_cost (bool, bool); static int arm_cortex_m_branch_cost (bool, bool); static int arm_cortex_m7_branch_cost (bool, bool); -static bool arm_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx, - const vec_perm_indices &); +static bool arm_vectorize_vec_perm_const (machine_mode, machine_mode, rtx, rtx, + rtx, const vec_perm_indices &); static bool aarch_macro_fusion_pair_p (rtx_insn*, rtx_insn*); @@ -31813,9 +31813,13 @@ arm_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */ static bool -arm_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, rtx op1, +arm_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + struct expand_vec_perm_d d; int i, nelt, which; diff --git a/gcc/config/avr/avr-mcus.def b/gcc/config/avr/avr-mcus.def index 1e12ab3..fa5e668 100644 --- a/gcc/config/avr/avr-mcus.def +++ b/gcc/config/avr/avr-mcus.def @@ -306,6 +306,14 @@ AVR_MCU ("atxmega16c4", ARCH_AVRXMEGA2, AVR_ISA_RMW, "__AVR_ATxmega16C4__" AVR_MCU ("atxmega32a4u", ARCH_AVRXMEGA2, AVR_ISA_RMW, "__AVR_ATxmega32A4U__", 0x2000, 0x0, 0x9000, 0) AVR_MCU ("atxmega32c4", ARCH_AVRXMEGA2, AVR_ISA_RMW, "__AVR_ATxmega32C4__", 0x2000, 0x0, 0x9000, 0) AVR_MCU ("atxmega32e5", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_ATxmega32E5__", 0x2000, 0x0, 0x9000, 0) +AVR_MCU ("avr64da28", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA28__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64da32", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA32__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64da48", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA48__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64da64", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DA64__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64db28", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB28__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64db32", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB32__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64db48", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB48__", 0x6000, 0x0, 0x8000, 0x10000) +AVR_MCU ("avr64db64", ARCH_AVRXMEGA2, AVR_ISA_NONE, "__AVR_AVR64DB64__", 0x6000, 0x0, 0x8000, 0x10000) /* Xmega, Flash + RAM < 64K, flash visible in RAM address space */ AVR_MCU ("avrxmega3", ARCH_AVRXMEGA3, AVR_ISA_NONE, NULL, 0x3f00, 0x0, 0x8000, 0) AVR_MCU ("attiny202", ARCH_AVRXMEGA3, AVR_ISA_RCALL, "__AVR_ATtiny202__", 0x3f80, 0x0, 0x800, 0x8000) @@ -342,6 +350,12 @@ AVR_MCU ("atmega3208", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_ATmega3208__" AVR_MCU ("atmega3209", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_ATmega3209__", 0x3800, 0x0, 0x8000, 0x4000) AVR_MCU ("atmega4808", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_ATmega4808__", 0x2800, 0x0, 0xc000, 0x4000) AVR_MCU ("atmega4809", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_ATmega4809__", 0x2800, 0x0, 0xc000, 0x4000) +AVR_MCU ("avr32da28", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_AVR32DA28__", 0x7000, 0x0, 0x8000, 0x8000) +AVR_MCU ("avr32da32", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_AVR32DA32__", 0x7000, 0x0, 0x8000, 0x8000) +AVR_MCU ("avr32da48", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_AVR32DA48__", 0x7000, 0x0, 0x8000, 0x8000) +AVR_MCU ("avr32db28", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_AVR32DB28__", 0x7000, 0x0, 0x8000, 0x8000) +AVR_MCU ("avr32db32", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_AVR32DB32__", 0x7000, 0x0, 0x8000, 0x8000) +AVR_MCU ("avr32db48", ARCH_AVRXMEGA3, AVR_ISA_NONE, "__AVR_AVR32DB48__", 0x7000, 0x0, 0x8000, 0x8000) /* Xmega, 64K < Flash <= 128K, RAM <= 64K */ AVR_MCU ("avrxmega4", ARCH_AVRXMEGA4, AVR_ISA_NONE, NULL, 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64a3", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_ATxmega64A3__", 0x2000, 0x0, 0x11000, 0) @@ -352,6 +366,14 @@ AVR_MCU ("atxmega64b1", ARCH_AVRXMEGA4, AVR_ISA_RMW, "__AVR_ATxmega64B1__" AVR_MCU ("atxmega64b3", ARCH_AVRXMEGA4, AVR_ISA_RMW, "__AVR_ATxmega64B3__", 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64c3", ARCH_AVRXMEGA4, AVR_ISA_RMW, "__AVR_ATxmega64C3__", 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64d4", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_ATxmega64D4__", 0x2000, 0x0, 0x11000, 0) +AVR_MCU ("avr128da28", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA28__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128da32", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA32__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128da48", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA48__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128da64", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DA64__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128db28", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB28__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128db32", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB32__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128db48", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB48__", 0x4000, 0x0, 0x8000, 0x20000) +AVR_MCU ("avr128db64", ARCH_AVRXMEGA4, AVR_ISA_NONE, "__AVR_AVR128DB64__", 0x4000, 0x0, 0x8000, 0x20000) /* Xmega, 64K < Flash <= 128K, RAM > 64K */ AVR_MCU ("avrxmega5", ARCH_AVRXMEGA5, AVR_ISA_NONE, NULL, 0x2000, 0x0, 0x11000, 0) AVR_MCU ("atxmega64a1", ARCH_AVRXMEGA5, AVR_ISA_NONE, "__AVR_ATxmega64A1__", 0x2000, 0x0, 0x11000, 0) diff --git a/gcc/config/avr/gen-avr-mmcu-specs.cc b/gcc/config/avr/gen-avr-mmcu-specs.cc index bf9aa2c..1b75e05 100644 --- a/gcc/config/avr/gen-avr-mmcu-specs.cc +++ b/gcc/config/avr/gen-avr-mmcu-specs.cc @@ -279,7 +279,7 @@ print_mcu (const avr_mcu_t *mcu) if (is_device) { fprintf (f, "*self_spec:\n"); - fprintf (f, "\t%%{!mmcu=avr*: %%<mmcu=* -mmcu=%s} ", arch->name); + fprintf (f, "\t%%<mmcu=* -mmcu=%s ", arch->name); fprintf (f, "%s ", rcall_spec); fprintf (f, "%s\n\n", sp8_spec); diff --git a/gcc/config/avr/gen-avr-mmcu-texi.cc b/gcc/config/avr/gen-avr-mmcu-texi.cc index a44e18e..0e013e9 100644 --- a/gcc/config/avr/gen-avr-mmcu-texi.cc +++ b/gcc/config/avr/gen-avr-mmcu-texi.cc @@ -55,7 +55,7 @@ c_prefix (const char *str) { static const char *const prefixes[] = { - "attiny", "atmega", "atxmega", "ata", "at90" + "attiny", "atmega", "atxmega", "ata", "at90", "avr" }; int i, n = (int) (ARRAY_SIZE (prefixes)); diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 3682bd2..f82ec62 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -143,10 +143,7 @@ extern GTY(()) int darwin_ms_struct; Right now there's no mechanism to split up the "variable portion" (%*) of the matched spec string, so where we have some driver specs that take 2 or 3 arguments, these cannot be processed here, but are deferred until the - LINK_SPEC, where they are copied verbatim. - We have a "safe" version of the MacOS version string, that's been sanity- - checked and truncated to minor version. If the 'tiny' (3rd) portion of the - value is not significant, it's better to use this in version-compare(). */ + LINK_SPEC, where they are copied verbatim. */ #undef SUBTARGET_DRIVER_SELF_SPECS #define SUBTARGET_DRIVER_SELF_SPECS \ @@ -220,13 +217,8 @@ extern GTY(()) int darwin_ms_struct; "%{image_base*:-Xlinker -image_base -Xlinker %*} %<image_base*", \ "%{init*:-Xlinker -init -Xlinker %*} %<init*", \ "%{multi_module:-Xlinker -multi_module} %<multi_module", \ - "%{multiply_defined*:-Xlinker -multiply_defined -Xlinker %*; \ - :%{shared-libgcc: \ - %:version-compare(< 10.5 asm_macosx_version_min= -Xlinker) \ - %:version-compare(< 10.5 asm_macosx_version_min= -multiply_defined) \ - %:version-compare(< 10.5 asm_macosx_version_min= -Xlinker) \ - %:version-compare(< 10.5 asm_macosx_version_min= suppress)}} \ - %<multiply_defined*", \ + "%{multiply_defined*:-Xlinker -multiply_defined -Xlinker %*} \ + %<multiply_defined* ", \ "%{multiplydefinedunused*:\ -Xlinker -multiply_defined_unused -Xlinker %*} \ %<multiplydefinedunused* ", \ @@ -458,6 +450,9 @@ extern GTY(()) int darwin_ms_struct; %{!force_cpusubtype_ALL:-arch %(darwin_subarch)} "\ LINK_SYSROOT_SPEC \ "%{mmacosx-version-min=*:-macosx_version_min %*} \ + %{!multiply_defined*:%{shared-libgcc: \ + %:version-compare(< 10.5 mmacosx-version-min= -multiply_defined) \ + %:version-compare(< 10.5 mmacosx-version-min= suppress) }} \ %{sectalign*} %{sectcreate*} %{sectobjectsymbols*} %{sectorder*} \ %{segaddr*} %{segcreate*} %{segprot*} " @@ -465,48 +460,36 @@ extern GTY(()) int darwin_ms_struct; #define LIB_SPEC "%{!static:-lSystem}" -/* - Note that by default, -lgcc_eh is not linked against. - This is because,in general, we need to unwind through system libraries that - are linked with the shared unwinder in libunwind (or libgcc_s for 10.4/5). +/* Note that by default, -lgcc_eh (which provides a statically-linked unwinder) + is not used. This is because, in general, we need to unwind through system + libraries that are linked with the shared unwinder in libunwind (or libgcc_s + for OSX 10.4/5 [darwin8/9]). - For -static-libgcc: < 10.6, use the unwinder in libgcc_eh (and find - the emultls impl. there too). + When -static-libgcc is forced: < 10.6, use the unwinder in libgcc_eh (and + find the emultls impl. there too). For -static-libgcc: >= 10.6, the unwinder *still* comes from libSystem and we find the emutls impl from lemutls_w. In either case, the builtins etc. - are linked from -lgcc. + are linked from -lgcc. The eh library is still available so that it could + be specified explicitly if there is some reason to do so. When we have specified shared-libgcc or any case that might require exceptions, we pull the libgcc content (including emulated tls) from - -lgcc_s.1 in GCC and the unwinder from /usr/lib/libgcc_s.1 for < 10.6 and + -lgcc_s.1.1 in GCC and the unwinder from /usr/lib/libgcc_s.1 for < 10.6 and libSystem for >= 10.6 respectively. Otherwise, we just link the emutls/builtins from convenience libs. - If we need exceptions, prior to 10.3.9, then we have to link the static - eh lib, since there's no shared version on the system. - - In all cases, libgcc_s.1 will be installed with the compiler, or any app - built using it, so we can link the builtins and emutls shared on all. - We have to work around that DYLD_XXXX are disabled in macOS 10.11+ which means that any bootstrap trying to use a shared libgcc with a bumped SO- name will fail. This means that we do not accept shared libgcc for these - versions. + versions (the primary reason for forcing a shared libgcc was that it + contained the unwinder on Darwin8 and 9). - For -static-libgcc: >= 10.6, the unwinder *still* comes from libSystem and - we find the emutls impl from lemutls_w. In either case, the builtins etc. - are linked from -lgcc. -> - Otherwise, we just link the shared version of gcc_s.1.1 and pick up - exceptions: + When using the shared version of gcc_s.1.1 the unwinder is provided by: * Prior to 10.3.9, then we have to link the static eh lib, since there - is no shared version on the system. + is no shared unwinder version on the system. * from 10.3.9 to 10.5, from /usr/lib/libgcc_s.1.dylib * from 10.6 onwards, from libSystem.dylib - - In all cases, libgcc_s.1.1 will be installed with the compiler, or any app - built using it, so we can link the builtins and emutls shared on all. */ #undef REAL_LIBGCC_SPEC #define REAL_LIBGCC_SPEC \ diff --git a/gcc/config/gcn/gcn-hsa.h b/gcc/config/gcn/gcn-hsa.h index 9b5fee9..b3079ce 100644 --- a/gcc/config/gcn/gcn-hsa.h +++ b/gcc/config/gcn/gcn-hsa.h @@ -75,68 +75,19 @@ extern unsigned int gcn_local_sym_hash (const char *name); supported for gcn. */ #define GOMP_SELF_SPECS "" -#ifdef HAVE_GCN_XNACK_FIJI -#define X_FIJI -#else -#define X_FIJI "!march=*:;march=fiji:;" -#endif -#ifdef HAVE_GCN_XNACK_GFX900 -#define X_900 -#else -#define X_900 "march=gfx900:;" -#endif -#ifdef HAVE_GCN_XNACK_GFX906 -#define X_906 -#else -#define X_906 "march=gfx906:;" -#endif -#ifdef HAVE_GCN_XNACK_GFX908 -#define X_908 -#else -#define X_908 "march=gfx908:;" -#endif - -/* These targets can't have SRAM-ECC, even if a broken assembler allows it. */ -#define S_FIJI "!march=*:;march=fiji:;" -#define S_900 "march=gfx900:;" -#define S_906 "march=gfx906:;" -#ifdef HAVE_GCN_SRAM_ECC_GFX908 -#define S_908 -#else -#define S_908 "march=gfx908:;" -#endif +#define NO_XNACK "!march=*:;march=fiji:;" +#define NO_SRAM_ECC "!march=*:;march=fiji:;march=gfx900:;march=gfx906:;" -#ifdef HAVE_GCN_ASM_V3_SYNTAX -#define SRAMOPT "!msram-ecc=off:-mattr=+sram-ecc;:-mattr=-sram-ecc" -#endif -#ifdef HAVE_GCN_ASM_V4_SYNTAX /* In HSACOv4 no attribute setting means the binary supports "any" hardware configuration. The name of the attribute also changed. */ #define SRAMOPT "msram-ecc=on:-mattr=+sramecc;msram-ecc=off:-mattr=-sramecc" -#endif -#if !defined(SRAMOPT) && !defined(IN_LIBGCC2) -#error "No assembler syntax configured" -#endif - -#ifdef HAVE_GCN_ASM_V4_SYNTAX -/* FIJI cards don't seem to support drivers new enough to allow HSACOv4. */ -#define HSACO3_SELECT_OPT \ - "%{!march=*|march=fiji:--amdhsa-code-object-version=3} " -#else -#define HSACO3_SELECT_OPT -#endif - -/* These targets can't have SRAM-ECC, even if a broken assembler allows it. */ -#define DRIVER_SELF_SPECS \ - "%{march=fiji|march=gfx900|march=gfx906:%{!msram-ecc=*:-msram-ecc=off}}" /* Use LLVM assembler and linker options. */ #define ASM_SPEC "-triple=amdgcn--amdhsa " \ "%:last_arg(%{march=*:-mcpu=%*}) " \ - HSACO3_SELECT_OPT \ - "%{" X_FIJI X_900 X_906 X_908 \ - "mxnack:-mattr=+xnack;:-mattr=-xnack} " \ - "%{" S_FIJI S_900 S_906 S_908 SRAMOPT "} " \ + "%{!march=*|march=fiji:--amdhsa-code-object-version=3} " \ + "%{" NO_XNACK "mxnack:-mattr=+xnack;:-mattr=-xnack} " \ + "%{" NO_SRAM_ECC SRAMOPT "} " \ "-filetype=obj" #define LINK_SPEC "--pie --export-dynamic" #define LIB_SPEC "-lc" diff --git a/gcc/config/gcn/gcn-opts.h b/gcc/config/gcn/gcn-opts.h index c080524..b62dfb4 100644 --- a/gcc/config/gcn/gcn-opts.h +++ b/gcc/config/gcn/gcn-opts.h @@ -23,16 +23,30 @@ enum processor_type PROCESSOR_FIJI, // gfx803 PROCESSOR_VEGA10, // gfx900 PROCESSOR_VEGA20, // gfx906 - PROCESSOR_GFX908 // as yet unnamed + PROCESSOR_GFX908, + PROCESSOR_GFX90a }; /* Set in gcn_option_override. */ -extern int gcn_isa; - -#define TARGET_GCN3 (gcn_isa == 3) -#define TARGET_GCN3_PLUS (gcn_isa >= 3) -#define TARGET_GCN5 (gcn_isa == 5) -#define TARGET_GCN5_PLUS (gcn_isa >= 5) +extern enum gcn_isa { + ISA_UNKNOWN, + ISA_GCN3, + ISA_GCN5, + ISA_CDNA1, + ISA_CDNA2 +} gcn_isa; + +#define TARGET_GCN3 (gcn_isa == ISA_GCN3) +#define TARGET_GCN3_PLUS (gcn_isa >= ISA_GCN3) +#define TARGET_GCN5 (gcn_isa == ISA_GCN5) +#define TARGET_GCN5_PLUS (gcn_isa >= ISA_GCN5) +#define TARGET_CDNA1 (gcn_isa == ISA_CDNA1) +#define TARGET_CDNA1_PLUS (gcn_isa >= ISA_CDNA1) +#define TARGET_CDNA2 (gcn_isa == ISA_CDNA2) +#define TARGET_CDNA2_PLUS (gcn_isa >= ISA_CDNA2) + +#define TARGET_M0_LDS_LIMIT (TARGET_GCN3) +#define TARGET_PACKED_WORK_ITEMS (TARGET_CDNA2_PLUS) enum sram_ecc_type { diff --git a/gcc/config/gcn/gcn-valu.md b/gcc/config/gcn/gcn-valu.md index 9f868a1..abe4620 100644 --- a/gcc/config/gcn/gcn-valu.md +++ b/gcc/config/gcn/gcn-valu.md @@ -823,17 +823,8 @@ static char buf[200]; if (AS_GLOBAL_P (as)) - { - /* Work around assembler bug in which a 64-bit register is expected, - but a 32-bit value would be correct. */ - int reg = REGNO (operands[2]) - FIRST_VGPR_REG; - if (HAVE_GCN_ASM_GLOBAL_LOAD_FIXED) - sprintf (buf, "global_load%%o0\t%%0, v%d, %%1 offset:%%3%s\;" - "s_waitcnt\tvmcnt(0)", reg, glc); - else - sprintf (buf, "global_load%%o0\t%%0, v[%d:%d], %%1 offset:%%3%s\;" - "s_waitcnt\tvmcnt(0)", reg, reg + 1, glc); - } + sprintf (buf, "global_load%%o0\t%%0, %%2, %%1 offset:%%3%s\;" + "s_waitcnt\tvmcnt(0)", glc); else gcc_unreachable (); @@ -958,17 +949,7 @@ static char buf[200]; if (AS_GLOBAL_P (as)) - { - /* Work around assembler bug in which a 64-bit register is expected, - but a 32-bit value would be correct. */ - int reg = REGNO (operands[1]) - FIRST_VGPR_REG; - if (HAVE_GCN_ASM_GLOBAL_LOAD_FIXED) - sprintf (buf, "global_store%%s3\tv%d, %%3, %%0 offset:%%2%s", - reg, glc); - else - sprintf (buf, "global_store%%s3\tv[%d:%d], %%3, %%0 offset:%%2%s", - reg, reg + 1, glc); - } + sprintf (buf, "global_store%%s3\t%%1, %%3, %%0 offset:%%2%s", glc); else gcc_unreachable (); diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index 76b27c4..6fc20d3 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -66,7 +66,7 @@ static bool ext_gcn_constants_init = 0; /* Holds the ISA variant, derived from the command line parameters. */ -int gcn_isa = 3; /* Default to GCN3. */ +enum gcn_isa gcn_isa = ISA_GCN3; /* Default to GCN3. */ /* Reserve this much space for LDS (for propagating variables from worker-single mode to worker-partitioned mode), per workgroup. Global @@ -129,7 +129,13 @@ gcn_option_override (void) if (!flag_pic) flag_pic = flag_pie; - gcn_isa = gcn_arch == PROCESSOR_FIJI ? 3 : 5; + gcn_isa = (gcn_arch == PROCESSOR_FIJI ? ISA_GCN3 + : gcn_arch == PROCESSOR_VEGA10 ? ISA_GCN5 + : gcn_arch == PROCESSOR_VEGA20 ? ISA_GCN5 + : gcn_arch == PROCESSOR_GFX908 ? ISA_CDNA1 + : gcn_arch == PROCESSOR_GFX90a ? ISA_CDNA2 + : ISA_UNKNOWN); + gcc_assert (gcn_isa != ISA_UNKNOWN); /* The default stack size needs to be small for offload kernels because there may be many, many threads. Also, a smaller stack gives a @@ -2642,6 +2648,8 @@ gcn_omp_device_kind_arch_isa (enum omp_device_kind_arch_isa trait, return gcn_arch == PROCESSOR_VEGA20; if (strcmp (name, "gfx908") == 0) return gcn_arch == PROCESSOR_GFX908; + if (strcmp (name, "gfx90a") == 0) + return gcn_arch == PROCESSOR_GFX90a; return 0; default: gcc_unreachable (); @@ -3081,13 +3089,35 @@ gcn_expand_prologue () /* Ensure that the scheduler doesn't do anything unexpected. */ emit_insn (gen_blockage ()); - /* m0 is initialized for the usual LDS DS and FLAT memory case. - The low-part is the address of the topmost addressable byte, which is - size-1. The high-part is an offset and should be zero. */ - emit_move_insn (gen_rtx_REG (SImode, M0_REG), - gen_int_mode (LDS_SIZE, SImode)); + if (TARGET_M0_LDS_LIMIT) + { + /* m0 is initialized for the usual LDS DS and FLAT memory case. + The low-part is the address of the topmost addressable byte, which is + size-1. The high-part is an offset and should be zero. */ + emit_move_insn (gen_rtx_REG (SImode, M0_REG), + gen_int_mode (LDS_SIZE, SImode)); + + emit_insn (gen_prologue_use (gen_rtx_REG (SImode, M0_REG))); + } - emit_insn (gen_prologue_use (gen_rtx_REG (SImode, M0_REG))); + if (TARGET_PACKED_WORK_ITEMS + && cfun && cfun->machine && !cfun->machine->normal_function) + { + /* v0 conatins the X, Y and Z dimensions all in one. + Expand them out for ABI compatibility. */ + /* TODO: implement and use zero_extract. */ + rtx v1 = gen_rtx_REG (V64SImode, VGPR_REGNO (1)); + emit_insn (gen_andv64si3 (v1, gen_rtx_REG (V64SImode, VGPR_REGNO (0)), + gen_rtx_CONST_INT (VOIDmode, 0x3FF << 10))); + emit_insn (gen_lshrv64si3 (v1, v1, gen_rtx_CONST_INT (VOIDmode, 10))); + emit_insn (gen_prologue_use (v1)); + + rtx v2 = gen_rtx_REG (V64SImode, VGPR_REGNO (2)); + emit_insn (gen_andv64si3 (v2, gen_rtx_REG (V64SImode, VGPR_REGNO (0)), + gen_rtx_CONST_INT (VOIDmode, 0x3FF << 20))); + emit_insn (gen_lshrv64si3 (v2, v2, gen_rtx_CONST_INT (VOIDmode, 20))); + emit_insn (gen_prologue_use (v2)); + } if (cfun && cfun->machine && !cfun->machine->normal_function && flag_openmp) { @@ -4131,10 +4161,13 @@ gcn_make_vec_perm_address (unsigned int *perm) permutations. */ static bool -gcn_vectorize_vec_perm_const (machine_mode vmode, rtx dst, - rtx src0, rtx src1, +gcn_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx dst, rtx src0, rtx src1, const vec_perm_indices & sel) { + if (vmode != op_mode) + return false; + unsigned int nelt = GET_MODE_NUNITS (vmode); gcc_assert (VECTOR_MODE_P (vmode)); @@ -5216,71 +5249,41 @@ gcn_shared_mem_layout (unsigned HOST_WIDE_INT *lo, static void output_file_start (void) { + /* In HSACOv4 no attribute setting means the binary supports "any" hardware + configuration. In GCC binaries, this is true for SRAM ECC, but not + XNACK. */ + const char *xnack = (flag_xnack ? ":xnack+" : ":xnack-"); + const char *sram_ecc = (flag_sram_ecc == SRAM_ECC_ON ? ":sramecc+" + : flag_sram_ecc == SRAM_ECC_OFF ? ":sramecc-" + : ""); + const char *cpu; - bool use_xnack_attr = true; - bool use_sram_attr = true; switch (gcn_arch) { case PROCESSOR_FIJI: cpu = "gfx803"; -#ifndef HAVE_GCN_XNACK_FIJI - use_xnack_attr = false; -#endif - use_sram_attr = false; + xnack = ""; + sram_ecc = ""; break; case PROCESSOR_VEGA10: cpu = "gfx900"; -#ifndef HAVE_GCN_XNACK_GFX900 - use_xnack_attr = false; -#endif - use_sram_attr = false; + sram_ecc = ""; break; case PROCESSOR_VEGA20: cpu = "gfx906"; -#ifndef HAVE_GCN_XNACK_GFX906 - use_xnack_attr = false; -#endif - use_sram_attr = false; + sram_ecc = ""; break; case PROCESSOR_GFX908: cpu = "gfx908"; -#ifndef HAVE_GCN_XNACK_GFX908 - use_xnack_attr = false; -#endif -#ifndef HAVE_GCN_SRAM_ECC_GFX908 - use_sram_attr = false; -#endif + break; + case PROCESSOR_GFX90a: + cpu = "gfx90a"; break; default: gcc_unreachable (); } -#if HAVE_GCN_ASM_V3_SYNTAX - const char *xnack = (flag_xnack ? "+xnack" : ""); - const char *sram_ecc = (flag_sram_ecc ? "+sram-ecc" : ""); -#endif -#if HAVE_GCN_ASM_V4_SYNTAX - /* In HSACOv4 no attribute setting means the binary supports "any" hardware - configuration. In GCC binaries, this is true for SRAM ECC, but not - XNACK. */ - const char *xnack = (flag_xnack ? ":xnack+" : ":xnack-"); - const char *sram_ecc = (flag_sram_ecc == SRAM_ECC_ON ? ":sramecc+" - : flag_sram_ecc == SRAM_ECC_OFF ? ":sramecc-" - : ""); -#endif - if (!use_xnack_attr) - xnack = ""; - if (!use_sram_attr) - sram_ecc = ""; - fprintf(asm_out_file, "\t.amdgcn_target \"amdgcn-unknown-amdhsa--%s%s%s\"\n", - cpu, -#if HAVE_GCN_ASM_V3_SYNTAX - xnack, sram_ecc -#endif -#ifdef HAVE_GCN_ASM_V4_SYNTAX - sram_ecc, xnack -#endif - ); + cpu, sram_ecc, xnack); } /* Implement ASM_DECLARE_FUNCTION_NAME via gcn-hsa.h. @@ -5329,6 +5332,10 @@ gcn_hsa_declare_function_name (FILE *file, const char *name, tree) sgpr = MAX_NORMAL_SGPR_COUNT; } + /* The gfx90a accum_offset field can't represent 0 registers. */ + if (gcn_arch == PROCESSOR_GFX90a && vgpr < 4) + vgpr = 4; + fputs ("\t.rodata\n" "\t.p2align\t6\n" "\t.amdhsa_kernel\t", file); @@ -5397,6 +5404,11 @@ gcn_hsa_declare_function_name (FILE *file, const char *name, tree) one 64th the wave-front stack size. */ stack_size_opt / 64, LDS_SIZE); + if (gcn_arch == PROCESSOR_GFX90a) + fprintf (file, + "\t .amdhsa_accum_offset\t%i\n" + "\t .amdhsa_tg_split\t0\n", + (vgpr+3)&~3); // I think this means the AGPRs come after the VGPRs fputs ("\t.end_amdhsa_kernel\n", file); #if 1 @@ -5425,6 +5437,8 @@ gcn_hsa_declare_function_name (FILE *file, const char *name, tree) LDS_SIZE, stack_size_opt / 64, sgpr, vgpr); + if (gcn_arch == PROCESSOR_GFX90a) + fprintf (file, " .agpr_count: 0\n"); // AGPRs are not used, yet fputs (" .end_amdgpu_metadata\n", file); #endif @@ -5724,23 +5738,10 @@ print_operand_address (FILE *file, rtx mem) if (vgpr_offset == NULL_RTX) /* In this case, the vector offset is zero, so we use the first lane of v1, which is initialized to zero. */ - { - if (HAVE_GCN_ASM_GLOBAL_LOAD_FIXED) - fprintf (file, "v1"); - else - fprintf (file, "v[1:2]"); - } + fprintf (file, "v1"); else if (REG_P (vgpr_offset) && VGPR_REGNO_P (REGNO (vgpr_offset))) - { - if (HAVE_GCN_ASM_GLOBAL_LOAD_FIXED) - fprintf (file, "v%d", - REGNO (vgpr_offset) - FIRST_VGPR_REG); - else - fprintf (file, "v[%d:%d]", - REGNO (vgpr_offset) - FIRST_VGPR_REG, - REGNO (vgpr_offset) - FIRST_VGPR_REG + 1); - } + fprintf (file, "v%d", REGNO (vgpr_offset) - FIRST_VGPR_REG); else output_operand_lossage ("bad ADDR_SPACE_GLOBAL address"); } diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index 9ae8919..a129760 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -24,6 +24,10 @@ builtin_define ("__GCN3__"); \ else if (TARGET_GCN5) \ builtin_define ("__GCN5__"); \ + else if (TARGET_CDNA1) \ + builtin_define ("__CDNA1__"); \ + else if (TARGET_CDNA2) \ + builtin_define ("__CDNA2__"); \ } \ while(0) diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 21a7476..53e846e 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -1410,7 +1410,7 @@ "" { if (can_create_pseudo_p () - && !TARGET_GCN5 + && !TARGET_GCN5_PLUS && !gcn_inline_immediate_operand (operands[2], SImode)) operands[2] = force_reg (SImode, operands[2]); @@ -1451,7 +1451,7 @@ (match_operand:SI 1 "register_operand" "Sg,Sg,v")) (match_operand:DI 2 "gcn_32bit_immediate_operand" "A, B,A")) (const_int 32))))] - "TARGET_GCN5 || gcn_inline_immediate_operand (operands[2], SImode)" + "TARGET_GCN5_PLUS || gcn_inline_immediate_operand (operands[2], SImode)" "@ s_mul_hi<sgnsuffix>0\t%0, %1, %2 s_mul_hi<sgnsuffix>0\t%0, %1, %2 @@ -1469,7 +1469,7 @@ "" { if (can_create_pseudo_p () - && !TARGET_GCN5 + && !TARGET_GCN5_PLUS && !gcn_inline_immediate_operand (operands[2], SImode)) operands[2] = force_reg (SImode, operands[2]); @@ -1506,7 +1506,7 @@ (match_operand:SI 1 "register_operand" "Sg, Sg, v")) (match_operand:DI 2 "gcn_32bit_immediate_operand" "A, B, A")))] - "TARGET_GCN5 || gcn_inline_immediate_operand (operands[2], SImode)" + "TARGET_GCN5_PLUS || gcn_inline_immediate_operand (operands[2], SImode)" "#" "&& reload_completed" [(const_int 0)] diff --git a/gcc/config/gcn/gcn.opt b/gcc/config/gcn/gcn.opt index 54da11f..9606aaf 100644 --- a/gcc/config/gcn/gcn.opt +++ b/gcc/config/gcn/gcn.opt @@ -37,6 +37,9 @@ Enum(gpu_type) String(gfx906) Value(PROCESSOR_VEGA20) EnumValue Enum(gpu_type) String(gfx908) Value(PROCESSOR_GFX908) +EnumValue +Enum(gpu_type) String(gfx90a) Value(PROCESSOR_GFX90a) + march= Target RejectNegative Joined ToLower Enum(gpu_type) Var(gcn_arch) Init(PROCESSOR_FIJI) Specify the name of the target GPU. diff --git a/gcc/config/gcn/mkoffload.cc b/gcc/config/gcn/mkoffload.cc index 94ba7ff..ed93ae8 100644 --- a/gcc/config/gcn/mkoffload.cc +++ b/gcc/config/gcn/mkoffload.cc @@ -55,9 +55,8 @@ #define EF_AMDGPU_MACH_AMDGCN_GFX906 0x2f #undef EF_AMDGPU_MACH_AMDGCN_GFX908 #define EF_AMDGPU_MACH_AMDGCN_GFX908 0x30 - -#define EF_AMDGPU_XNACK_V3 0x100 -#define EF_AMDGPU_SRAM_ECC_V3 0x200 +#undef EF_AMDGPU_MACH_AMDGCN_GFX90a +#define EF_AMDGPU_MACH_AMDGCN_GFX90a 0x3f #define EF_AMDGPU_FEATURE_XNACK_V4 0x300 /* Mask. */ #define EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 0x000 @@ -71,19 +70,6 @@ #define EF_AMDGPU_FEATURE_SRAMECC_OFF_V4 0x800 #define EF_AMDGPU_FEATURE_SRAMECC_ON_V4 0xc00 -#ifdef HAVE_GCN_ASM_V3_SYNTAX -#define SET_XNACK_ON(VAR) VAR |= EF_AMDGPU_XNACK_V3 -#define SET_XNACK_OFF(VAR) VAR &= ~EF_AMDGPU_XNACK_V3 -#define TEST_XNACK(VAR) (VAR & EF_AMDGPU_XNACK_V3) - -#define SET_SRAM_ECC_ON(VAR) VAR |= EF_AMDGPU_SRAM_ECC_V3 -#define SET_SRAM_ECC_ANY(VAR) SET_SRAM_ECC_ON (VAR) -#define SET_SRAM_ECC_OFF(VAR) VAR &= ~EF_AMDGPU_SRAM_ECC_V3 -#define SET_SRAM_ECC_UNSUPPORTED(VAR) SET_SRAM_ECC_OFF (VAR) -#define TEST_SRAM_ECC_ANY(VAR) 0 /* Not supported. */ -#define TEST_SRAM_ECC_ON(VAR) (VAR & EF_AMDGPU_SRAM_ECC_V3) -#endif -#ifdef HAVE_GCN_ASM_V4_SYNTAX #define SET_XNACK_ON(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_XNACK_V4) \ | EF_AMDGPU_FEATURE_XNACK_ON_V4) #define SET_XNACK_OFF(VAR) VAR = ((VAR & ~EF_AMDGPU_FEATURE_XNACK_V4) \ @@ -104,7 +90,6 @@ == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4) #define TEST_SRAM_ECC_ON(VAR) ((VAR & EF_AMDGPU_FEATURE_SRAMECC_V4) \ == EF_AMDGPU_FEATURE_SRAMECC_ON_V4) -#endif #ifndef R_AMDGPU_NONE #define R_AMDGPU_NONE 0 @@ -130,12 +115,7 @@ static struct obstack files_to_cleanup; enum offload_abi offload_abi = OFFLOAD_ABI_UNSET; uint32_t elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX803; // Default GPU architecture. uint32_t elf_flags = -#ifdef HAVE_GCN_ASM_V3_SYNTAX - 0; -#endif -#ifdef HAVE_GCN_ASM_V4_SYNTAX (EF_AMDGPU_FEATURE_XNACK_ANY_V4 | EF_AMDGPU_FEATURE_SRAMECC_ANY_V4); -#endif /* Delete tempfiles. */ @@ -362,14 +342,9 @@ copy_early_debug_info (const char *infile, const char *outfile) /* Patch the correct elf architecture flag into the file. */ ehdr.e_ident[7] = ELFOSABI_AMDGPU_HSA; -#ifdef HAVE_GCN_ASM_V3_SYNTAX - ehdr.e_ident[8] = ELFABIVERSION_AMDGPU_HSA_V3; -#endif -#ifdef HAVE_GCN_ASM_V4_SYNTAX ehdr.e_ident[8] = (elf_arch == EF_AMDGPU_MACH_AMDGCN_GFX803 ? ELFABIVERSION_AMDGPU_HSA_V3 : ELFABIVERSION_AMDGPU_HSA_V4); -#endif ehdr.e_type = ET_REL; ehdr.e_machine = EM_AMDGPU; ehdr.e_flags = elf_arch | elf_flags_actual; @@ -884,7 +859,6 @@ main (int argc, char **argv) bool fopenacc = false; bool fPIC = false; bool fpic = false; - bool sram_seen = false; for (int i = 1; i < argc; i++) { #define STR "-foffload-abi=" @@ -912,20 +886,11 @@ main (int argc, char **argv) else if (strcmp (argv[i], "-mno-xnack") == 0) SET_XNACK_OFF (elf_flags); else if (strcmp (argv[i], "-msram-ecc=on") == 0) - { - SET_SRAM_ECC_ON (elf_flags); - sram_seen = true; - } + SET_SRAM_ECC_ON (elf_flags); else if (strcmp (argv[i], "-msram-ecc=any") == 0) - { - SET_SRAM_ECC_ANY (elf_flags); - sram_seen = true; - } + SET_SRAM_ECC_ANY (elf_flags); else if (strcmp (argv[i], "-msram-ecc=off") == 0) - { - SET_SRAM_ECC_OFF (elf_flags); - sram_seen = true; - } + SET_SRAM_ECC_OFF (elf_flags); else if (strcmp (argv[i], "-save-temps") == 0) save_temps = true; else if (strcmp (argv[i], "-v") == 0) @@ -941,33 +906,13 @@ main (int argc, char **argv) elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX906; else if (strcmp (argv[i], "-march=gfx908") == 0) elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX908; + else if (strcmp (argv[i], "-march=gfx90a") == 0) + elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX90a; } if (!(fopenacc ^ fopenmp)) fatal_error (input_location, "either -fopenacc or -fopenmp must be set"); - if (!sram_seen) - { -#ifdef HAVE_GCN_ASM_V3_SYNTAX - /* For HSACOv3, the SRAM-ECC feature defaults to "on" on GPUs where the - feature is available. - (HSACOv4 has elf_flags initialsed to "any" in all cases.) */ - switch (elf_arch) - { - case EF_AMDGPU_MACH_AMDGCN_GFX803: - case EF_AMDGPU_MACH_AMDGCN_GFX900: - case EF_AMDGPU_MACH_AMDGCN_GFX906: -#ifndef HAVE_GCN_SRAM_ECC_GFX908 - case EF_AMDGPU_MACH_AMDGCN_GFX908: -#endif - break; - default: - SET_SRAM_ECC_ON (elf_flags); - break; - } -#endif - } - const char *abi; switch (offload_abi) { diff --git a/gcc/config/gcn/t-gcn-hsa b/gcc/config/gcn/t-gcn-hsa index 10e31f3..9e03ec8 100644 --- a/gcc/config/gcn/t-gcn-hsa +++ b/gcc/config/gcn/t-gcn-hsa @@ -42,8 +42,8 @@ ALL_HOST_OBJS += gcn-run.o gcn-run$(exeext): gcn-run.o +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ $< -ldl -MULTILIB_OPTIONS = march=gfx900/march=gfx906/march=gfx908 -MULTILIB_DIRNAMES = gfx900 gfx906 gfx908 +MULTILIB_OPTIONS = march=gfx900/march=gfx906/march=gfx908/march=gfx90a +MULTILIB_DIRNAMES = gfx900 gfx906 gfx908 gfx90a gcn-tree.o: $(srcdir)/config/gcn/gcn-tree.cc $(COMPILE) $< diff --git a/gcc/config/gcn/t-omp-device b/gcc/config/gcn/t-omp-device index e1d9e0d..27d36db 100644 --- a/gcc/config/gcn/t-omp-device +++ b/gcc/config/gcn/t-omp-device @@ -1,4 +1,4 @@ omp-device-properties-gcn: $(srcdir)/config/gcn/gcn.cc echo kind: gpu > $@ echo arch: amdgcn gcn >> $@ - echo isa: fiji gfx900 gfx906 gfx908 >> $@ + echo isa: fiji gfx900 gfx906 gfx908 gfx90a >> $@ diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 1460bcc..5cd7b99 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -4026,6 +4026,7 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false) case E_V8HFmode: case E_V4SImode: case E_V2DImode: + case E_V1TImode: if (TARGET_SSE4_1) { gen = gen_sse4_1_pblendvb; @@ -22068,9 +22069,13 @@ canonicalize_perm (struct expand_vec_perm_d *d) /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */ bool -ix86_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel) +ix86_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + struct expand_vec_perm_d d; unsigned char perm[MAX_VECT_LEN]; unsigned int i, nelt, which; diff --git a/gcc/config/i386/i386-expand.h b/gcc/config/i386/i386-expand.h index 9d320c2..6c65019 100644 --- a/gcc/config/i386/i386-expand.h +++ b/gcc/config/i386/i386-expand.h @@ -48,8 +48,9 @@ rtx gen_push (rtx arg); rtx gen_pop (rtx arg); rtx ix86_expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, int ignore); -bool ix86_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel); +bool ix86_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel); bool ix86_notrack_prefixed_insn_p (rtx_insn *); machine_mode ix86_split_reduction (machine_mode mode); void ix86_expand_divmod_libfunc (rtx libfunc, machine_mode mode, rtx op0, diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 050dee7..17bdbd9 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -8465,7 +8465,7 @@ (zero_extend:<DWI> (match_dup 3))) (match_operand:QI 4 "const_int_operand" "n"))))] "TARGET_BMI2 && INTVAL (operands[4]) == <MODE_SIZE> * BITS_PER_UNIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" + && !(MEM_P (operands[2]) && MEM_P (operands[3]))" "mulx\t{%3, %0, %1|%1, %0, %3}" [(set_attr "type" "imulx") (set_attr "prefix" "vex") @@ -9716,6 +9716,27 @@ operands[2] = gen_rtx_AND (mode, val, immed_wide_int_const (mask, mode)); }) +;; Split and;cmp (as optimized by combine) into not;test +;; Except when TARGET_BMI provides andn (*andn_<mode>_ccno). +(define_insn_and_split "*test<mode>_not" + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ + (and:SWI + (not:SWI (match_operand:SWI 0 "register_operand")) + (match_operand:SWI 1 "<nonmemory_szext_operand>")) + (const_int 0)))] + "ix86_pre_reload_split () + && (!TARGET_BMI || !REG_P (operands[1]))" + "#" + "&& 1" + [(set (match_dup 2) (not:SWI (match_dup 0))) + (set (reg:CCZ FLAGS_REG) + (compare:CCZ (and:SWI (match_dup 2) (match_dup 1)) + (const_int 0)))] +{ + operands[2] = gen_reg_rtx (<MODE>mode); +}) + ;; Convert HImode/SImode test instructions with immediate to QImode ones. ;; i386 does not allow to encode test with 8bit sign extended immediate, so ;; this is relatively important trick. @@ -11040,6 +11061,46 @@ (clobber (reg:CC FLAGS_REG))])] "ix86_expand_clear (operands[0]);") +;; Convert: +;; xorl %edx, %edx +;; negl %eax +;; adcl $0, %edx +;; negl %edx +;; to: +;; negl %eax +;; sbbl %edx, %edx // *x86_mov<mode>cc_0_m1 + +(define_peephole2 + [(parallel + [(set (match_operand:SWI48 0 "general_reg_operand") (const_int 0)) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (reg:CCC FLAGS_REG) + (ne:CCC (match_operand:SWI48 1 "general_reg_operand") (const_int 0))) + (set (match_dup 1) (neg:SWI48 (match_dup 1)))]) + (parallel + [(set (match_dup 0) + (plus:SWI48 (plus:SWI48 + (ltu:SWI48 (reg:CC FLAGS_REG) (const_int 0)) + (match_dup 0)) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 0) + (neg:SWI48 (match_dup 0))) + (clobber (reg:CC FLAGS_REG))])] + "REGNO (operands[0]) != REGNO (operands[1])" + [(parallel + [(set (reg:CCC FLAGS_REG) + (ne:CCC (match_dup 1) (const_int 0))) + (set (match_dup 1) (neg:SWI48 (match_dup 1)))]) + (parallel + [(set (match_dup 0) + (if_then_else:SWI48 (ltu:SWI48 (reg:CC FLAGS_REG) (const_int 0)) + (const_int -1) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))])]) + (define_insn "*neg<mode>_1" [(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m") (neg:SWI (match_operand:SWI 1 "nonimmediate_operand" "0"))) diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index a6b0e28..0dbaacb 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -1047,7 +1047,7 @@ Enable shadow stack built-in functions from Control-flow Enforcement Technology (CET). mcet-switch -Target Undocumented Var(flag_cet_switch) Init(0) +Target Var(flag_cet_switch) Init(0) Turn on CET instrumentation for switch statements that use a jump table and an indirect jump. diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 191371b..8b2602b 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -4579,10 +4579,10 @@ }) (define_expand "vcond_mask_<mode><sseintvecmodelower>" - [(set (match_operand:VI124_128 0 "register_operand") - (vec_merge:VI124_128 - (match_operand:VI124_128 1 "vector_operand") - (match_operand:VI124_128 2 "nonimm_or_0_operand") + [(set (match_operand:VI_128 0 "register_operand") + (vec_merge:VI_128 + (match_operand:VI_128 1 "vector_operand") + (match_operand:VI_128 2 "nonimm_or_0_operand") (match_operand:<sseintvecmode> 3 "register_operand")))] "TARGET_SSE2" { @@ -4591,13 +4591,13 @@ DONE; }) -(define_expand "vcond_mask_v2div2di" - [(set (match_operand:V2DI 0 "register_operand") - (vec_merge:V2DI - (match_operand:V2DI 1 "vector_operand") - (match_operand:V2DI 2 "nonimm_or_0_operand") - (match_operand:V2DI 3 "register_operand")))] - "TARGET_SSE4_2" +(define_expand "vcond_mask_v1tiv1ti" + [(set (match_operand:V1TI 0 "register_operand") + (vec_merge:V1TI + (match_operand:V1TI 1 "vector_operand") + (match_operand:V1TI 2 "nonimm_or_0_operand") + (match_operand:V1TI 3 "register_operand")))] + "TARGET_SSE2" { ix86_expand_sse_movcc (operands[0], operands[3], operands[1], operands[2]); @@ -15842,8 +15842,9 @@ sel[7] = 15; } vec_perm_indices indices (sel, 2, 8); - bool ok = targetm.vectorize.vec_perm_const (V8SImode, target, - arg0, arg1, indices); + bool ok = targetm.vectorize.vec_perm_const (V8SImode, V8SImode, + target, arg0, arg1, + indices); gcc_assert (ok); emit_move_insn (operands[0], lowpart_subreg (V4DImode, target, V8SImode)); @@ -24629,8 +24630,9 @@ sel[3] = 7; } vec_perm_indices indices (sel, arg0 != arg1 ? 2 : 1, 4); - bool ok = targetm.vectorize.vec_perm_const (V4SImode, target, - arg0, arg1, indices); + bool ok = targetm.vectorize.vec_perm_const (V4SImode, V4SImode, + target, arg0, arg1, + indices); gcc_assert (ok); emit_move_insn (operands[0], lowpart_subreg (V2DImode, target, V4SImode)); diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc index f9fb681..25e4a47 100644 --- a/gcc/config/ia64/ia64.cc +++ b/gcc/config/ia64/ia64.cc @@ -332,8 +332,8 @@ static fixed_size_mode ia64_get_reg_raw_mode (int regno); static section * ia64_hpux_function_section (tree, enum node_frequency, bool, bool); -static bool ia64_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx, - const vec_perm_indices &); +static bool ia64_vectorize_vec_perm_const (machine_mode, machine_mode, rtx, + rtx, rtx, const vec_perm_indices &); static unsigned int ia64_hard_regno_nregs (unsigned int, machine_mode); static bool ia64_hard_regno_mode_ok (unsigned int, machine_mode); @@ -11751,9 +11751,13 @@ ia64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */ static bool -ia64_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel) +ia64_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + struct expand_vec_perm_d d; unsigned char perm[MAX_VECT_LEN]; unsigned int i, nelt, which; diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index e64928f..5eb8459 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -21790,9 +21790,13 @@ mips_expand_vec_perm_const_1 (struct expand_vec_perm_d *d) /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */ static bool -mips_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel) +mips_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + struct expand_vec_perm_d d; int i, nelt, which; unsigned char orig_perm[MAX_VECT_LEN]; diff --git a/gcc/config/riscv/arch-canonicalize b/gcc/config/riscv/arch-canonicalize index 71b2232..fd7651a 100755 --- a/gcc/config/riscv/arch-canonicalize +++ b/gcc/config/riscv/arch-canonicalize @@ -73,8 +73,8 @@ def arch_canonicalize(arch, isa_spec): std_exts = [] if arch[:5] in ['rv32e', 'rv32i', 'rv32g', 'rv64i', 'rv64g']: new_arch = arch[:5].replace("g", "i") - std_exts = ['m', 'a', 'f', 'd'] if arch[:5] in ['rv32g', 'rv64g']: + std_exts = ['m', 'a', 'f', 'd'] if not is_isa_spec_2p2: extra_long_ext = ['zicsr', 'zifencei'] else: diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 97cdbdf..c37caa2 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -52,7 +52,7 @@ (match_test "INTVAL (op) + 1 != 0"))) (define_predicate "const_0_operand" - (and (match_code "const_int,const_wide_int,const_double,const_vector") + (and (match_code "const_int,const_wide_int,const_vector") (match_test "op == CONST0_RTX (GET_MODE (op))"))) (define_predicate "reg_or_0_operand" @@ -239,3 +239,7 @@ (define_predicate "const63_operand" (and (match_code "const_int") (match_test "INTVAL (op) == 63"))) + +(define_predicate "imm5_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) < 5"))) diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 0658f8d..795132a 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -87,6 +87,18 @@ struct riscv_builtin_description { AVAIL (hard_float, TARGET_HARD_FLOAT) + +AVAIL (clean32, TARGET_ZICBOM && !TARGET_64BIT) +AVAIL (clean64, TARGET_ZICBOM && TARGET_64BIT) +AVAIL (flush32, TARGET_ZICBOM && !TARGET_64BIT) +AVAIL (flush64, TARGET_ZICBOM && TARGET_64BIT) +AVAIL (inval32, TARGET_ZICBOM && !TARGET_64BIT) +AVAIL (inval64, TARGET_ZICBOM && TARGET_64BIT) +AVAIL (zero32, TARGET_ZICBOZ && !TARGET_64BIT) +AVAIL (zero64, TARGET_ZICBOZ && TARGET_64BIT) +AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT) +AVAIL (prefetchi64, TARGET_ZICBOP && TARGET_64BIT) + /* Construct a riscv_builtin_description from the given arguments. INSN is the name of the associated instruction pattern, without the @@ -119,6 +131,8 @@ AVAIL (hard_float, TARGET_HARD_FLOAT) /* Argument types. */ #define RISCV_ATYPE_VOID void_type_node #define RISCV_ATYPE_USI unsigned_intSI_type_node +#define RISCV_ATYPE_SI intSI_type_node +#define RISCV_ATYPE_DI intDI_type_node /* RISCV_FTYPE_ATYPESN takes N RISCV_FTYPES-like type codes and lists their associated RISCV_ATYPEs. */ @@ -128,6 +142,8 @@ AVAIL (hard_float, TARGET_HARD_FLOAT) RISCV_ATYPE_##A, RISCV_ATYPE_##B static const struct riscv_builtin_description riscv_builtins[] = { + #include "riscv-cmo.def" + DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float), DIRECT_NO_TARGET_BUILTIN (fsflags, RISCV_VOID_FTYPE_USI, hard_float) }; diff --git a/gcc/config/riscv/riscv-cmo.def b/gcc/config/riscv/riscv-cmo.def new file mode 100644 index 0000000..b30ecf9 --- /dev/null +++ b/gcc/config/riscv/riscv-cmo.def @@ -0,0 +1,17 @@ +// zicbom +RISCV_BUILTIN (clean_si, "zicbom_cbo_clean", RISCV_BUILTIN_DIRECT, RISCV_SI_FTYPE, clean32), +RISCV_BUILTIN (clean_di, "zicbom_cbo_clean", RISCV_BUILTIN_DIRECT, RISCV_DI_FTYPE, clean64), + +RISCV_BUILTIN (flush_si, "zicbom_cbo_flush", RISCV_BUILTIN_DIRECT, RISCV_SI_FTYPE, flush32), +RISCV_BUILTIN (flush_di, "zicbom_cbo_flush", RISCV_BUILTIN_DIRECT, RISCV_DI_FTYPE, flush64), + +RISCV_BUILTIN (inval_si, "zicbom_cbo_inval", RISCV_BUILTIN_DIRECT, RISCV_SI_FTYPE, inval32), +RISCV_BUILTIN (inval_di, "zicbom_cbo_inval", RISCV_BUILTIN_DIRECT, RISCV_DI_FTYPE, inval64), + +// zicboz +RISCV_BUILTIN (zero_si, "zicboz_cbo_zero", RISCV_BUILTIN_DIRECT, RISCV_SI_FTYPE, zero32), +RISCV_BUILTIN (zero_di, "zicboz_cbo_zero", RISCV_BUILTIN_DIRECT, RISCV_DI_FTYPE, zero64), + +// zicbop +RISCV_BUILTIN (prefetchi_si, "zicbop_cbo_prefetchi", RISCV_BUILTIN_DIRECT, RISCV_SI_FTYPE_SI, prefetchi32), +RISCV_BUILTIN (prefetchi_di, "zicbop_cbo_prefetchi", RISCV_BUILTIN_DIRECT, RISCV_DI_FTYPE_DI, prefetchi64), diff --git a/gcc/config/riscv/riscv-ftypes.def b/gcc/config/riscv/riscv-ftypes.def index 2214c49..6242129 100644 --- a/gcc/config/riscv/riscv-ftypes.def +++ b/gcc/config/riscv/riscv-ftypes.def @@ -28,3 +28,7 @@ along with GCC; see the file COPYING3. If not see DEF_RISCV_FTYPE (0, (USI)) DEF_RISCV_FTYPE (1, (VOID, USI)) +DEF_RISCV_FTYPE (0, (SI)) +DEF_RISCV_FTYPE (0, (DI)) +DEF_RISCV_FTYPE (1, (SI, SI)) +DEF_RISCV_FTYPE (1, (DI, DI)) diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 15bb5e7..1e153b3 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -145,6 +145,14 @@ enum stack_protector_guard { #define TARGET_ZVL32768B ((riscv_zvl_flags & MASK_ZVL32768B) != 0) #define TARGET_ZVL65536B ((riscv_zvl_flags & MASK_ZVL65536B) != 0) +#define MASK_ZICBOZ (1 << 0) +#define MASK_ZICBOM (1 << 1) +#define MASK_ZICBOP (1 << 2) + +#define TARGET_ZICBOZ ((riscv_zicmo_subext & MASK_ZICBOZ) != 0) +#define TARGET_ZICBOM ((riscv_zicmo_subext & MASK_ZICBOM) != 0) +#define TARGET_ZICBOP ((riscv_zicmo_subext & MASK_ZICBOP) != 0) + /* Bit of riscv_zvl_flags will set contintuly, N-1 bit will set if N-bit is set, e.g. MASK_ZVL64B has set then MASK_ZVL32B is set, so we can use popcount to caclulate the minimal VLEN. */ diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index ee756aa..f83dc79 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -220,6 +220,7 @@ struct riscv_tune_param unsigned short issue_rate; unsigned short branch_cost; unsigned short memory_cost; + unsigned short fmv_cost; bool slow_unaligned_access; }; @@ -285,6 +286,7 @@ static const struct riscv_tune_param rocket_tune_info = { 1, /* issue_rate */ 3, /* branch_cost */ 5, /* memory_cost */ + 8, /* fmv_cost */ true, /* slow_unaligned_access */ }; @@ -298,6 +300,7 @@ static const struct riscv_tune_param sifive_7_tune_info = { 2, /* issue_rate */ 4, /* branch_cost */ 3, /* memory_cost */ + 8, /* fmv_cost */ true, /* slow_unaligned_access */ }; @@ -311,6 +314,7 @@ static const struct riscv_tune_param thead_c906_tune_info = { 1, /* issue_rate */ 3, /* branch_cost */ 5, /* memory_cost */ + 8, /* fmv_cost */ false, /* slow_unaligned_access */ }; @@ -324,6 +328,7 @@ static const struct riscv_tune_param optimize_size_tune_info = { 1, /* issue_rate */ 1, /* branch_cost */ 2, /* memory_cost */ + 8, /* fmv_cost */ false, /* slow_unaligned_access */ }; @@ -1797,6 +1802,12 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN case SYMBOL_REF: case LABEL_REF: case CONST_DOUBLE: + /* With TARGET_SUPPORTS_WIDE_INT const int can't be in CONST_DOUBLE + rtl object. Weird recheck due to switch-case fall through above. */ + if (GET_CODE (x) == CONST_DOUBLE) + gcc_assert (GET_MODE (x) != VOIDmode); + /* Fall through. */ + case CONST: if ((cost = riscv_const_insns (x)) > 0) { @@ -4737,6 +4748,10 @@ static int riscv_register_move_cost (machine_mode mode, reg_class_t from, reg_class_t to) { + if ((from == FP_REGS && to == GR_REGS) || + (from == GR_REGS && to == FP_REGS)) + return tune_param->fmv_cost; + return riscv_secondary_memory_needed (mode, from, to) ? 8 : 2; } diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index b191606..5083a1c 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -1009,4 +1009,6 @@ extern void riscv_remove_unneeded_save_restore_calls (void); #define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \ ((VALUE) = GET_MODE_UNIT_BITSIZE (MODE), 2) +#define TARGET_SUPPORTS_WIDE_INT 1 + #endif /* ! GCC_RISCV_H */ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index d9b451b..b8ab0cf 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -71,6 +71,13 @@ ;; Stack Smash Protector UNSPEC_SSP_SET UNSPEC_SSP_TEST + + ;; CMO instructions. + UNSPECV_CLEAN + UNSPECV_FLUSH + UNSPECV_INVAL + UNSPECV_ZERO + UNSPECV_PREI ]) (define_constants @@ -2885,6 +2892,56 @@ "<load>\t%3, %1\;<load>\t%0, %2\;xor\t%0, %3, %0\;li\t%3, 0" [(set_attr "length" "12")]) +(define_insn "riscv_clean_<mode>" + [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")] + UNSPECV_CLEAN)] + "TARGET_ZICBOM" + "cbo.clean\t%a0" +) + +(define_insn "riscv_flush_<mode>" + [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")] + UNSPECV_FLUSH)] + "TARGET_ZICBOM" + "cbo.flush\t%a0" +) + +(define_insn "riscv_inval_<mode>" + [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")] + UNSPECV_INVAL)] + "TARGET_ZICBOM" + "cbo.inval\t%a0" +) + +(define_insn "riscv_zero_<mode>" + [(unspec_volatile:X [(match_operand:X 0 "register_operand" "r")] + UNSPECV_ZERO)] + "TARGET_ZICBOZ" + "cbo.zero\t%a0" +) + +(define_insn "prefetch" + [(prefetch (match_operand 0 "address_operand" "p") + (match_operand 1 "imm5_operand" "i") + (match_operand 2 "const_int_operand" "n"))] + "TARGET_ZICBOP" +{ + switch (INTVAL (operands[1])) + { + case 0: return "prefetch.r\t%a0"; + case 1: return "prefetch.w\t%a0"; + default: gcc_unreachable (); + } +}) + +(define_insn "riscv_prefetchi_<mode>" + [(unspec_volatile:X [(match_operand:X 0 "address_operand" "p") + (match_operand:X 1 "imm5_operand" "i")] + UNSPECV_PREI)] + "TARGET_ZICBOP" + "prefetch.i\t%a0" +) + (include "bitmanip.md") (include "sync.md") (include "peephole.md") diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 84c8cf5..9e9fe6d 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -209,6 +209,9 @@ int riscv_vector_elen_flags TargetVariable int riscv_zvl_flags +TargetVariable +int riscv_zicmo_subext + Enum Name(isa_spec_class) Type(enum riscv_isa_spec_class) Supported ISA specs (for use with the -misa-spec= option): diff --git a/gcc/config/rs6000/rs6000-p8swap.cc b/gcc/config/rs6000/rs6000-p8swap.cc index d301bc3..275702f 100644 --- a/gcc/config/rs6000/rs6000-p8swap.cc +++ b/gcc/config/rs6000/rs6000-p8swap.cc @@ -214,8 +214,9 @@ union_defs (swap_web_entry *insn_entry, rtx insn, df_ref use) if (DF_REF_INSN_INFO (link->ref)) { rtx def_insn = DF_REF_INSN (link->ref); - (void)unionfind_union (insn_entry + INSN_UID (insn), - insn_entry + INSN_UID (def_insn)); + gcc_assert (NONDEBUG_INSN_P (def_insn)); + unionfind_union (insn_entry + INSN_UID (insn), + insn_entry + INSN_UID (def_insn)); } link = link->next; @@ -242,8 +243,9 @@ union_uses (swap_web_entry *insn_entry, rtx insn, df_ref def) if (DF_REF_INSN_INFO (link->ref)) { rtx use_insn = DF_REF_INSN (link->ref); - (void)unionfind_union (insn_entry + INSN_UID (insn), - insn_entry + INSN_UID (use_insn)); + if (NONDEBUG_INSN_P (use_insn)) + unionfind_union (insn_entry + INSN_UID (insn), + insn_entry + INSN_UID (use_insn)); } link = link->next; diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index d4defc8..0af2085 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -23294,9 +23294,13 @@ rs6000_expand_vec_perm_const_1 (rtx target, rtx op0, rtx op1, /* Implement TARGET_VECTORIZE_VEC_PERM_CONST. */ static bool -rs6000_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel) +rs6000_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + bool testing_p = !target; /* AltiVec (and thus VSX) can handle arbitrary permutations. */ diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index d46aba6..444b1ec 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -17175,9 +17175,13 @@ vectorize_vec_perm_const_1 (const struct expand_vec_perm_d &d) hook is supposed to emit the required INSNs. */ bool -s390_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, rtx op1, +s390_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + struct expand_vec_perm_d d; unsigned int i, nelt; diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc index 8d40563..03e1c04 100644 --- a/gcc/config/sh/sh.cc +++ b/gcc/config/sh/sh.cc @@ -10762,6 +10762,12 @@ sh_register_move_cost (machine_mode mode, && ! REGCLASS_HAS_GENERAL_REG (dstclass)) return 2 * ((GET_MODE_SIZE (mode) + 7) / 8U); + if (((dstclass == FP_REGS || dstclass == DF_REGS) + && (srcclass == PR_REGS)) + || ((srcclass == FP_REGS || srcclass == DF_REGS) + && (dstclass == PR_REGS))) + return 7; + return 2 * ((GET_MODE_SIZE (mode) + 3) / 4U); } diff --git a/gcc/config/sparc/sparc.cc b/gcc/config/sparc/sparc.cc index aca925b..c72c38e 100644 --- a/gcc/config/sparc/sparc.cc +++ b/gcc/config/sparc/sparc.cc @@ -712,7 +712,8 @@ static bool sparc_modes_tieable_p (machine_mode, machine_mode); static bool sparc_can_change_mode_class (machine_mode, machine_mode, reg_class_t); static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT); -static bool sparc_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx, +static bool sparc_vectorize_vec_perm_const (machine_mode, machine_mode, + rtx, rtx, rtx, const vec_perm_indices &); static bool sparc_can_follow_jump (const rtx_insn *, const rtx_insn *); static HARD_REG_SET sparc_zero_call_used_regs (HARD_REG_SET); @@ -13035,9 +13036,13 @@ sparc_expand_vec_perm_bmask (machine_mode vmode, rtx sel) /* Implement TARGET_VEC_PERM_CONST. */ static bool -sparc_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, - rtx op1, const vec_perm_indices &sel) +sparc_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode, + rtx target, rtx op0, rtx op1, + const vec_perm_indices &sel) { + if (vmode != op_mode) + return false; + if (!TARGET_VIS2) return false; diff --git a/gcc/config/xtensa/constraints.md b/gcc/config/xtensa/constraints.md index 7fda33a..e7ac8db 100644 --- a/gcc/config/xtensa/constraints.md +++ b/gcc/config/xtensa/constraints.md @@ -92,7 +92,7 @@ "An integer constant in the range @minus{}32-95 for use with MOVI.N instructions." (and (match_code "const_int") - (match_test "ival >= -32 && ival <= 95"))) + (match_test "IN_RANGE (ival, -32, 95)"))) (define_constraint "N" "An unsigned 8-bit integer constant shifted left by 8 bits for use @@ -103,7 +103,7 @@ (define_constraint "O" "An integer constant that can be used in ADDI.N instructions." (and (match_code "const_int") - (match_test "ival == -1 || (ival >= 1 && ival <= 15)"))) + (match_test "ival == -1 || IN_RANGE (ival, 1, 15)"))) (define_constraint "P" "An integer constant that can be used as a mask value in an EXTUI diff --git a/gcc/config/xtensa/predicates.md b/gcc/config/xtensa/predicates.md index 01226a2..a912e6d 100644 --- a/gcc/config/xtensa/predicates.md +++ b/gcc/config/xtensa/predicates.md @@ -25,8 +25,7 @@ (define_predicate "addsubx_operand" (and (match_code "const_int") - (match_test "INTVAL (op) >= 1 - && INTVAL (op) <= 3"))) + (match_test "IN_RANGE (INTVAL (op), 1, 3)"))) (define_predicate "arith_operand" (ior (and (match_code "const_int") @@ -55,7 +54,7 @@ (define_predicate "extui_fldsz_operand" (and (match_code "const_int") - (match_test "xtensa_mask_immediate ((1 << INTVAL (op)) - 1)"))) + (match_test "IN_RANGE (INTVAL (op), 1, 16)"))) (define_predicate "sext_operand" (if_then_else (match_test "TARGET_SEXT") @@ -64,7 +63,7 @@ (define_predicate "sext_fldsz_operand" (and (match_code "const_int") - (match_test "INTVAL (op) >= 8 && INTVAL (op) <= 23"))) + (match_test "IN_RANGE (INTVAL (op), 8, 23)"))) (define_predicate "lsbitnum_operand" (and (match_code "const_int") diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h index 4bc42da..30e4b54 100644 --- a/gcc/config/xtensa/xtensa-protos.h +++ b/gcc/config/xtensa/xtensa-protos.h @@ -41,6 +41,8 @@ extern void xtensa_expand_conditional_branch (rtx *, machine_mode); extern int xtensa_expand_conditional_move (rtx *, int); extern int xtensa_expand_scc (rtx *, machine_mode); extern int xtensa_expand_block_move (rtx *); +extern int xtensa_expand_block_set_unrolled_loop (rtx *); +extern int xtensa_expand_block_set_small_loop (rtx *); extern void xtensa_split_operand_pair (rtx *, machine_mode); extern int xtensa_emit_move_sequence (rtx *, machine_mode); extern rtx xtensa_copy_incoming_a7 (rtx); diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index 7023bad..c7b54ba 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -351,42 +351,42 @@ struct gcc_target targetm = TARGET_INITIALIZER; bool xtensa_simm8 (HOST_WIDE_INT v) { - return v >= -128 && v <= 127; + return IN_RANGE (v, -128, 127); } bool xtensa_simm8x256 (HOST_WIDE_INT v) { - return (v & 255) == 0 && (v >= -32768 && v <= 32512); + return (v & 255) == 0 && IN_RANGE (v, -32768, 32512); } bool xtensa_simm12b (HOST_WIDE_INT v) { - return v >= -2048 && v <= 2047; + return IN_RANGE (v, -2048, 2047); } static bool xtensa_uimm8 (HOST_WIDE_INT v) { - return v >= 0 && v <= 255; + return IN_RANGE (v, 0, 255); } static bool xtensa_uimm8x2 (HOST_WIDE_INT v) { - return (v & 1) == 0 && (v >= 0 && v <= 510); + return (v & 1) == 0 && IN_RANGE (v, 0, 510); } static bool xtensa_uimm8x4 (HOST_WIDE_INT v) { - return (v & 3) == 0 && (v >= 0 && v <= 1020); + return (v & 3) == 0 && IN_RANGE (v, 0, 1020); } @@ -456,19 +456,7 @@ xtensa_b4constu (HOST_WIDE_INT v) bool xtensa_mask_immediate (HOST_WIDE_INT v) { -#define MAX_MASK_SIZE 16 - int mask_size; - - for (mask_size = 1; mask_size <= MAX_MASK_SIZE; mask_size++) - { - if ((v & 1) == 0) - return false; - v = v >> 1; - if (v == 0) - return true; - } - - return false; + return IN_RANGE (exact_log2 (v + 1), 1, 16); } @@ -549,7 +537,7 @@ smalloffset_mem_p (rtx op) return FALSE; val = INTVAL (offset); - return (val & 3) == 0 && (val >= 0 && val <= 60); + return (val & 3) == 0 && IN_RANGE (val, 0, 60); } } return FALSE; @@ -1325,7 +1313,7 @@ xtensa_expand_block_move (rtx *operands) move_ratio = 4; if (optimize > 2) move_ratio = LARGEST_MOVE_RATIO; - num_pieces = (bytes / align) + (bytes % align); /* Close enough anyway. */ + num_pieces = (bytes / align) + ((bytes % align + 1) / 2); if (num_pieces > move_ratio) return 0; @@ -1362,7 +1350,7 @@ xtensa_expand_block_move (rtx *operands) temp[next] = gen_reg_rtx (mode[next]); x = adjust_address (src_mem, mode[next], offset_ld); - emit_insn (gen_rtx_SET (temp[next], x)); + emit_move_insn (temp[next], x); offset_ld += next_amount; bytes -= next_amount; @@ -1372,9 +1360,9 @@ xtensa_expand_block_move (rtx *operands) if (active[phase]) { active[phase] = false; - + x = adjust_address (dst_mem, mode[phase], offset_st); - emit_insn (gen_rtx_SET (x, temp[phase])); + emit_move_insn (x, temp[phase]); offset_st += amount[phase]; } @@ -1385,6 +1373,217 @@ xtensa_expand_block_move (rtx *operands) } +/* Try to expand a block set operation to a sequence of RTL move + instructions. If not optimizing, or if the block size is not a + constant, or if the block is too large, or if the value to + initialize the block with is not a constant, the expansion + fails and GCC falls back to calling memset(). + + operands[0] is the destination + operands[1] is the length + operands[2] is the initialization value + operands[3] is the alignment */ + +static int +xtensa_sizeof_MOVI (HOST_WIDE_INT imm) +{ + return (TARGET_DENSITY && IN_RANGE (imm, -32, 95)) ? 2 : 3; +} + +int +xtensa_expand_block_set_unrolled_loop (rtx *operands) +{ + rtx dst_mem = operands[0]; + HOST_WIDE_INT bytes, value, align; + int expand_len, funccall_len; + rtx x, reg; + int offset; + + if (!CONST_INT_P (operands[1]) || !CONST_INT_P (operands[2])) + return 0; + + bytes = INTVAL (operands[1]); + if (bytes <= 0) + return 0; + value = (int8_t)INTVAL (operands[2]); + align = INTVAL (operands[3]); + if (align > MOVE_MAX) + align = MOVE_MAX; + + /* Insn expansion: holding the init value. + Either MOV(.N) or L32R w/litpool. */ + if (align == 1) + expand_len = xtensa_sizeof_MOVI (value); + else if (value == 0 || value == -1) + expand_len = TARGET_DENSITY ? 2 : 3; + else + expand_len = 3 + 4; + /* Insn expansion: a series of aligned memory stores. + Consist of S8I, S16I or S32I(.N). */ + expand_len += (bytes / align) * (TARGET_DENSITY + && align == 4 ? 2 : 3); + /* Insn expansion: the remainder, sub-aligned memory stores. + A combination of S8I and S16I as needed. */ + expand_len += ((bytes % align + 1) / 2) * 3; + + /* Function call: preparing two arguments. */ + funccall_len = xtensa_sizeof_MOVI (value); + funccall_len += xtensa_sizeof_MOVI (bytes); + /* Function call: calling memset(). */ + funccall_len += TARGET_LONGCALLS ? (3 + 4 + 3) : 3; + + /* Apply expansion bonus (2x) if optimizing for speed. */ + if (optimize > 1 && !optimize_size) + funccall_len *= 2; + + /* Decide whether to expand or not, based on the sum of the length + of instructions. */ + if (expand_len > funccall_len) + return 0; + + x = XEXP (dst_mem, 0); + if (!REG_P (x)) + dst_mem = replace_equiv_address (dst_mem, force_reg (Pmode, x)); + switch (align) + { + case 1: + break; + case 2: + value = (int16_t)((uint8_t)value * 0x0101U); + break; + case 4: + value = (int32_t)((uint8_t)value * 0x01010101U); + break; + default: + gcc_unreachable (); + } + reg = force_reg (SImode, GEN_INT (value)); + + offset = 0; + do + { + int unit_size = MIN (bytes, align); + machine_mode unit_mode = (unit_size >= 4 ? SImode : + (unit_size >= 2 ? HImode : + QImode)); + unit_size = GET_MODE_SIZE (unit_mode); + + emit_move_insn (adjust_address (dst_mem, unit_mode, offset), + unit_mode == SImode ? reg + : convert_to_mode (unit_mode, reg, true)); + + offset += unit_size; + bytes -= unit_size; + } + while (bytes > 0); + + return 1; +} + +int +xtensa_expand_block_set_small_loop (rtx *operands) +{ + HOST_WIDE_INT bytes, value, align; + int expand_len, funccall_len; + rtx x, dst, end, reg; + machine_mode unit_mode; + rtx_code_label *label; + + if (!CONST_INT_P (operands[1]) || !CONST_INT_P (operands[2])) + return 0; + + bytes = INTVAL (operands[1]); + if (bytes <= 0) + return 0; + value = (int8_t)INTVAL (operands[2]); + align = INTVAL (operands[3]); + if (align > MOVE_MAX) + align = MOVE_MAX; + + /* Totally-aligned block only. */ + if (bytes % align != 0) + return 0; + + /* If 4-byte aligned, small loop substitution is almost optimal, thus + limited to only offset to the end address for ADDI/ADDMI instruction. */ + if (align == 4 + && ! (bytes <= 127 || (bytes <= 32512 && bytes % 256 == 0))) + return 0; + + /* If no 4-byte aligned, loop count should be treated as the constraint. */ + if (align != 4 + && bytes / align > ((optimize > 1 && !optimize_size) ? 8 : 15)) + return 0; + + /* Insn expansion: holding the init value. + Either MOV(.N) or L32R w/litpool. */ + if (align == 1) + expand_len = xtensa_sizeof_MOVI (value); + else if (value == 0 || value == -1) + expand_len = TARGET_DENSITY ? 2 : 3; + else + expand_len = 3 + 4; + /* Insn expansion: Either ADDI(.N) or ADDMI for the end address. */ + expand_len += bytes > 127 ? 3 + : (TARGET_DENSITY && bytes <= 15) ? 2 : 3; + + /* Insn expansion: the loop body and branch instruction. + For store, one of S8I, S16I or S32I(.N). + For advance, ADDI(.N). + For branch, BNE. */ + expand_len += (TARGET_DENSITY && align == 4 ? 2 : 3) + + (TARGET_DENSITY ? 2 : 3) + 3; + + /* Function call: preparing two arguments. */ + funccall_len = xtensa_sizeof_MOVI (value); + funccall_len += xtensa_sizeof_MOVI (bytes); + /* Function call: calling memset(). */ + funccall_len += TARGET_LONGCALLS ? (3 + 4 + 3) : 3; + + /* Apply expansion bonus (2x) if optimizing for speed. */ + if (optimize > 1 && !optimize_size) + funccall_len *= 2; + + /* Decide whether to expand or not, based on the sum of the length + of instructions. */ + if (expand_len > funccall_len) + return 0; + + x = XEXP (operands[0], 0); + if (!REG_P (x)) + x = XEXP (replace_equiv_address (operands[0], force_reg (Pmode, x)), 0); + dst = gen_reg_rtx (SImode); + emit_move_insn (dst, x); + end = gen_reg_rtx (SImode); + emit_insn (gen_addsi3 (end, dst, operands[1] /* the length */)); + switch (align) + { + case 1: + unit_mode = QImode; + break; + case 2: + value = (int16_t)((uint8_t)value * 0x0101U); + unit_mode = HImode; + break; + case 4: + value = (int32_t)((uint8_t)value * 0x01010101U); + unit_mode = SImode; + break; + default: + gcc_unreachable (); + } + reg = force_reg (unit_mode, GEN_INT (value)); + + label = gen_label_rtx (); + emit_label (label); + emit_move_insn (gen_rtx_MEM (unit_mode, dst), reg); + emit_insn (gen_addsi3 (dst, dst, GEN_INT (align))); + emit_cmp_and_jump_insns (dst, end, NE, const0_rtx, SImode, true, label); + + return 1; +} + + void xtensa_expand_nonlocal_goto (rtx *operands) { @@ -2379,7 +2578,7 @@ static void printx (FILE *file, signed int val) { /* Print a hexadecimal value in a nice way. */ - if ((val > -0xa) && (val < 0xa)) + if (IN_RANGE (val, -9, 9)) fprintf (file, "%d", val); else if (val < 0) fprintf (file, "-0x%x", -val); @@ -2430,17 +2629,11 @@ print_operand (FILE *file, rtx x, int letter) case 'K': if (GET_CODE (x) == CONST_INT) { - int num_bits = 0; unsigned val = INTVAL (x); - while (val & 1) - { - num_bits += 1; - val = val >> 1; - } - if ((val != 0) || (num_bits == 0) || (num_bits > 16)) + if (!xtensa_mask_immediate (val)) fatal_insn ("invalid mask", x); - fprintf (file, "%d", num_bits); + fprintf (file, "%d", floor_log2 (val + 1)); } else output_operand_lossage ("invalid %%K value"); @@ -2715,7 +2908,7 @@ xtensa_call_save_reg(int regno) return crtl->profile || !crtl->is_leaf || crtl->calls_eh_return || df_regs_ever_live_p (regno); - if (crtl->calls_eh_return && regno >= 2 && regno < 4) + if (crtl->calls_eh_return && IN_RANGE (regno, 2, 3)) return true; return !call_used_or_fixed_reg_p (regno) && df_regs_ever_live_p (regno); @@ -2835,7 +3028,7 @@ xtensa_expand_prologue (void) int callee_save_size = cfun->machine->callee_save_size; /* -128 is a limit of single addi instruction. */ - if (total_size > 0 && total_size <= 128) + if (IN_RANGE (total_size, 1, 128)) { insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-total_size))); diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h index d25594f..d027a77 100644 --- a/gcc/config/xtensa/xtensa.h +++ b/gcc/config/xtensa/xtensa.h @@ -504,7 +504,7 @@ enum reg_class used for this purpose since all function arguments are pushed on the stack. */ #define FUNCTION_ARG_REGNO_P(N) \ - ((N) >= GP_OUTGOING_ARG_FIRST && (N) <= GP_OUTGOING_ARG_LAST) + IN_RANGE ((N), GP_OUTGOING_ARG_FIRST, GP_OUTGOING_ARG_LAST) /* Record the number of argument words seen so far, along with a flag to indicate whether these are incoming arguments. (FUNCTION_INCOMING_ARG diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 96e043b..6f5cbc5 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -471,23 +471,68 @@ ;; Byte swap. -(define_insn "bswapsi2" - [(set (match_operand:SI 0 "register_operand" "=&a") - (bswap:SI (match_operand:SI 1 "register_operand" "r")))] - "!optimize_size" - "ssai\t8\;srli\t%0, %1, 16\;src\t%0, %0, %1\;src\t%0, %0, %0\;src\t%0, %1, %0" - [(set_attr "type" "arith") - (set_attr "mode" "SI") - (set_attr "length" "15")]) +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "") + (bswap:SI (match_operand:SI 1 "register_operand" "")))] + "!optimize_debug && optimize > 1" +{ + /* GIMPLE manual byte-swapping recognition is now activated. + For both built-in and manual bswaps, emit corresponding library call + if optimizing for size, or a series of dedicated machine instructions + if otherwise. */ + if (optimize_size) + emit_library_call_value (optab_libfunc (bswap_optab, SImode), + operands[0], LCT_NORMAL, SImode, + operands[1], SImode); + else + emit_insn (gen_bswapsi2_internal (operands[0], operands[1])); + DONE; +}) -(define_insn "bswapdi2" - [(set (match_operand:DI 0 "register_operand" "=&a") - (bswap:DI (match_operand:DI 1 "register_operand" "r")))] - "!optimize_size" - "ssai\t8\;srli\t%0, %D1, 16\;src\t%0, %0, %D1\;src\t%0, %0, %0\;src\t%0, %D1, %0\;srli\t%D0, %1, 16\;src\t%D0, %D0, %1\;src\t%D0, %D0, %D0\;src\t%D0, %1, %D0" - [(set_attr "type" "arith") - (set_attr "mode" "DI") - (set_attr "length" "27")]) +(define_insn "bswapsi2_internal" + [(set (match_operand:SI 0 "register_operand" "=a,&a") + (bswap:SI (match_operand:SI 1 "register_operand" "0,r"))) + (clobber (match_scratch:SI 2 "=&a,X"))] + "!optimize_debug && optimize > 1 && !optimize_size" +{ + rtx_insn *prev_insn = prev_nonnote_nondebug_insn (insn); + const char *init = "ssai\t8\;"; + static char result[64]; + if (prev_insn && NONJUMP_INSN_P (prev_insn)) + { + rtx x = PATTERN (prev_insn); + if (GET_CODE (x) == PARALLEL && XVECLEN (x, 0) == 2 + && GET_CODE (XVECEXP (x, 0, 0)) == SET + && GET_CODE (XVECEXP (x, 0, 1)) == CLOBBER) + { + x = XEXP (XVECEXP (x, 0, 0), 1); + if (GET_CODE (x) == BSWAP && GET_MODE (x) == SImode) + init = ""; + } + } + sprintf (result, + (which_alternative == 0) + ? "%s" "srli\t%%2, %%1, 16\;src\t%%2, %%2, %%1\;src\t%%2, %%2, %%2\;src\t%%0, %%1, %%2" + : "%s" "srli\t%%0, %%1, 16\;src\t%%0, %%0, %%1\;src\t%%0, %%0, %%0\;src\t%%0, %%1, %%0", + init); + return result; +} + [(set_attr "type" "arith,arith") + (set_attr "mode" "SI") + (set_attr "length" "15,15")]) + +(define_expand "bswapdi2" + [(set (match_operand:DI 0 "register_operand" "") + (bswap:DI (match_operand:DI 1 "register_operand" "")))] + "!optimize_debug && optimize > 1 && optimize_size" +{ + /* Replace with a single DImode library call. + Without this, two SImode library calls are emitted. */ + emit_library_call_value (optab_libfunc (bswap_optab, DImode), + operands[0], LCT_NORMAL, DImode, + operands[1], DImode); + DONE; +}) ;; Negation and one's complement. @@ -1080,6 +1125,22 @@ DONE; }) +;; Block sets + +(define_expand "setmemsi" + [(match_operand:BLK 0 "memory_operand") + (match_operand:SI 1 "") + (match_operand:SI 2 "") + (match_operand:SI 3 "const_int_operand")] + "!optimize_debug && optimize" +{ + if (xtensa_expand_block_set_unrolled_loop (operands)) + DONE; + if (xtensa_expand_block_set_small_loop (operands)) + DONE; + FAIL; +}) + ;; Shift instructions. diff --git a/gcc/config/xtensa/xtensa.opt b/gcc/config/xtensa/xtensa.opt index c406297..1fc68a3 100644 --- a/gcc/config/xtensa/xtensa.opt +++ b/gcc/config/xtensa/xtensa.opt @@ -27,7 +27,7 @@ Target Mask(FORCE_NO_PIC) Disable position-independent code (PIC) for use in OS kernel code. mlongcalls -Target +Target Mask(LONGCALLS) Use indirect CALLXn instructions for large programs. mtarget-align diff --git a/gcc/configure b/gcc/configure index 37e0dd5..ba3a998 100755 --- a/gcc/configure +++ b/gcc/configure @@ -29015,421 +29015,28 @@ case "$target" in ;; esac -# This tests if the assembler supports two registers for global_load functions -# (like in LLVM versions <12) or one register (like in LLVM 12). +# AMD GCN needs the LLVM assembler and linker. +# Test that LLVM is at least 13.0.1. case "$target" in amdgcn-* | gcn-*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler fix for global_load functions" >&5 -$as_echo_n "checking assembler fix for global_load functions... " >&6; } - gcc_cv_as_gcn_global_load_fixed=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: checking llvm assembler version" >&5 +$as_echo_n "checking llvm assembler version... " >&6; } + gcc_cv_as_version="unknown" if test x$gcc_cv_as != x; then - cat > conftest.s <<EOF - global_store_dwordx2 v[1:2], v[4:5], s[14:15] -EOF - if $gcc_cv_as -triple=amdgcn--amdhsa -filetype=obj -mcpu=gfx900 -o conftest.o conftest.s > /dev/null 2>&1; then - gcc_cv_as_gcn_global_load_fixed=no - fi - rm -f conftest.s conftest.o conftest - fi - global_load_fixed=`if test x$gcc_cv_as_gcn_global_load_fixed = xyes; then echo 1; else echo 0; fi` - -cat >>confdefs.h <<_ACEOF -#define HAVE_GCN_ASM_GLOBAL_LOAD_FIXED $global_load_fixed -_ACEOF - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_global_load_fixed" >&5 -$as_echo "$gcc_cv_as_gcn_global_load_fixed" >&6; } - ;; -esac - -case "$target" in - amdgcn-* | gcn-*) - # Test the LLVM assembler syntax dialect; they have made a number of - # changes between LLVM 12 & 13 without any backward compatibility. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler amdgcn_target v2/3 syntax" >&5 -$as_echo_n "checking assembler for assembler amdgcn_target v2/3 syntax... " >&6; } -if ${gcc_cv_as_gcn_asm_v3_syntax+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_asm_v3_syntax=no - if test x$gcc_cv_as != x; then - $as_echo '.amdgcn_target "amdgcn-unknown-amdhsa--gfx906+xnack"' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx906 -mattr=+xnack -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - gcc_cv_as_gcn_asm_v3_syntax=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_asm_v3_syntax" >&5 -$as_echo "$gcc_cv_as_gcn_asm_v3_syntax" >&6; } -if test $gcc_cv_as_gcn_asm_v3_syntax = yes; then - -$as_echo "#define HAVE_GCN_ASM_V3_SYNTAX 1" >>confdefs.h - -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler amdgcn_target v4 syntax" >&5 -$as_echo_n "checking assembler for assembler amdgcn_target v4 syntax... " >&6; } -if ${gcc_cv_as_gcn_asm_v4_syntax+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_asm_v4_syntax=no - if test x$gcc_cv_as != x; then - $as_echo '.amdgcn_target "amdgcn-unknown-amdhsa--gfx908:xnack+"' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx908 -mattr=+xnack -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - gcc_cv_as_gcn_asm_v4_syntax=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_asm_v4_syntax" >&5 -$as_echo "$gcc_cv_as_gcn_asm_v4_syntax" >&6; } -if test $gcc_cv_as_gcn_asm_v4_syntax = yes; then - -$as_echo "#define HAVE_GCN_ASM_V4_SYNTAX 1" >>confdefs.h - -fi - - - # Some attribute names changed in the move to v4 ... - if test $gcc_cv_as_gcn_asm_v3_syntax = yes; then - sramopt="+sram-ecc" - sramattr="+sram-ecc" - xnackattr="+xnack" - elif test $gcc_cv_as_gcn_asm_v4_syntax = yes; then - sramopt="+sramecc" - sramattr=":sramecc+" - xnackattr=":xnack+" - else - as_fn_error $? "Unrecognised assembler version" "$LINENO" 5 - fi - - # Test whether the LLVM assembler accepts -mattr=+xnack without any - # diagnostic. LLVM 9 & 10 accept the option whether it makes sense or not, - # LLVM 12+ throws a warning for GPUs without support. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=+xnack for fiji" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=+xnack for fiji... " >&6; } -if ${gcc_cv_as_gcn_xnack_ecc_fiji+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_xnack_ecc_fiji=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=fiji -mattr=+xnack 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_xnack_ecc_fiji=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_xnack_ecc_fiji" >&5 -$as_echo "$gcc_cv_as_gcn_xnack_ecc_fiji" >&6; } -if test $gcc_cv_as_gcn_xnack_ecc_fiji = yes; then - -$as_echo "#define HAVE_GCN_XNACK_FIJI 1" >>confdefs.h - -fi - - rm -f conftest.err - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=+xnack for gfx900" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=+xnack for gfx900... " >&6; } -if ${gcc_cv_as_gcn_xnack_ecc_gfx900+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_xnack_ecc_gfx900=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx900 -mattr=+xnack 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_xnack_ecc_gfx900=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_xnack_ecc_gfx900" >&5 -$as_echo "$gcc_cv_as_gcn_xnack_ecc_gfx900" >&6; } -if test $gcc_cv_as_gcn_xnack_ecc_gfx900 = yes; then - -$as_echo "#define HAVE_GCN_XNACK_GFX900 1" >>confdefs.h - -fi - - rm -f conftest.err - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=+xnack for gfx906" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=+xnack for gfx906... " >&6; } -if ${gcc_cv_as_gcn_xnack_ecc_gfx906+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_xnack_ecc_gfx906=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx906 -mattr=+xnack 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_xnack_ecc_gfx906=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_xnack_ecc_gfx906" >&5 -$as_echo "$gcc_cv_as_gcn_xnack_ecc_gfx906" >&6; } -if test $gcc_cv_as_gcn_xnack_ecc_gfx906 = yes; then - -$as_echo "#define HAVE_GCN_XNACK_GFX906 1" >>confdefs.h - -fi - - rm -f conftest.err - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=+xnack for gfx908" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=+xnack for gfx908... " >&6; } -if ${gcc_cv_as_gcn_xnack_ecc_gfx908+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_xnack_ecc_gfx908=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx908 -mattr=+xnack 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_xnack_ecc_gfx908=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_xnack_ecc_gfx908" >&5 -$as_echo "$gcc_cv_as_gcn_xnack_ecc_gfx908" >&6; } -if test $gcc_cv_as_gcn_xnack_ecc_gfx908 = yes; then - -$as_echo "#define HAVE_GCN_XNACK_GFX908 1" >>confdefs.h - -fi - - rm -f conftest.err - - # Test whether the LLVM assembler accepts -mattr=+sramecc without any - # diagnostic. LLVM 9 & 10 accept the option whether it makes sense or not, - # (some?) LLVM 12 rejects it for all GPUs, and LLVM13 throws a warning - # for GPUs without support. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=$sramopt for fiji" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=$sramopt for fiji... " >&6; } -if ${gcc_cv_as_gcn_sram_ecc_fiji+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_sram_ecc_fiji=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=fiji -mattr=$sramopt 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_sram_ecc_fiji=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_sram_ecc_fiji" >&5 -$as_echo "$gcc_cv_as_gcn_sram_ecc_fiji" >&6; } -if test $gcc_cv_as_gcn_sram_ecc_fiji = yes; then - -$as_echo "#define HAVE_GCN_SRAM_ECC_FIJI 1" >>confdefs.h - -fi - - rm -f conftest.err - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=$sramopt for gfx900" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=$sramopt for gfx900... " >&6; } -if ${gcc_cv_as_gcn_sram_ecc_gfx900+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_sram_ecc_gfx900=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx900 -mattr=$sramopt 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_sram_ecc_gfx900=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_sram_ecc_gfx900" >&5 -$as_echo "$gcc_cv_as_gcn_sram_ecc_gfx900" >&6; } -if test $gcc_cv_as_gcn_sram_ecc_gfx900 = yes; then - -$as_echo "#define HAVE_GCN_SRAM_ECC_GFX900 1" >>confdefs.h - -fi - - rm -f conftest.err - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=$sramopt for gfx906" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=$sramopt for gfx906... " >&6; } -if ${gcc_cv_as_gcn_sram_ecc_gfx906+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_sram_ecc_gfx906=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx906 -mattr=$sramopt 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_sram_ecc_gfx906=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_sram_ecc_gfx906" >&5 -$as_echo "$gcc_cv_as_gcn_sram_ecc_gfx906" >&6; } -if test $gcc_cv_as_gcn_sram_ecc_gfx906 = yes; then - -$as_echo "#define HAVE_GCN_SRAM_ECC_GFX906 1" >>confdefs.h - -fi - - rm -f conftest.err - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler accepts -mattr=$sramopt for gfx908" >&5 -$as_echo_n "checking assembler for assembler accepts -mattr=$sramopt for gfx908... " >&6; } -if ${gcc_cv_as_gcn_sram_ecc_gfx908+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_gcn_sram_ecc_gfx908=no - if test x$gcc_cv_as != x; then - $as_echo '' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -triple=amdgcn--amdhsa -mcpu=gfx908 -mattr=$sramopt 2>conftest.err -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - grep "." conftest.err >&5 \ - || gcc_cv_as_gcn_sram_ecc_gfx908=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 + gcc_cv_as_version=`$gcc_cv_as --version 2>&1 | sed -ne '/version/s/.* \([0-9]\)/\1/p' || echo error` + case "$gcc_cv_as_version" in + 13.0.[1-9]*) ;; # 13.0.1+ + 13.[1-9]*) ;; # 13.1+ + 1[4-9]*) ;; # 14..19 + [2-9][0-9]*) ;; # 20..99 + [1-9][0-9][0-9]*) ;; # 100+ + error) as_fn_error $? "cannot determine LLVM version" "$LINENO" 5 ;; + *) as_fn_error $? "LLVM 13.0.1 or later is required (found LLVM $gcc_cv_as_version)" "$LINENO" 5 ;; + esac fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_gcn_sram_ecc_gfx908" >&5 -$as_echo "$gcc_cv_as_gcn_sram_ecc_gfx908" >&6; } -if test $gcc_cv_as_gcn_sram_ecc_gfx908 = yes; then - -$as_echo "#define HAVE_GCN_SRAM_ECC_GFX908 1" >>confdefs.h - -fi - - rm -f conftest.err + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_version, ok" >&5 +$as_echo "$gcc_cv_as_version, ok" >&6; } ;; - arm*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler for arm accepts context-specific architecture extensions" >&5 -$as_echo_n "checking assembler for assembler for arm accepts context-specific architecture extensions... " >&6; } -if ${gcc_cv_as_arm_option_extensions+:} false; then : - $as_echo_n "(cached) " >&6 -else - gcc_cv_as_arm_option_extensions=no - if test x$gcc_cv_as != x; then - $as_echo '.text - .thumb - .syntax unified - vmov.f32 s0, s1' > conftest.s - if { ac_try='$gcc_cv_as $gcc_cv_as_flags -march=armv8.1-m.main+mve -o conftest.o conftest.s >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; } - then - gcc_cv_as_arm_option_extensions=yes - else - echo "configure: failed program was" >&5 - cat conftest.s >&5 - fi - rm -f conftest.o conftest.s - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_arm_option_extensions" >&5 -$as_echo "$gcc_cv_as_arm_option_extensions" >&6; } -if test $gcc_cv_as_arm_option_extensions = yes; then - -$as_echo "#define HAVE_GAS_ARM_EXTENDED_ARCH 1" >>confdefs.h - -fi - esac # ??? Not all targets support dwarf2 debug_line, even within a version diff --git a/gcc/configure.ac b/gcc/configure.ac index 23bee70..4cd48b4 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -5375,141 +5375,26 @@ case "$target" in ;; esac -# This tests if the assembler supports two registers for global_load functions -# (like in LLVM versions <12) or one register (like in LLVM 12). +# AMD GCN needs the LLVM assembler and linker. +# Test that LLVM is at least 13.0.1. case "$target" in amdgcn-* | gcn-*) - AC_MSG_CHECKING(assembler fix for global_load functions) - gcc_cv_as_gcn_global_load_fixed=yes + AC_MSG_CHECKING(llvm assembler version) + gcc_cv_as_version="unknown" if test x$gcc_cv_as != x; then - cat > conftest.s <<EOF - global_store_dwordx2 v[[1:2]], v[[4:5]], s[[14:15]] -EOF - if $gcc_cv_as -triple=amdgcn--amdhsa -filetype=obj -mcpu=gfx900 -o conftest.o conftest.s > /dev/null 2>&1; then - gcc_cv_as_gcn_global_load_fixed=no - fi - rm -f conftest.s conftest.o conftest - fi - global_load_fixed=`if test x$gcc_cv_as_gcn_global_load_fixed = xyes; then echo 1; else echo 0; fi` - AC_DEFINE_UNQUOTED(HAVE_GCN_ASM_GLOBAL_LOAD_FIXED, $global_load_fixed, - [Define if your assembler has fixed global_load functions.]) - AC_MSG_RESULT($gcc_cv_as_gcn_global_load_fixed) - ;; -esac - -case "$target" in - amdgcn-* | gcn-*) - # Test the LLVM assembler syntax dialect; they have made a number of - # changes between LLVM 12 & 13 without any backward compatibility. - gcc_GAS_CHECK_FEATURE([assembler amdgcn_target v2/3 syntax], - gcc_cv_as_gcn_asm_v3_syntax, - [-triple=amdgcn--amdhsa -mcpu=gfx906 -mattr=+xnack], - [.amdgcn_target "amdgcn-unknown-amdhsa--gfx906+xnack"],, - [AC_DEFINE(HAVE_GCN_ASM_V3_SYNTAX, 1, - [Define if your assembler expects amdgcn_target gfx908+xnack syntax.])]) - gcc_GAS_CHECK_FEATURE([assembler amdgcn_target v4 syntax], - gcc_cv_as_gcn_asm_v4_syntax, - [-triple=amdgcn--amdhsa -mcpu=gfx908 -mattr=+xnack], - [.amdgcn_target "amdgcn-unknown-amdhsa--gfx908:xnack+"],, - [AC_DEFINE(HAVE_GCN_ASM_V4_SYNTAX, 1, - [Define if your assembler expects amdgcn_target gfx908:xnack+ syntax.])]) - - # Some attribute names changed in the move to v4 ... - if test $gcc_cv_as_gcn_asm_v3_syntax = yes; then - sramopt="+sram-ecc" - sramattr="+sram-ecc" - xnackattr="+xnack" - elif test $gcc_cv_as_gcn_asm_v4_syntax = yes; then - sramopt="+sramecc" - sramattr=":sramecc+" - xnackattr=":xnack+" - else - AC_MSG_ERROR([Unrecognised assembler version]) + gcc_cv_as_version=`$gcc_cv_as --version 2>&1 | sed -ne '/version/s/.* \([[0-9]]\)/\1/p' || echo error` + case "$gcc_cv_as_version" in + 13.0.[[1-9]]*) ;; # 13.0.1+ + 13.[[1-9]]*) ;; # 13.1+ + 1[[4-9]]*) ;; # 14..19 + [[2-9]][[0-9]]*) ;; # 20..99 + [[1-9]][[0-9]][[0-9]]*) ;; # 100+ + error) AC_MSG_ERROR([cannot determine LLVM version]) ;; + *) AC_MSG_ERROR([LLVM 13.0.1 or later is required (found LLVM $gcc_cv_as_version)]) ;; + esac fi - - # Test whether the LLVM assembler accepts -mattr=+xnack without any - # diagnostic. LLVM 9 & 10 accept the option whether it makes sense or not, - # LLVM 12+ throws a warning for GPUs without support. - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=+xnack for fiji], - gcc_cv_as_gcn_xnack_ecc_fiji, - [-triple=amdgcn--amdhsa -mcpu=fiji -mattr=+xnack 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_xnack_ecc_fiji=yes], - [AC_DEFINE(HAVE_GCN_XNACK_FIJI, 1, - [Define if your assembler allows -mattr=+xnack for fiji.])]) - rm -f conftest.err - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=+xnack for gfx900], - gcc_cv_as_gcn_xnack_ecc_gfx900, - [-triple=amdgcn--amdhsa -mcpu=gfx900 -mattr=+xnack 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_xnack_ecc_gfx900=yes], - [AC_DEFINE(HAVE_GCN_XNACK_GFX900, 1, - [Define if your assembler allows -mattr=+xnack for gfx900.])]) - rm -f conftest.err - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=+xnack for gfx906], - gcc_cv_as_gcn_xnack_ecc_gfx906, - [-triple=amdgcn--amdhsa -mcpu=gfx906 -mattr=+xnack 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_xnack_ecc_gfx906=yes], - [AC_DEFINE(HAVE_GCN_XNACK_GFX906, 1, - [Define if your assembler allows -mattr=+xnack for gfx906.])]) - rm -f conftest.err - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=+xnack for gfx908], - gcc_cv_as_gcn_xnack_ecc_gfx908, - [-triple=amdgcn--amdhsa -mcpu=gfx908 -mattr=+xnack 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_xnack_ecc_gfx908=yes], - [AC_DEFINE(HAVE_GCN_XNACK_GFX908, 1, - [Define if your assembler allows -mattr=+xnack for gfx908.])]) - rm -f conftest.err - - # Test whether the LLVM assembler accepts -mattr=+sramecc without any - # diagnostic. LLVM 9 & 10 accept the option whether it makes sense or not, - # (some?) LLVM 12 rejects it for all GPUs, and LLVM13 throws a warning - # for GPUs without support. - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=$sramopt for fiji], - gcc_cv_as_gcn_sram_ecc_fiji, - [-triple=amdgcn--amdhsa -mcpu=fiji -mattr=$sramopt 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_sram_ecc_fiji=yes], - [AC_DEFINE(HAVE_GCN_SRAM_ECC_FIJI, 1, - [Define if your assembler allows -mattr=+sramecc for fiji.])]) - rm -f conftest.err - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=$sramopt for gfx900], - gcc_cv_as_gcn_sram_ecc_gfx900, - [-triple=amdgcn--amdhsa -mcpu=gfx900 -mattr=$sramopt 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_sram_ecc_gfx900=yes], - [AC_DEFINE(HAVE_GCN_SRAM_ECC_GFX900, 1, - [Define if your assembler allows -mattr=+sramecc for gfx900.])]) - rm -f conftest.err - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=$sramopt for gfx906], - gcc_cv_as_gcn_sram_ecc_gfx906, - [-triple=amdgcn--amdhsa -mcpu=gfx906 -mattr=$sramopt 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_sram_ecc_gfx906=yes], - [AC_DEFINE(HAVE_GCN_SRAM_ECC_GFX906, 1, - [Define if your assembler allows -mattr=+sramecc for gfx906.])]) - rm -f conftest.err - gcc_GAS_CHECK_FEATURE([assembler accepts -mattr=$sramopt for gfx908], - gcc_cv_as_gcn_sram_ecc_gfx908, - [-triple=amdgcn--amdhsa -mcpu=gfx908 -mattr=$sramopt 2>conftest.err], [], - [grep "." conftest.err >&AS_MESSAGE_LOG_FD \ - || gcc_cv_as_gcn_sram_ecc_gfx908=yes], - [AC_DEFINE(HAVE_GCN_SRAM_ECC_GFX908, 1, - [Define if your assembler allows -mattr=+sramecc for gfx908.])]) - rm -f conftest.err + AC_MSG_RESULT([$gcc_cv_as_version, ok]) ;; - arm*) - gcc_GAS_CHECK_FEATURE([assembler for arm accepts context-specific architecture extensions], - gcc_cv_as_arm_option_extensions, - [-march=armv8.1-m.main+mve], - [.text - .thumb - .syntax unified - vmov.f32 s0, s1],, - [AC_DEFINE(HAVE_GAS_ARM_EXTENDED_ARCH, 1, - [Define if your Arm assembler permits context-specific feature extensions.])]) esac # ??? Not all targets support dwarf2 debug_line, even within a version diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e4788be..8575393 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,145 @@ +2022-05-28 Jakub Jelinek <jakub@redhat.com> + + * parser.cc (handle_omp_declare_target_clause): If OMP_CLAUSE_LINK was + seen first, use "%<to%>" or "%<enter%>" depending on + OMP_CLAUSE_ENTER_TO of the current clause, otherwise use + "%<to%> or %<enter%>" wording. + +2022-05-28 Jason Merrill <jason@redhat.com> + + PR c++/105652 + * pt.cc (tsubst_lambda_expr): Don't let a namespace-scope lambda + instantiate into a class-scope lambda. + +2022-05-27 Marek Polacek <polacek@redhat.com> + + PR c++/105725 + * parser.cc (class_decl_loc_t::add): Check CLASS_TYPE_P. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + * parser.cc (cp_parser_omp_clause_name): Parse enter clause. + (cp_parser_omp_all_clauses): For to clause on declare target, use + OMP_CLAUSE_ENTER clause with OMP_CLAUSE_ENTER_TO instead of + OMP_CLAUSE_TO_DECLARE clause. Handle PRAGMA_OMP_CLAUSE_ENTER. + (OMP_DECLARE_TARGET_CLAUSE_MASK): Add enter clause. + (cp_parser_omp_declare_target): Use OMP_CLAUSE_ENTER instead of + OMP_CLAUSE_TO_DECLARE. + * semantics.cc (finish_omp_clauses): Handle OMP_CLAUSE_ENTER instead + of OMP_CLAUSE_TO_DECLARE, to OMP_CLAUSE_ENTER_TO use "to" as clause + name in diagnostics instead of + omp_clause_code_name[OMP_CLAUSE_CODE (c)]. + +2022-05-26 Marek Polacek <polacek@redhat.com> + + PR c++/105569 + * typeck.cc (warn_for_null_address): Improve the warning when + the POINTER_PLUS_EXPR's base is of reference type. + +2022-05-26 Patrick Palka <ppalka@redhat.com> + + PR c++/96363 + * decl.cc (shadow_tag): Use the return value of + maybe_process_partial_specialization. + * parser.cc (cp_parser_single_declaration): Call shadow_tag + before associate_classtype_constraints. + * pt.cc (maybe_new_partial_specialization): Change return type + to bool. Take 'type' argument by mutable reference. Set 'type' + to point to the correct constrained specialization when + appropriate. + (maybe_process_partial_specialization): Adjust accordingly. + +2022-05-25 Marek Polacek <polacek@redhat.com> + + PR c++/96637 + * cp-tree.h (attr_chainon): Declare. + * decl.cc (start_decl): Use attr_chainon. + (grokdeclarator): Likewise. + * parser.cc (cp_parser_statement): No longer static. + +2022-05-25 Jason Merrill <jason@redhat.com> + + PR c++/105655 + * pt.cc (build_template_decl): Add assert. + (tsubst_function_decl): Don't return a template. + +2022-05-25 Jason Merrill <jason@redhat.com> + + PR c++/105623 + * decl2.cc (mark_used): Copy type from fn to BASELINK. + * pt.cc (unify_one_argument): Call mark_single_function. + +2022-05-25 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_call_expression): Check for + heap vars in the result. + +2022-05-25 Jason Merrill <jason@redhat.com> + + * constexpr.cc (maybe_constant_init_1): Only pass false for + strict when initializing a variable of static duration. + +2022-05-25 Marek Polacek <polacek@redhat.com> + + PR c++/100252 + * typeck2.cc (potential_prvalue_result_of): New. + (replace_placeholders_for_class_temp_r): New. + (digest_nsdmi_init): Call it. + +2022-05-24 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_fold_indirect_ref): Add default arg. + (cxx_eval_call_expression): Call it. + (cxx_fold_indirect_ref_1): Handle null empty_base. + +2022-05-24 Jason Merrill <jason@redhat.com> + + * constexpr.cc (enum value_cat): New. Change all 'lval' parameters + from int to value_cat. Change most false to vc_prvalue, most true + to vc_glvalue, cases where the return value is ignored to + vc_discard. + (cxx_eval_statement_list): Only vc_prvalue for stmt-expr result. + (cxx_eval_store_expression): Only build _REF for vc_glvalue. + (cxx_eval_array_reference, cxx_eval_component_reference) + (cxx_eval_indirect_ref, cxx_eval_constant_expression): Likewise. + +2022-05-24 Jason Merrill <jason@redhat.com> + + PR c++/105622 + * constexpr.cc (cxx_eval_store_expression): Adjust assert. + Use initialized_type. + +2022-05-24 Patrick Palka <ppalka@redhat.com> + + * cp-tree.h (any_template_arguments_need_structural_equality_p): + Declare. + * pt.cc (struct ctp_hasher): Define. + (ctp_table): Define. + (canonical_type_parameter): Use it. + (process_template_parm): Set TYPE_CANONICAL for + TEMPLATE_TEMPLATE_PARM too. + (lookup_template_class_1): Remove now outdated comment for the + any_template_arguments_need_structural_equality_p test. + (tsubst) <case TEMPLATE_TEMPLATE_PARM, etc>: Don't specifically + clear TYPE_CANONICAL for ttps. Set TYPE_CANONICAL on the + substituted type later. + (any_template_arguments_need_structural_equality_p): Return + true for any_targ_node. Don't return true just because a + template argument uses structural equality. Add comment for + the PARM_DECL special case. + (rewrite_template_parm): Set TYPE_CANONICAL on the rewritten + parm's type later. + * tree.cc (bind_template_template_parm): Set TYPE_CANONICAL + when safe to do so. + * typeck.cc (structural_comptypes) [check_alias]: Increment + processing_template_decl before checking + dependent_alias_template_spec_p. + +2022-05-24 Jakub Jelinek <jakub@redhat.com> + + PR c/105378 + * parser.cc (OMP_TASKWAIT_CLAUSE_MASK): Add nowait clause. + 2022-05-20 David Malcolm <dmalcolm@redhat.com> * cxx-pretty-print.h: Replace uses of "FINAL" and "OVERRIDE" with diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 433fa76..4520847 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1210,9 +1210,6 @@ uid_sensitive_constexpr_evaluation_checker::evaluation_restricted_p () const static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table; -static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, - bool, bool *, bool *, tree * = NULL); - /* Compute a hash value for a constexpr call representation. */ inline hashval_t @@ -1346,13 +1343,28 @@ get_nth_callarg (tree t, int n) } } +/* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST), + a glvalue (e.g. VAR_DECL or _REF), or nothing. */ + +enum value_cat { + vc_prvalue = 0, + vc_glvalue = 1, + vc_discard = 2 +}; + +static tree cxx_eval_constant_expression (const constexpr_ctx *, tree, + value_cat, bool *, bool *, tree * = NULL); +static tree cxx_fold_indirect_ref (const constexpr_ctx *, location_t, tree, tree, + bool * = NULL); +static tree find_heap_var_refs (tree *, int *, void *); + /* Attempt to evaluate T which represents a call to a builtin function. We assume here that all builtin functions evaluate to scalar types represented by _CST nodes. */ static tree cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { const int nargs = call_expr_nargs (t); @@ -1458,7 +1470,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, || potential_constant_expression (arg)) { bool dummy1 = false, dummy2 = false; - arg = cxx_eval_constant_expression (&new_ctx, arg, false, + arg = cxx_eval_constant_expression (&new_ctx, arg, vc_prvalue, &dummy1, &dummy2); } @@ -1703,7 +1715,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun, /* Normally we would strip a TARGET_EXPR in an initialization context such as this, but here we do the elision differently: we keep the TARGET_EXPR, and use its CONSTRUCTOR as the value of the parm. */ - arg = cxx_eval_constant_expression (ctx, x, /*lval=*/false, + arg = cxx_eval_constant_expression (ctx, x, vc_prvalue, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p && ctx->quiet) @@ -1807,7 +1819,7 @@ cx_error_context (void) static tree cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { enum tree_code opcode = ERROR_MARK; @@ -1832,12 +1844,13 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, case IFN_LAUNDER: return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), - false, non_constant_p, overflow_p); + vc_prvalue, non_constant_p, + overflow_p); case IFN_VEC_CONVERT: { tree arg = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), - false, non_constant_p, + vc_prvalue, non_constant_p, overflow_p); if (TREE_CODE (arg) == VECTOR_CST) if (tree r = fold_const_call (CFN_VEC_CONVERT, TREE_TYPE (t), arg)) @@ -2103,7 +2116,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, } /* Evaluate the object so that we know its dynamic type. */ - obj = cxx_eval_constant_expression (ctx, obj, /*lval*/false, non_constant_p, + obj = cxx_eval_constant_expression (ctx, obj, vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) return call; @@ -2138,7 +2151,7 @@ cxx_eval_dynamic_cast_fn (const constexpr_ctx *ctx, tree call, considered to be a most derived object that has the type of the constructor or destructor's class. */ tree vtable = build_vfield_ref (obj, objtype); - vtable = cxx_eval_constant_expression (ctx, vtable, /*lval*/false, + vtable = cxx_eval_constant_expression (ctx, vtable, vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) return call; @@ -2301,7 +2314,7 @@ replace_decl (tree *tp, tree decl, tree replacement) static tree cxx_eval_thunk_call (const constexpr_ctx *ctx, tree t, tree thunk_fndecl, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { tree function = THUNK_TARGET (thunk_fndecl); @@ -2362,7 +2375,7 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, { /* Subobjects might not be stored in ctx->global->values but we can get its CONSTRUCTOR by evaluating *this. */ - tree e = cxx_eval_constant_expression (ctx, object, /*lval*/false, + tree e = cxx_eval_constant_expression (ctx, object, vc_prvalue, non_constant_p, overflow_p); if (TREE_CODE (e) == CONSTRUCTOR && !*non_constant_p) TREE_READONLY (e) = readonly_p; @@ -2375,7 +2388,7 @@ cxx_set_object_constness (const constexpr_ctx *ctx, tree object, static tree cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { /* Handle concept checks separately. */ @@ -2395,9 +2408,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (fun) != FUNCTION_DECL) { /* Might be a constexpr function pointer. */ - fun = cxx_eval_constant_expression (ctx, fun, - /*lval*/false, non_constant_p, - overflow_p); + fun = cxx_eval_constant_expression (ctx, fun, vc_prvalue, + non_constant_p, overflow_p); STRIP_NOPS (fun); if (TREE_CODE (fun) == ADDR_EXPR) fun = TREE_OPERAND (fun, 0); @@ -2463,7 +2475,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, for (int i = 0; i < nargs; ++i) { tree arg = CALL_EXPR_ARG (t, i); - arg = cxx_eval_constant_expression (ctx, arg, false, + arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (arg); if (i == 0) @@ -2571,7 +2583,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, for (int i = 0; i < nargs; ++i) { tree arg = CALL_EXPR_ARG (t, i); - arg = cxx_eval_constant_expression (ctx, arg, false, + arg = cxx_eval_constant_expression (ctx, arg, vc_prvalue, non_constant_p, overflow_p); if (i == 1) arg1 = arg; @@ -2711,9 +2723,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, At this point it has already been evaluated in the call to cxx_bind_parameters_in_call. */ new_obj = TREE_VEC_ELT (new_call.bindings, 0); - STRIP_NOPS (new_obj); - if (TREE_CODE (new_obj) == ADDR_EXPR) - new_obj = TREE_OPERAND (new_obj, 0); + new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj); if (ctx->call && ctx->call->fundef && DECL_CONSTRUCTOR_P (ctx->call->fundef->decl)) @@ -2852,7 +2862,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree jump_target = NULL_TREE; cxx_eval_constant_expression (&ctx_with_save_exprs, body, - lval, non_constant_p, overflow_p, + vc_discard, non_constant_p, overflow_p, &jump_target); if (DECL_CONSTRUCTOR_P (fun)) @@ -2956,6 +2966,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, cacheable = false; break; } + /* Also don't cache a call that returns a deallocated pointer. */ + if (cacheable && (cp_walk_tree_without_duplicates + (&result, find_heap_var_refs, NULL))) + cacheable = false; } /* Rewrite all occurrences of the function's RESULT_DECL with the @@ -3213,7 +3227,7 @@ cxx_eval_unary_expression (const constexpr_ctx *ctx, tree t, { tree r; tree orig_arg = TREE_OPERAND (t, 0); - tree arg = cxx_eval_constant_expression (ctx, orig_arg, /*lval*/false, + tree arg = cxx_eval_constant_expression (ctx, orig_arg, vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (arg); location_t loc = EXPR_LOCATION (t); @@ -3259,8 +3273,8 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, t = fold_convert_loc (loc, ssizetype, TREE_OPERAND (lhs, 1)); tree nelts = array_type_nelts_top (TREE_TYPE (TREE_OPERAND (lhs, 0))); - nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p, - overflow_p); + nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue, + non_constant_p, overflow_p); if (*non_constant_p) return NULL_TREE; /* Don't fold an out-of-bound access. */ @@ -3281,7 +3295,7 @@ cxx_fold_pointer_plus_expression (const constexpr_ctx *ctx, tree t, t, NULL_TREE, NULL_TREE); t = cp_build_addr_expr (t, tf_warning_or_error); t = cp_fold_convert (orig_type, t); - return cxx_eval_constant_expression (ctx, t, /*lval*/false, + return cxx_eval_constant_expression (ctx, t, vc_prvalue, non_constant_p, overflow_p); } @@ -3325,20 +3339,20 @@ cxx_maybe_fold_addr_pointer_plus (tree t) static tree cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { tree r = NULL_TREE; tree orig_lhs = TREE_OPERAND (t, 0); tree orig_rhs = TREE_OPERAND (t, 1); tree lhs, rhs; - lhs = cxx_eval_constant_expression (ctx, orig_lhs, /*lval*/false, + lhs = cxx_eval_constant_expression (ctx, orig_lhs, vc_prvalue, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here, it's unnecessary and will break pointer subtraction. */ if (*non_constant_p) return t; - rhs = cxx_eval_constant_expression (ctx, orig_rhs, /*lval*/false, + rhs = cxx_eval_constant_expression (ctx, orig_rhs, vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) return t; @@ -3457,12 +3471,12 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t, static tree cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p, tree *jump_target) { tree val = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), - /*lval*/false, + vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (val); if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) @@ -3504,15 +3518,15 @@ cxx_eval_vector_conditional_expression (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p) { tree arg1 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), - /*lval*/false, + vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (arg1); tree arg2 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), - /*lval*/false, + vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (arg2); tree arg3 = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2), - /*lval*/false, + vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (arg3); location_t loc = EXPR_LOCATION (t); @@ -3844,7 +3858,7 @@ get_array_or_vector_nelts (const constexpr_ctx *ctx, tree type, gcc_unreachable (); /* For VLAs, the number of elements won't be an integer constant. */ - nelts = cxx_eval_constant_expression (ctx, nelts, false, + nelts = cxx_eval_constant_expression (ctx, nelts, vc_prvalue, non_constant_p, overflow_p); return nelts; } @@ -3881,7 +3895,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx, location_t loc = cp_expr_loc_or_input_loc (t); tree ary = TREE_OPERAND (t, 0); t = TREE_OPERAND (t, 1); - tree index = cxx_eval_constant_expression (ctx, t, false, + tree index = cxx_eval_constant_expression (ctx, t, vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (index); @@ -3913,7 +3927,7 @@ eval_and_check_array_index (const constexpr_ctx *ctx, static tree cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { tree oldary = TREE_OPERAND (t, 0); @@ -3936,6 +3950,8 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, if (lval && ary == oldary && index == oldidx) return t; + else if (lval == vc_discard) + return t; else if (lval) return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); @@ -4043,7 +4059,7 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, static tree cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { unsigned HOST_WIDE_INT i; @@ -4067,6 +4083,8 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, whole = cplus_expand_constant (whole); if (whole == orig_whole) return t; + if (lval == vc_discard) + return t; if (lval) return fold_build3 (COMPONENT_REF, TREE_TYPE (t), whole, part, NULL_TREE); @@ -4152,7 +4170,7 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t, static tree cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { tree orig_whole = TREE_OPERAND (t, 0); @@ -4449,7 +4467,7 @@ cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, return t; } - tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false, + tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) return t; @@ -4569,14 +4587,14 @@ cxx_eval_logical_expression (const constexpr_ctx *ctx, tree t, { tree r; tree lhs = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), - /*lval*/false, non_constant_p, + vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (lhs); if (tree_int_cst_equal (lhs, bailout_value)) return lhs; gcc_assert (tree_int_cst_equal (lhs, continue_value)); r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), - /*lval*/false, non_constant_p, + vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (r); return r; @@ -4725,7 +4743,7 @@ verify_ctor_sanity (const constexpr_ctx *ctx, tree type) static tree cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); @@ -4858,7 +4876,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, static tree cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, - bool value_init, bool lval, + bool value_init, value_cat lval, bool *non_constant_p, bool *overflow_p) { tree elttype = TREE_TYPE (atype); @@ -5000,7 +5018,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init, static tree cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { tree atype = TREE_TYPE (t); @@ -5070,7 +5088,7 @@ cxx_union_active_member (const constexpr_ctx *ctx, tree t) constexpr_ctx new_ctx = *ctx; new_ctx.quiet = true; bool non_constant_p = false, overflow_p = false; - tree ctor = cxx_eval_constant_expression (&new_ctx, t, false, + tree ctor = cxx_eval_constant_expression (&new_ctx, t, vc_prvalue, &non_constant_p, &overflow_p); if (TREE_CODE (ctor) == CONSTRUCTOR @@ -5184,7 +5202,8 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, && CLASS_TYPE_P (optype) && DERIVED_FROM_P (type, optype)) { - *empty_base = true; + if (empty_base) + *empty_base = true; return op; } } @@ -5203,7 +5222,7 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, static tree cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, - tree op0, bool *empty_base) + tree op0, bool *empty_base /* = NULL*/) { tree sub = op0; tree subtype; @@ -5306,7 +5325,7 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, static tree cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { tree orig_op0 = TREE_OPERAND (t, 0); @@ -5330,7 +5349,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, { /* If that didn't work, evaluate the operand first. */ tree op0 = cxx_eval_constant_expression (ctx, orig_op0, - /*lval*/false, non_constant_p, + vc_prvalue, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) @@ -5366,7 +5385,7 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, return t; } - if (lval && op0 != orig_op0) + if (lval == vc_glvalue && op0 != orig_op0) return build1 (INDIRECT_REF, TREE_TYPE (t), op0); if (!lval) VERIFY_CONSTANT (t); @@ -5462,7 +5481,7 @@ non_const_var_error (location_t loc, tree r) static tree cxx_eval_trinary_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { int i; @@ -5594,7 +5613,7 @@ modifying_const_object_p (tree_code code, tree obj, bool mutable_p) static tree cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { constexpr_ctx new_ctx = *ctx; @@ -5617,19 +5636,19 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, stored in, so that any side-effects happen first. */ if (!SCALAR_TYPE_P (type)) new_ctx.ctor = new_ctx.object = NULL_TREE; - init = cxx_eval_constant_expression (&new_ctx, init, false, + init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) return t; } bool evaluated = false; - if (lval) + if (lval == vc_glvalue) { /* If we want to return a reference to the target, we need to evaluate it as a whole; otherwise, only evaluate the innermost piece to avoid building up unnecessary *_REFs. */ - target = cxx_eval_constant_expression (ctx, target, true, + target = cxx_eval_constant_expression (ctx, target, lval, non_constant_p, overflow_p); evaluated = true; if (*non_constant_p) @@ -5681,7 +5700,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, object = probe; else { - probe = cxx_eval_constant_expression (ctx, probe, true, + probe = cxx_eval_constant_expression (ctx, probe, vc_glvalue, non_constant_p, overflow_p); evaluated = true; if (*non_constant_p) @@ -5893,7 +5912,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (init) == TARGET_EXPR) if (tree tinit = TARGET_EXPR_INITIAL (init)) init = tinit; - init = cxx_eval_constant_expression (&new_ctx, init, false, + init = cxx_eval_constant_expression (&new_ctx, init, vc_prvalue, non_constant_p, overflow_p); /* The hash table might have moved since the get earlier, and the initializer might have mutated the underlying CONSTRUCTORs, so we must @@ -5916,15 +5935,15 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (*valp), type))); if (empty_base || !(same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (init), type))) + (initialized_type (init), type))) { /* For initialization of an empty base, the original target will be *(base*)this, evaluation of which resolves to the object argument, which has the derived type rather than the base type. In this situation, just evaluate the initializer and return, since there's no actual data to store, and we didn't build a CONSTRUCTOR. */ + gcc_assert (is_empty_class (TREE_TYPE (target))); empty_base = true; - gcc_assert (is_empty_class (TREE_TYPE (init))); if (!*valp) { /* But do make sure we have something in *valp. */ @@ -5992,7 +6011,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, static tree cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p) { enum tree_code code = TREE_CODE (t); @@ -6006,12 +6025,12 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t, offset = fold_simple (offset); /* The operand as an lvalue. */ - op = cxx_eval_constant_expression (ctx, op, true, + op = cxx_eval_constant_expression (ctx, op, vc_glvalue, non_constant_p, overflow_p); /* The operand as an rvalue. */ tree val - = cxx_eval_constant_expression (ctx, op, false, + = cxx_eval_constant_expression (ctx, op, vc_prvalue, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT if this might be dealing with a pointer to a local array in a constexpr function. */ @@ -6160,8 +6179,10 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, local_target = NULL_TREE; jump_target = &local_target; } - for (tree stmt : tsi_range (t)) + for (tree_stmt_iterator i = tsi_start (t); !tsi_end_p (i); ++i) { + tree stmt = *i; + /* We've found a continue, so skip everything until we reach the label its jumping to. */ if (continues (jump_target)) @@ -6174,7 +6195,13 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, } if (TREE_CODE (stmt) == DEBUG_BEGIN_STMT) continue; - r = cxx_eval_constant_expression (ctx, stmt, false, + + value_cat lval = vc_discard; + /* The result of a statement-expression is not wrapped in EXPR_STMT. */ + if (tsi_one_before_end_p (i) && TREE_CODE (stmt) != EXPR_STMT) + lval = vc_prvalue; + + r = cxx_eval_constant_expression (ctx, stmt, lval, non_constant_p, overflow_p, jump_target); if (*non_constant_p) @@ -6228,7 +6255,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, break; case FOR_STMT: if (FOR_INIT_STMT (t)) - cxx_eval_constant_expression (ctx, FOR_INIT_STMT (t), /*lval*/false, + cxx_eval_constant_expression (ctx, FOR_INIT_STMT (t), vc_discard, non_constant_p, overflow_p, jump_target); if (*non_constant_p) return NULL_TREE; @@ -6247,7 +6274,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, if (count != -1) { if (body) - cxx_eval_constant_expression (&new_ctx, body, /*lval*/false, + cxx_eval_constant_expression (&new_ctx, body, vc_discard, non_constant_p, overflow_p, jump_target); if (breaks (jump_target)) @@ -6260,7 +6287,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, *jump_target = NULL_TREE; if (expr) - cxx_eval_constant_expression (&new_ctx, expr, /*lval*/false, + cxx_eval_constant_expression (&new_ctx, expr, vc_prvalue, non_constant_p, overflow_p, jump_target); } @@ -6268,7 +6295,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, if (cond) { tree res - = cxx_eval_constant_expression (&new_ctx, cond, /*lval*/false, + = cxx_eval_constant_expression (&new_ctx, cond, vc_prvalue, non_constant_p, overflow_p, jump_target); if (res) @@ -6322,7 +6349,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, { tree cond = TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t); - cond = cxx_eval_constant_expression (ctx, cond, false, + cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (cond); *jump_target = cond; @@ -6332,7 +6359,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, constexpr_ctx new_ctx = *ctx; constexpr_switch_state css = css_default_not_seen; new_ctx.css_state = &css; - cxx_eval_constant_expression (&new_ctx, body, false, + cxx_eval_constant_expression (&new_ctx, body, vc_discard, non_constant_p, overflow_p, jump_target); if (switches (jump_target) && css == css_default_seen) { @@ -6340,7 +6367,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, this time instructing label_matches to return true for default: label on switches (jump_target). */ css = css_default_processing; - cxx_eval_constant_expression (&new_ctx, body, false, + cxx_eval_constant_expression (&new_ctx, body, vc_discard, non_constant_p, overflow_p, jump_target); } if (breaks (jump_target) || switches (jump_target)) @@ -6351,7 +6378,7 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, /* Find the object of TYPE under initialization in CTX. */ static tree -lookup_placeholder (const constexpr_ctx *ctx, bool lval, tree type) +lookup_placeholder (const constexpr_ctx *ctx, value_cat lval, tree type) { if (!ctx) return NULL_TREE; @@ -6478,12 +6505,12 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, tree op1 = TREE_OPERAND (arg_size, 1); if (integer_zerop (op0)) arg_size - = cxx_eval_constant_expression (ctx, op1, false, non_constant_p, - overflow_p); + = cxx_eval_constant_expression (ctx, op1, vc_prvalue, + non_constant_p, overflow_p); else if (integer_zerop (op1)) arg_size - = cxx_eval_constant_expression (ctx, op0, false, non_constant_p, - overflow_p); + = cxx_eval_constant_expression (ctx, op0, vc_prvalue, + non_constant_p, overflow_p); else arg_size = NULL_TREE; } @@ -6513,7 +6540,7 @@ build_new_constexpr_heap_type (const constexpr_ctx *ctx, tree elt_type, static tree cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, - bool lval, + value_cat lval, bool *non_constant_p, bool *overflow_p, tree *jump_target /* = NULL */) { @@ -6760,8 +6787,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (tree init = DECL_INITIAL (r)) { - init = cxx_eval_constant_expression (ctx, init, - false, + init = cxx_eval_constant_expression (ctx, init, vc_prvalue, non_constant_p, overflow_p); /* Don't share a CONSTRUCTOR that might be changed. */ init = unshare_constructor (init); @@ -6821,10 +6847,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, ctx->global->values.put (new_ctx.object, new_ctx.ctor); ctx = &new_ctx; } - /* Pass false for 'lval' because this indicates + /* Pass vc_prvalue because this indicates initialization of a temporary. */ - r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), - false, + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) break; @@ -6880,7 +6905,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = *p; else { - r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false, + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), vc_prvalue, non_constant_p, overflow_p); if (*non_constant_p) break; @@ -6922,7 +6947,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, tree cleanup; /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (ctx, cleanup, false, + cxx_eval_constant_expression (ctx, cleanup, vc_discard, non_constant_p, overflow_p); } break; @@ -6933,7 +6958,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, jump_target); if (!*non_constant_p) /* Also evaluate the cleanup. */ - cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), true, + cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), vc_discard, non_constant_p, overflow_p); break; @@ -6945,7 +6970,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, { iloc_sentinel ils (loc); /* Also evaluate the cleanup. */ - cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, + cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), vc_discard, non_constant_p, overflow_p); } break; @@ -6962,8 +6987,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case ADDR_EXPR: { tree oldop = TREE_OPERAND (t, 0); - tree op = cxx_eval_constant_expression (ctx, oldop, - /*lval*/true, + tree op = cxx_eval_constant_expression (ctx, oldop, vc_glvalue, non_constant_p, overflow_p); /* Don't VERIFY_CONSTANT here. */ if (*non_constant_p) @@ -6987,7 +7011,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, non_constant_p, overflow_p); if (r == error_mark_node) ; - else if (r == TREE_OPERAND (t, 0)) + else if (r == TREE_OPERAND (t, 0) || lval == vc_discard) r = t; else r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), r); @@ -7039,8 +7063,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, else { /* Check that the LHS is constant and then discard it. */ - cxx_eval_constant_expression (ctx, op0, - true, non_constant_p, overflow_p, + cxx_eval_constant_expression (ctx, op0, vc_discard, + non_constant_p, overflow_p, jump_target); if (*non_constant_p) return t; @@ -7461,7 +7485,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case EXIT_EXPR: { tree cond = TREE_OPERAND (t, 0); - cond = cxx_eval_constant_expression (ctx, cond, /*lval*/false, + cond = cxx_eval_constant_expression (ctx, cond, vc_prvalue, non_constant_p, overflow_p); VERIFY_CONSTANT (cond); if (integer_nonzerop (cond)) @@ -7820,8 +7844,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (manifestly_const_eval) instantiate_constexpr_fns (r); - r = cxx_eval_constant_expression (&ctx, r, - false, &non_constant_p, &overflow_p); + r = cxx_eval_constant_expression (&ctx, r, vc_prvalue, + &non_constant_p, &overflow_p); if (!constexpr_dtor) verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); @@ -7832,7 +7856,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, tree cleanup; /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) - cxx_eval_constant_expression (&ctx, cleanup, false, + cxx_eval_constant_expression (&ctx, cleanup, vc_discard, &non_constant_p, &overflow_p); /* Mutable logic is a bit tricky: we want to allow initialization of @@ -8282,9 +8306,15 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, else if (CONSTANT_CLASS_P (t) && allow_non_constant) /* No evaluation needed. */; else - t = cxx_eval_outermost_constant_expr (t, allow_non_constant, - /*strict*/false, - manifestly_const_eval, false, decl); + { + /* [basic.start.static] allows constant-initialization of variables with + static or thread storage duration even if it isn't required, but we + shouldn't bend the rules the same way for automatic variables. */ + bool is_static = (decl && DECL_P (decl) + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); + t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static, + manifestly_const_eval, false, decl); + } if (TREE_CODE (t) == TARGET_EXPR) { tree init = TARGET_EXPR_INITIAL (t); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b2df6fc..d77fd1e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6647,6 +6647,7 @@ extern bool make_safe_copy_elision (tree, tree); extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warning_or_error); extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); +extern bool any_template_arguments_need_structural_equality_p (tree); /* in class.cc */ extern tree build_vfield_ref (tree, tree); @@ -7234,6 +7235,7 @@ extern void inject_this_parameter (tree, cp_cv_quals); extern location_t defparse_location (tree); extern void maybe_show_extern_c_location (void); extern bool literal_integer_zerop (const_tree); +extern tree attr_chainon (tree, tree); /* in pt.cc */ extern tree canonical_type_parameter (tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 381259c..892e4a4 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -5464,7 +5464,8 @@ shadow_tag (cp_decl_specifier_seq *declspecs) if (!t) return NULL_TREE; - if (maybe_process_partial_specialization (t) == error_mark_node) + t = maybe_process_partial_specialization (t); + if (t == error_mark_node) return NULL_TREE; /* This is where the variables in an anonymous union are @@ -5557,7 +5558,7 @@ start_decl (const cp_declarator *declarator, *pushed_scope_p = NULL_TREE; if (prefix_attributes != error_mark_node) - attributes = chainon (attributes, prefix_attributes); + attributes = attr_chainon (attributes, prefix_attributes); decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, &attributes); @@ -12728,9 +12729,10 @@ grokdeclarator (const cp_declarator *declarator, as a whole. */ late_attrs = splice_template_attributes (&attrs, type); returned_attrs = decl_attributes (&type, - chainon (returned_attrs, attrs), + attr_chainon (returned_attrs, + attrs), attr_flags); - returned_attrs = chainon (late_attrs, returned_attrs); + returned_attrs = attr_chainon (late_attrs, returned_attrs); } inner_declarator = declarator->declarator; @@ -12781,8 +12783,8 @@ grokdeclarator (const cp_declarator *declarator, The optional attribute-specifier-seq appertains to the array. */ - returned_attrs = chainon (returned_attrs, - declarator->std_attributes); + returned_attrs = attr_chainon (returned_attrs, + declarator->std_attributes); break; case cdk_function: @@ -13122,9 +13124,9 @@ grokdeclarator (const cp_declarator *declarator, /* transaction_safe applies to the type, but transaction_safe_dynamic applies to the function. */ if (is_attribute_p ("transaction_safe", tx_qual)) - attrs = chainon (attrs, att); + attrs = attr_chainon (attrs, att); else - returned_attrs = chainon (returned_attrs, att); + returned_attrs = attr_chainon (returned_attrs, att); } if (attrs) /* [dcl.fct]/2: @@ -13438,7 +13440,7 @@ grokdeclarator (const cp_declarator *declarator, if (returned_attrs) { if (attrlist) - *attrlist = chainon (returned_attrs, *attrlist); + *attrlist = attr_chainon (returned_attrs, *attrlist); else attrlist = &returned_attrs; } @@ -13451,7 +13453,7 @@ grokdeclarator (const cp_declarator *declarator, /* [dcl.meaning]/1: The optional attribute-specifier-seq following a declarator-id appertains to the entity that is declared. */ if (declarator->std_attributes != error_mark_node) - *attrlist = chainon (*attrlist, declarator->std_attributes); + *attrlist = attr_chainon (*attrlist, declarator->std_attributes); else /* We should have already diagnosed the issue (c++/78344). */ gcc_assert (seen_error ()); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index ae743c8..e72fdf0 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -5799,10 +5799,15 @@ mark_used (tree decl, tsubst_flags_t complain) actually used until after overload resolution. */ if (BASELINK_P (decl)) { - decl = BASELINK_FUNCTIONS (decl); - if (really_overloaded_fn (decl)) + tree fns = BASELINK_FUNCTIONS (decl); + if (really_overloaded_fn (fns)) return true; - decl = OVL_FIRST (decl); + fns = OVL_FIRST (fns); + if (!mark_used (fns, complain)) + return false; + /* We might have deduced its return type. */ + TREE_TYPE (decl) = TREE_TYPE (fns); + return true; } if (!DECL_P (decl)) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 24585c1..b3a6c9a 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -12557,7 +12557,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Append ATTR to attribute list ATTRS. */ -static tree +tree attr_chainon (tree attrs, tree attr) { if (attrs == error_mark_node) @@ -31811,12 +31811,6 @@ cp_parser_single_declaration (cp_parser* parser, if (cp_parser_declares_only_class_p (parser) || (declares_class_or_enum & 2)) { - /* If this is a declaration, but not a definition, associate - any constraints with the type declaration. Constraints - are associated with definitions in cp_parser_class_specifier. */ - if (declares_class_or_enum == 1) - associate_classtype_constraints (decl_specifiers.type); - decl = shadow_tag (&decl_specifiers); /* In this case: @@ -31838,6 +31832,12 @@ cp_parser_single_declaration (cp_parser* parser, else decl = error_mark_node; + /* If this is a declaration, but not a definition, associate + any constraints with the type declaration. Constraints + are associated with definitions in cp_parser_class_specifier. */ + if (declares_class_or_enum == 1) + associate_classtype_constraints (TREE_TYPE (decl)); + /* Perform access checks for template parameters. */ cp_parser_perform_template_parameter_access_checks (checks); @@ -33666,7 +33666,8 @@ class_decl_loc_t::add (cp_parser *parser, location_t key_loc, bool key_redundant = (!def_p && !decl_p && (decl == type_decl || TREE_CODE (decl) == TEMPLATE_DECL - || TYPE_BEING_DEFINED (type))); + || (CLASS_TYPE_P (type) + && TYPE_BEING_DEFINED (type)))); if (key_redundant && class_key != class_type @@ -33704,7 +33705,7 @@ class_decl_loc_t::add (cp_parser *parser, location_t key_loc, } else { - /* TYPE was previously defined in some unknown precompiled hdeader. + /* TYPE was previously defined in some unknown precompiled header. Simply add a record of its definition at an unknown location and proceed below to add a reference to it at the current location. (Declarations in precompiled headers that are not definitions @@ -36498,6 +36499,10 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("dist_schedule", p)) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; + case 'e': + if (!strcmp ("enter", p)) + result = PRAGMA_OMP_CLAUSE_ENTER; + break; case 'f': if (!strcmp ("filter", p)) result = PRAGMA_OMP_CLAUSE_FILTER; @@ -40418,8 +40423,13 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, break; case PRAGMA_OMP_CLAUSE_TO: if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, - clauses); + { + tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ENTER, + clauses); + for (tree c = nl; c != clauses; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ENTER_TO (c) = 1; + clauses = nl; + } else clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses, true); @@ -40526,6 +40536,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses, token->location); c_name = "simd"; break; + case PRAGMA_OMP_CLAUSE_ENTER: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_ENTER, + clauses); + c_name = "enter"; + break; default: cp_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -43793,7 +43808,8 @@ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) # pragma omp taskwait taskwait-clause[opt] new-line */ #define OMP_TASKWAIT_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static void cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok) @@ -45976,9 +45992,14 @@ handle_omp_declare_target_clause (tree c, tree t, int device_type) id = get_identifier ("omp declare target"); if (at2) { - error_at (OMP_CLAUSE_LOCATION (c), - "%qD specified both in declare target %<link%> and %<to%>" - " clauses", t); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target %<link%> and %qs" + " clauses", t, OMP_CLAUSE_ENTER_TO (c) ? "to" : "enter"); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target %<link%> and " + "%<to%> or %<enter%> clauses", t); return false; } if (!at1) @@ -46036,6 +46057,7 @@ handle_omp_declare_target_clause (tree c, tree t, int device_type) #define OMP_DECLARE_TARGET_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ENTER) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE)) @@ -46055,7 +46077,7 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) "#pragma omp declare target", pragma_tok); else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_ENTER, clauses); clauses = finish_omp_clauses (clauses, C_ORT_OMP); cp_parser_require_pragma_eol (parser, pragma_tok); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 5037627..f1f0805 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -203,7 +203,6 @@ static tree copy_default_args_to_explicit_spec_1 (tree, tree); static void copy_default_args_to_explicit_spec (tree); static bool invalid_nontype_parm_type_p (tree, tsubst_flags_t); static bool dependent_template_arg_p (tree); -static bool any_template_arguments_need_structural_equality_p (tree); static bool dependent_type_p_r (tree); static tree tsubst_copy (tree, tree, tsubst_flags_t, tree); static tree tsubst_decl (tree, tree, tsubst_flags_t); @@ -875,12 +874,12 @@ check_explicit_instantiation_namespace (tree spec) spec, current_namespace, ns); } -/* Returns the type of a template specialization only if that - specialization needs to be defined. Otherwise (e.g., if the type has - already been defined), the function returns NULL_TREE. */ +/* Returns true if TYPE is a new partial specialization that needs to be + set up. This may also modify TYPE to point to the correct (new or + existing) constrained partial specialization. */ -static tree -maybe_new_partial_specialization (tree type) +static bool +maybe_new_partial_specialization (tree& type) { /* An implicit instantiation of an incomplete type implies the definition of a new class template. @@ -894,7 +893,7 @@ maybe_new_partial_specialization (tree type) Here, S<T*> is an implicit instantiation of S whose type is incomplete. */ if (CLASSTYPE_IMPLICIT_INSTANTIATION (type) && !COMPLETE_TYPE_P (type)) - return type; + return true; /* It can also be the case that TYPE is a completed specialization. Continuing the previous example, suppose we also declare: @@ -920,11 +919,11 @@ maybe_new_partial_specialization (tree type) /* If there are no template parameters, this cannot be a new partial template specialization? */ if (!current_template_parms) - return NULL_TREE; + return false; /* The injected-class-name is not a new partial specialization. */ if (DECL_SELF_REFERENCE_P (TYPE_NAME (type))) - return NULL_TREE; + return false; /* If the constraints are not the same as those of the primary then, we can probably create a new specialization. */ @@ -934,7 +933,7 @@ maybe_new_partial_specialization (tree type) { tree main_constr = get_constraints (tmpl); if (equivalent_constraints (type_constr, main_constr)) - return NULL_TREE; + return false; } /* Also, if there's a pre-existing specialization with matching @@ -947,7 +946,10 @@ maybe_new_partial_specialization (tree type) tree spec_constr = get_constraints (spec_tmpl); if (comp_template_args (args, spec_args) && equivalent_constraints (type_constr, spec_constr)) - return NULL_TREE; + { + type = TREE_TYPE (spec_tmpl); + return false; + } specs = TREE_CHAIN (specs); } @@ -972,10 +974,11 @@ maybe_new_partial_specialization (tree type) set_instantiating_module (d); DECL_MODULE_EXPORT_P (d) = DECL_MODULE_EXPORT_P (tmpl); - return t; + type = t; + return true; } - return NULL_TREE; + return false; } /* The TYPE is being declared. If it is a template type, that means it @@ -1031,16 +1034,16 @@ maybe_process_partial_specialization (tree type) Make sure that `C<int>' and `C<T*>' are implicit instantiations. */ - if (tree t = maybe_new_partial_specialization (type)) + if (maybe_new_partial_specialization (type)) { - if (!check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (t)) + if (!check_specialization_namespace (CLASSTYPE_TI_TEMPLATE (type)) && !at_namespace_scope_p ()) return error_mark_node; - SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t); - DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (t)) = input_location; + SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (type); + DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)) = input_location; if (processing_template_decl) { - tree decl = push_template_decl (TYPE_MAIN_DECL (t)); + tree decl = push_template_decl (TYPE_MAIN_DECL (type)); if (decl == error_mark_node) return error_mark_node; return TREE_TYPE (decl); @@ -4526,6 +4529,27 @@ build_template_parm_index (int index, return t; } +struct ctp_hasher : ggc_ptr_hash<tree_node> +{ + static hashval_t hash (tree t) + { + tree_code code = TREE_CODE (t); + 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) == BOUND_TEMPLATE_TEMPLATE_PARM) + val = iterative_hash_template_arg (TYPE_TI_ARGS (t), val); + return val; + } + + static bool equal (tree t, tree u) + { + return comptypes (t, u, COMPARE_STRUCTURAL); + } +}; + +static GTY (()) hash_table<ctp_hasher> *ctp_table; + /* Find the canonical type parameter for the given template type parameter. Returns the canonical type parameter, which may be TYPE if no such parameter existed. */ @@ -4533,21 +4557,13 @@ build_template_parm_index (int index, tree canonical_type_parameter (tree type) { - int idx = TEMPLATE_TYPE_IDX (type); - - gcc_assert (TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM); - - if (vec_safe_length (canonical_template_parms) <= (unsigned) idx) - vec_safe_grow_cleared (canonical_template_parms, idx + 1, true); + if (ctp_table == NULL) + ctp_table = hash_table<ctp_hasher>::create_ggc (61); - for (tree list = (*canonical_template_parms)[idx]; - list; list = TREE_CHAIN (list)) - if (comptypes (type, TREE_VALUE (list), COMPARE_STRUCTURAL)) - return TREE_VALUE (list); - - (*canonical_template_parms)[idx] - = tree_cons (NULL_TREE, type, (*canonical_template_parms)[idx]); - return type; + tree& slot = *ctp_table->find_slot (type, INSERT); + if (slot == NULL_TREE) + slot = type; + return slot; } /* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose @@ -4720,10 +4736,7 @@ process_template_parm (tree list, location_t parm_loc, tree parm, current_template_depth, decl, TREE_TYPE (parm)); TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack; - if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM) - SET_TYPE_STRUCTURAL_EQUALITY (t); - else - TYPE_CANONICAL (t) = canonical_type_parameter (t); + TYPE_CANONICAL (t) = canonical_type_parameter (t); } DECL_ARTIFICIAL (decl) = 1; SET_DECL_TEMPLATE_PARM_P (decl); @@ -5012,6 +5025,8 @@ maybe_update_decl_type (tree orig_type, tree scope) static tree build_template_decl (tree decl, tree parms, bool member_template_p) { + gcc_checking_assert (TREE_CODE (decl) != TEMPLATE_DECL); + tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE); SET_DECL_LANGUAGE (tmpl, DECL_LANGUAGE (decl)); DECL_TEMPLATE_PARMS (tmpl) = parms; @@ -10131,9 +10146,6 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, appropriately. */ TYPE_CANONICAL (t) = template_type; else if (any_template_arguments_need_structural_equality_p (arglist)) - /* Some of the template arguments require structural - equality testing, so this template class requires - structural equality testing. */ SET_TYPE_STRUCTURAL_EQUALITY (t); } else @@ -14068,7 +14080,9 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, { hash = hash_tmpl_and_args (gen_tmpl, argvec); if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash)) - return spec; + /* The spec for these args might be a partial instantiation of the + template, but here what we want is the FUNCTION_DECL. */ + return STRIP_TEMPLATE (spec); } } else @@ -15908,20 +15922,6 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) only instantiated during satisfaction. */ PLACEHOLDER_TYPE_CONSTRAINTS_INFO (r) = ci; - if (TREE_CODE (r) == TEMPLATE_TEMPLATE_PARM) - /* We have reduced the level of the template - template parameter, but not the levels of its - template parameters, so canonical_type_parameter - will not be able to find the canonical template - template parameter for this level. Thus, we - require structural equality checking to compare - TEMPLATE_TEMPLATE_PARMs. */ - SET_TYPE_STRUCTURAL_EQUALITY (r); - else if (TYPE_STRUCTURAL_EQUALITY_P (t)) - SET_TYPE_STRUCTURAL_EQUALITY (r); - else - TYPE_CANONICAL (r) = canonical_type_parameter (r); - if (code == BOUND_TEMPLATE_TEMPLATE_PARM) { tree tinfo = TYPE_TEMPLATE_INFO (t); @@ -15939,6 +15939,11 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec); } + + if (TYPE_STRUCTURAL_EQUALITY_P (t)) + SET_TYPE_STRUCTURAL_EQUALITY (r); + else + TYPE_CANONICAL (r) = canonical_type_parameter (r); } break; @@ -19735,11 +19740,18 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) return error_mark_node; if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE) - /* A lambda in a default argument outside a class gets no - LAMBDA_EXPR_EXTRA_SCOPE, as specified by the ABI. But - tsubst_default_argument calls start_lambda_scope, so we need to - specifically ignore it here, and use the global scope. */ - record_null_lambda_scope (r); + { + /* A lambda in a default argument outside a class gets no + LAMBDA_EXPR_EXTRA_SCOPE, as specified by the ABI. But + tsubst_default_argument calls start_lambda_scope, so we need to + specifically ignore it here, and use the global scope. */ + record_null_lambda_scope (r); + + /* If we're pushed into another scope (PR105652), fix it. */ + if (TYPE_NAMESPACE_SCOPE_P (TREE_TYPE (t))) + TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_NAME (type)) + = TYPE_CONTEXT (TREE_TYPE (t)); + } else record_lambda_scope (r); @@ -22646,6 +22658,10 @@ unify_one_argument (tree tparms, tree targs, tree parm, tree arg, return unify_success (explain_p); } + /* Force auto deduction now. Use tf_none to avoid redundant + deprecated warning on deprecated-14.C. */ + mark_single_function (arg, tf_none); + arg_expr = arg; arg = unlowered_expr_type (arg); if (arg == error_mark_node) @@ -28227,8 +28243,8 @@ find_parm_usage_r (tree *tp, int *walk_subtrees, void*) return NULL_TREE; } -/* Returns true if ARGS (a collection of template arguments) contains - any types that require structural equality testing. */ +/* Returns true if a type specialization formed using the template + arguments ARGS needs to use structural equality. */ bool any_template_arguments_need_structural_equality_p (tree args) @@ -28266,10 +28282,11 @@ any_template_arguments_need_structural_equality_p (tree args) return true; else if (TREE_CODE (arg) == TEMPLATE_DECL) continue; - else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg)) - return true; - else if (!TYPE_P (arg) && TREE_TYPE (arg) - && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg))) + else if (arg == any_targ_node) + /* An any_targ_node argument (added by add_defaults_to_ttp) + makes the corresponding specialization not canonicalizable, + since template_args_equal always return true for it. We + may see this when called from bind_template_template_parm. */ return true; /* Checking current_function_decl because this structural comparison is only necessary for redeclaration. */ @@ -28277,6 +28294,16 @@ any_template_arguments_need_structural_equality_p (tree args) && dependent_template_arg_p (arg) && (cp_walk_tree_without_duplicates (&arg, find_parm_usage_r, NULL))) + /* The identity of a class template specialization that uses + a function parameter depends on the identity of the function. + And if this specialization appeared in the trailing return + type thereof, we don't know the identity of the function + (e.g. if it's a redeclaration or a new function) until we + form its signature and go through duplicate_decls. Thus + it's unsafe to decide on a canonical type now (which depends + on the DECL_CONTEXT of the function parameter, which can get + mutated after the fact by duplicate_decls), so just require + structural equality in this case (PR52830). */ return true; } } @@ -29144,10 +29171,6 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, TEMPLATE_PARM_PARAMETER_PACK (newidx) = TEMPLATE_PARM_PARAMETER_PACK (oldidx); TYPE_STUB_DECL (newtype) = TYPE_NAME (newtype) = newdecl; - if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (olddecl))) - SET_TYPE_STRUCTURAL_EQUALITY (newtype); - else - TYPE_CANONICAL (newtype) = canonical_type_parameter (newtype); if (TREE_CODE (olddecl) == TEMPLATE_DECL) { @@ -29189,6 +29212,11 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, // All done. DECL_TEMPLATE_PARMS (newdecl) = ttparms; } + + if (TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (olddecl))) + SET_TYPE_STRUCTURAL_EQUALITY (newtype); + else + TYPE_CANONICAL (newtype) = canonical_type_parameter (newtype); } else { diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cd7a281..cdc91a3 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -8341,48 +8341,50 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; - case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_ENTER: case OMP_CLAUSE_LINK: t = OMP_CLAUSE_DECL (c); + const char *cname; + cname = omp_clause_code_name[OMP_CLAUSE_CODE (c)]; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER + && OMP_CLAUSE_ENTER_TO (c)) + cname = "to"; if (TREE_CODE (t) == FUNCTION_DECL - && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) ; else if (!VAR_P (t)) { - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ENTER) { if (TREE_CODE (t) == TEMPLATE_ID_EXPR) error_at (OMP_CLAUSE_LOCATION (c), - "template %qE in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + "template %qE in clause %qs", t, cname); else if (really_overloaded_fn (t)) error_at (OMP_CLAUSE_LOCATION (c), "overloaded function name %qE in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + cname); else error_at (OMP_CLAUSE_LOCATION (c), "%qE is neither a variable nor a function name " - "in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + "in clause %qs", t, cname); } else error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + "%qE is not a variable in clause %qs", t, cname); remove = true; } else if (DECL_THREAD_LOCAL_P (t)) { error_at (OMP_CLAUSE_LOCATION (c), "%qD is threadprivate variable in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + cname); remove = true; } else if (!cp_omp_mappable_type (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), "%qD does not have a mappable type in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + cname); cp_omp_emit_unmappable_type_notes (TREE_TYPE (t)); remove = true; } diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index bc38c8f..0916279 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2901,7 +2901,11 @@ bind_template_template_parm (tree t, tree newargs) TYPE_NAME (t2) = decl; TYPE_STUB_DECL (t2) = decl; TYPE_SIZE (t2) = 0; - SET_TYPE_STRUCTURAL_EQUALITY (t2); + + if (any_template_arguments_need_structural_equality_p (newargs)) + SET_TYPE_STRUCTURAL_EQUALITY (t2); + else + TYPE_CANONICAL (t2) = canonical_type_parameter (t2); return t2; } diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 6ecdd97..190d710 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -1511,8 +1511,10 @@ structural_comptypes (tree t1, tree t2, int strict) substitute into the specialization arguments at instantiation time. And aliases can't be equivalent without being ==, so we don't need to look any deeper. */ + ++processing_template_decl; tree dep1 = dependent_alias_template_spec_p (t1, nt_transparent); tree dep2 = dependent_alias_template_spec_p (t2, nt_transparent); + --processing_template_decl; if ((dep1 || dep2) && dep1 != dep2) return false; } @@ -4755,8 +4757,16 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain) tree off = TREE_OPERAND (cop, 1); if (!integer_zerop (off) && !warning_suppressed_p (cop, OPT_Waddress)) - warning_at (location, OPT_Waddress, "comparing the result of pointer " - "addition %qE and NULL", cop); + { + tree base = TREE_OPERAND (cop, 0); + STRIP_NOPS (base); + if (TYPE_REF_P (TREE_TYPE (base))) + warning_at (location, OPT_Waddress, "the compiler can assume that " + "the address of %qE will never be NULL", base); + else + warning_at (location, OPT_Waddress, "comparing the result of " + "pointer addition %qE and NULL", cop); + } return; } else if (CONVERT_EXPR_P (op) diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 1d92310..1a96be3 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -1371,6 +1371,71 @@ digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain) return digest_init_r (type, init, 0, flags, complain); } +/* Return true if SUBOB initializes the same object as FULL_EXPR. + For instance: + + A a = A{}; // initializer + A a = (A{}); // initializer + A a = (1, A{}); // initializer + A a = true ? A{} : A{}; // initializer + auto x = A{}.x; // temporary materialization + auto x = foo(A{}); // temporary materialization + + FULL_EXPR is the whole expression, SUBOB is its TARGET_EXPR subobject. */ + +static bool +potential_prvalue_result_of (tree subob, tree full_expr) +{ + if (subob == full_expr) + return true; + else if (TREE_CODE (full_expr) == TARGET_EXPR) + { + tree init = TARGET_EXPR_INITIAL (full_expr); + if (TREE_CODE (init) == COND_EXPR) + return (potential_prvalue_result_of (subob, TREE_OPERAND (init, 1)) + || potential_prvalue_result_of (subob, TREE_OPERAND (init, 2))); + else if (TREE_CODE (init) == COMPOUND_EXPR) + return potential_prvalue_result_of (subob, TREE_OPERAND (init, 1)); + /* ??? I don't know if this can be hit. */ + else if (TREE_CODE (init) == PAREN_EXPR) + { + gcc_checking_assert (false); + return potential_prvalue_result_of (subob, TREE_OPERAND (init, 0)); + } + } + return false; +} + +/* Callback to replace PLACEHOLDER_EXPRs in a TARGET_EXPR (which isn't used + in the context of guaranteed copy elision). */ + +static tree +replace_placeholders_for_class_temp_r (tree *tp, int *, void *data) +{ + tree t = *tp; + tree full_expr = *static_cast<tree *>(data); + + /* We're looking for a TARGET_EXPR nested in the whole expression. */ + if (TREE_CODE (t) == TARGET_EXPR + && !potential_prvalue_result_of (t, full_expr)) + { + tree init = TARGET_EXPR_INITIAL (t); + while (TREE_CODE (init) == COMPOUND_EXPR) + init = TREE_OPERAND (init, 1); + if (TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init)) + { + tree obj = TARGET_EXPR_SLOT (t); + replace_placeholders (init, obj); + /* We should have dealt with all PLACEHOLDER_EXPRs. */ + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = false; + gcc_checking_assert (!find_placeholders (init)); + } + } + + return NULL_TREE; +} + /* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL). */ tree digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) @@ -1390,6 +1455,32 @@ digest_nsdmi_init (tree decl, tree init, tsubst_flags_t complain) && CP_AGGREGATE_TYPE_P (type)) init = reshape_init (type, init, complain); init = digest_init_flags (type, init, flags, complain); + + /* We may have temporary materialization in a NSDMI, if the initializer + has something like A{} in it. Digesting the {} could have introduced + a PLACEHOLDER_EXPR referring to A. Now that we've got a TARGET_EXPR, + we have an object we can refer to. The reason we bother doing this + here is for code like + + struct A { + int x; + int y = x; + }; + + struct B { + int x = 0; + int y = A{x}.y; // #1 + }; + + where in #1 we don't want to end up with two PLACEHOLDER_EXPRs for + different types on the same level in a {} when lookup_placeholder + wouldn't find a named object for the PLACEHOLDER_EXPR for A. Note, + temporary materialization does not occur when initializing an object + from a prvalue of the same type, therefore we must not replace the + placeholder with a temporary object so that it can be elided. */ + cp_walk_tree (&init, replace_placeholders_for_class_temp_r, &init, + nullptr); + return init; } diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index d3ac0bc..a629a4d 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,26 @@ +2022-05-27 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd 4d07f22f2 + * d-lang.cc (d_handle_option): Handle OPT_fpreview_fiximmutableconv. + * lang.opt (fpreview=fiximmutableconv): New option. + * runtime.def (ARRAYAPPENDT): Remove. + +2022-05-25 Iain Buclaw <ibuclaw@gdcproject.org> + + * expr.cc: Add "final" and "override" to all "visit" vfunc decls + as appropriate. + * imports.cc: Likewise. + * typeinfo.cc: Likewise. + +2022-05-24 David Malcolm <dmalcolm@redhat.com> + + * decl.cc: Add "final" and "override" to all "visit" vfunc decls + as appropriate. + * expr.cc: Likewise. + * toir.cc: Likewise. + * typeinfo.cc: Likewise. + * types.cc: Likewise. + 2022-05-16 Iain Buclaw <ibuclaw@gdcproject.org> * dmd/MERGE: Merge upstream dmd 60bfa0ee7. diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index d1f4959..ef0fe0b 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -581,6 +581,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.rvalueRefParam = FeatureState::enabled; global.params.inclusiveInContracts = value; global.params.shortenedMethods = value; + global.params.fixImmutableConv = value; break; case OPT_fpreview_bitfields: @@ -615,6 +616,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.fixAliasThis = value; break; + case OPT_fpreview_fiximmutableconv: + global.params.fixImmutableConv = value; + break; + case OPT_fpreview_in: global.params.previewIn = value; break; diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index f5c2107..5d85006 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -149,13 +149,13 @@ public: /* This should be overridden by each declaration class. */ - void visit (Dsymbol *) + void visit (Dsymbol *) final override { } /* Compile a D module, and all members of it. */ - void visit (Module *d) + void visit (Module *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -166,7 +166,7 @@ public: /* Write the imported symbol to debug. */ - void visit (Import *d) + void visit (Import *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -218,7 +218,7 @@ public: /* Expand any local variables found in tuples. */ - void visit (TupleDeclaration *d) + void visit (TupleDeclaration *d) final override { for (size_t i = 0; i < d->objects->length; i++) { @@ -234,7 +234,7 @@ public: /* Walk over all declarations in the attribute scope. */ - void visit (AttribDeclaration *d) + void visit (AttribDeclaration *d) final override { Dsymbols *ds = d->include (NULL); @@ -248,7 +248,7 @@ public: /* Pragmas are a way to pass special information to the compiler and to add vendor specific extensions to D. */ - void visit (PragmaDeclaration *d) + void visit (PragmaDeclaration *d) final override { if (d->ident == Identifier::idPool ("lib") || d->ident == Identifier::idPool ("startaddress")) @@ -266,7 +266,7 @@ public: /* Conditional compilation is the process of selecting which code to compile and which code to not compile. Look for version conditions that may */ - void visit (ConditionalDeclaration *d) + void visit (ConditionalDeclaration *d) final override { bool old_condition = this->in_version_unittest_; @@ -284,7 +284,7 @@ public: /* Walk over all members in the namespace scope. */ - void visit (Nspace *d) + void visit (Nspace *d) final override { if (isError (d) || !d->members) return; @@ -298,7 +298,7 @@ public: voldemort type, then it's members must be compiled before the parent function finishes. */ - void visit (TemplateDeclaration *d) + void visit (TemplateDeclaration *d) final override { /* Type cannot be directly named outside of the scope it's declared in, so the only way it can be escaped is if the function has auto return. */ @@ -329,7 +329,7 @@ public: /* Walk over all members in the instantiated template. */ - void visit (TemplateInstance *d) + void visit (TemplateInstance *d) final override { if (isError (d)|| !d->members) return; @@ -343,7 +343,7 @@ public: /* Walk over all members in the mixin template scope. */ - void visit (TemplateMixin *d) + void visit (TemplateMixin *d) final override { if (isError (d)|| !d->members) return; @@ -355,7 +355,7 @@ public: /* Write out compiler generated TypeInfo, initializer and functions for the given struct declaration, walking over all static members. */ - void visit (StructDeclaration *d) + void visit (StructDeclaration *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -470,7 +470,7 @@ public: /* Write out compiler generated TypeInfo, initializer and vtables for the given class declaration, walking over all static members. */ - void visit (ClassDeclaration *d) + void visit (ClassDeclaration *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -544,7 +544,7 @@ public: /* Write out compiler generated TypeInfo and vtables for the given interface declaration, walking over all static members. */ - void visit (InterfaceDeclaration *d) + void visit (InterfaceDeclaration *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -587,7 +587,7 @@ public: /* Write out compiler generated TypeInfo and initializer for the given enum declaration. */ - void visit (EnumDeclaration *d) + void visit (EnumDeclaration *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -626,7 +626,7 @@ public: /* Finish up a variable declaration and push it into the current scope. This can either be a static, local or manifest constant. */ - void visit (VarDeclaration *d) + void visit (VarDeclaration *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -753,7 +753,7 @@ public: /* Generate and compile a static TypeInfo declaration, but only if it is needed in the current compilation. */ - void visit (TypeInfoDeclaration *d) + void visit (TypeInfoDeclaration *d) final override { if (d->semanticRun >= PASS::obj) return; @@ -770,7 +770,7 @@ public: /* Finish up a function declaration and compile it all the way down to assembler language output. */ - void visit (FuncDeclaration *d) + void visit (FuncDeclaration *d) final override { /* Already generated the function. */ if (d->semanticRun >= PASS::obj) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index b4d42ec..c37da05 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -a6c5224b2d6b61fa3856aa8a3369581f7c949b68 +4d07f22f29d098869ad937f0499d8895df089a71 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/aggregate.h b/gcc/d/dmd/aggregate.h index bdeb38e..f27ca07 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -120,20 +120,20 @@ public: Sizeok sizeok; // set when structsize contains valid data virtual Scope *newScope(Scope *sc); - void setScope(Scope *sc); + void setScope(Scope *sc) override final; size_t nonHiddenFields(); bool determineSize(const Loc &loc); virtual void finalizeSize() = 0; - uinteger_t size(const Loc &loc); + uinteger_t size(const Loc &loc) override final; bool fill(const Loc &loc, Expressions *elements, bool ctorinit); - Type *getType(); - bool isDeprecated() const; // is aggregate deprecated? + Type *getType() override final; + bool isDeprecated() const override final; // is aggregate deprecated? void setDeprecated(); bool isNested() const; - bool isExport() const; + bool isExport() const override final; Dsymbol *searchCtor(); - Visibility visible(); + Visibility visible() override final; // 'this' type Type *handleType() { return type; } @@ -143,8 +143,8 @@ public: // Back end void *sinit; - AggregateDeclaration *isAggregateDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + AggregateDeclaration *isAggregateDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; struct StructFlags @@ -186,28 +186,28 @@ public: TypeTuple *argTypes; static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject); - StructDeclaration *syntaxCopy(Dsymbol *s); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); - const char *kind() const; - void finalizeSize(); + StructDeclaration *syntaxCopy(Dsymbol *s) override; + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; + const char *kind() const override; + void finalizeSize() override final; bool isPOD(); - StructDeclaration *isStructDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + StructDeclaration *isStructDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } unsigned numArgTypes() const; Type *argType(unsigned index); bool hasRegularCtor(bool checkDisabled = false); }; -class UnionDeclaration : public StructDeclaration +class UnionDeclaration final : public StructDeclaration { public: - UnionDeclaration *syntaxCopy(Dsymbol *s); - const char *kind() const; + UnionDeclaration *syntaxCopy(Dsymbol *s) override; + const char *kind() const override; - UnionDeclaration *isUnionDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + UnionDeclaration *isUnionDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; struct BaseClass @@ -279,9 +279,9 @@ public: Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr static ClassDeclaration *create(const Loc &loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject); - const char *toPrettyChars(bool QualifyTypes = false); - ClassDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); + const char *toPrettyChars(bool QualifyTypes = false) override; + ClassDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; bool isBaseOf2(ClassDeclaration *cd); #define OFFSET_RUNTIME 0x76543210 @@ -289,9 +289,9 @@ public: virtual bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isBaseInfoComplete(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; ClassDeclaration *searchBase(Identifier *ident); - void finalizeSize(); + void finalizeSize() override; bool hasMonitor(); bool isFuncHidden(FuncDeclaration *fd); FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); @@ -301,30 +301,30 @@ public: virtual bool isCPPinterface() const; bool isAbstract(); virtual int vtblOffset() const; - const char *kind() const; + const char *kind() const override; - void addLocalClass(ClassDeclarations *); - void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories); + void addLocalClass(ClassDeclarations *) override final; + void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories) override final; // Back end Dsymbol *vtblsym; Dsymbol *vtblSymbol(); - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } - void accept(Visitor *v) { v->visit(this); } + ClassDeclaration *isClassDeclaration() override final { return (ClassDeclaration *)this; } + void accept(Visitor *v) override { v->visit(this); } }; -class InterfaceDeclaration : public ClassDeclaration +class InterfaceDeclaration final : public ClassDeclaration { public: - InterfaceDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - bool isBaseOf(ClassDeclaration *cd, int *poffset); - const char *kind() const; - int vtblOffset() const; - bool isCPPinterface() const; - bool isCOMinterface() const; - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + InterfaceDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + bool isBaseOf(ClassDeclaration *cd, int *poffset) override; + const char *kind() const override; + int vtblOffset() const override; + bool isCPPinterface() const override; + bool isCOMinterface() const override; + + InterfaceDeclaration *isInterfaceDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h index 3b67903..c63d717 100644 --- a/gcc/d/dmd/aliasthis.h +++ b/gcc/d/dmd/aliasthis.h @@ -15,7 +15,7 @@ /**************************************************************/ -class AliasThis : public Dsymbol +class AliasThis final : public Dsymbol { public: // alias Identifier this; @@ -23,9 +23,9 @@ public: Dsymbol *sym; bool isDeprecated_; - AliasThis *syntaxCopy(Dsymbol *); - const char *kind() const; + AliasThis *syntaxCopy(Dsymbol *) override; + const char *kind() const override; AliasThis *isAliasThis() { return this; } - void accept(Visitor *v) { v->visit(this); } - bool isDeprecated() const { return this->isDeprecated_; } + void accept(Visitor *v) override { v->visit(this); } + bool isDeprecated() const override { return this->isDeprecated_; } }; diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 812729b..1fe33a6 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -26,20 +26,20 @@ public: virtual Dsymbols *include(Scope *sc); virtual Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - void importAll(Scope *sc); - void addComment(const utf8_t *comment); - const char *kind() const; - bool oneMember(Dsymbol **ps, Identifier *ident); - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); - bool hasPointers(); - bool hasStaticCtorOrDtor(); - void checkCtorConstInit(); - void addLocalClass(ClassDeclarations *); - AttribDeclaration *isAttribDeclaration() { return this; } - - void accept(Visitor *v) { v->visit(this); } + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void setScope(Scope *sc) override; + 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 hasPointers() override final; + bool hasStaticCtorOrDtor() override final; + void checkCtorConstInit() override final; + void addLocalClass(ClassDeclarations *) override final; + AttribDeclaration *isAttribDeclaration() override final { return this; } + + void accept(Visitor *v) override { v->visit(this); } }; class StorageClassDeclaration : public AttribDeclaration @@ -47,90 +47,90 @@ class StorageClassDeclaration : public AttribDeclaration public: StorageClass stc; - StorageClassDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - bool oneMember(Dsymbol **ps, Identifier *ident); - void addMember(Scope *sc, ScopeDsymbol *sds); - StorageClassDeclaration *isStorageClassDeclaration() { return this; } + StorageClassDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + bool oneMember(Dsymbol **ps, Identifier *ident) override final; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + StorageClassDeclaration *isStorageClassDeclaration() override { return this; } - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DeprecatedDeclaration : public StorageClassDeclaration +class DeprecatedDeclaration final : public StorageClassDeclaration { public: Expression *msg; const char *msgstr; - DeprecatedDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void setScope(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + void setScope(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class LinkDeclaration : public AttribDeclaration +class LinkDeclaration final : public AttribDeclaration { public: LINK linkage; static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl); - LinkDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - const char *toChars() const; - void accept(Visitor *v) { v->visit(this); } + LinkDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + const char *toChars() const override; + void accept(Visitor *v) override { v->visit(this); } }; -class CPPMangleDeclaration : public AttribDeclaration +class CPPMangleDeclaration final : public AttribDeclaration { public: CPPMANGLE cppmangle; - CPPMangleDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void setScope(Scope *sc); - const char *toChars() const; - void accept(Visitor *v) { v->visit(this); } + CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + void setScope(Scope *sc) override; + const char *toChars() const override; + void accept(Visitor *v) override { v->visit(this); } }; -class CPPNamespaceDeclaration : public AttribDeclaration +class CPPNamespaceDeclaration final : public AttribDeclaration { public: Expression *exp; - CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - const char *toChars() const; - void accept(Visitor *v) { v->visit(this); } + CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + const char *toChars() const override; + void accept(Visitor *v) override { v->visit(this); } }; -class VisibilityDeclaration : public AttribDeclaration +class VisibilityDeclaration final : public AttribDeclaration { public: Visibility visibility; DArray<Identifier*> pkg_identifiers; - VisibilityDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind() const; - const char *toPrettyChars(bool unused); - VisibilityDeclaration *isVisibilityDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + VisibilityDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + const char *kind() const override; + const char *toPrettyChars(bool unused) override; + VisibilityDeclaration *isVisibilityDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class AlignDeclaration : public AttribDeclaration +class AlignDeclaration final : public AttribDeclaration { public: Expressions *alignExps; structalign_t salign; AlignDeclaration(const Loc &loc, Expression *ealign, Dsymbols *decl); - AlignDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + AlignDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class AnonDeclaration : public AttribDeclaration +class AnonDeclaration final : public AttribDeclaration { public: bool isunion; @@ -139,24 +139,24 @@ public: unsigned anonstructsize; // size of anonymous struct unsigned anonalignsize; // size of anonymous struct for alignment purposes - AnonDeclaration *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); - const char *kind() const; - AnonDeclaration *isAnonDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + AnonDeclaration *syntaxCopy(Dsymbol *s) override; + void setScope(Scope *sc) 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); } }; -class PragmaDeclaration : public AttribDeclaration +class PragmaDeclaration final : public AttribDeclaration { public: Expressions *args; // array of Expression's - PragmaDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); + PragmaDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; PINLINE evalPragmaInline(Scope* sc); - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } + const char *kind() const override; + void accept(Visitor *v) override { v->visit(this); } }; class ConditionalDeclaration : public AttribDeclaration @@ -165,31 +165,31 @@ public: Condition *condition; Dsymbols *elsedecl; // array of Dsymbol's for else block - ConditionalDeclaration *syntaxCopy(Dsymbol *s); - bool oneMember(Dsymbol **ps, Identifier *ident); - Dsymbols *include(Scope *sc); - void addComment(const utf8_t *comment); - void setScope(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + ConditionalDeclaration *syntaxCopy(Dsymbol *s) override; + bool oneMember(Dsymbol **ps, Identifier *ident) override final; + Dsymbols *include(Scope *sc) override; + void addComment(const utf8_t *comment) override final; + void setScope(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class StaticIfDeclaration : public ConditionalDeclaration +class StaticIfDeclaration final : public ConditionalDeclaration { public: ScopeDsymbol *scopesym; bool addisdone; bool onStack; - StaticIfDeclaration *syntaxCopy(Dsymbol *s); - Dsymbols *include(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - void importAll(Scope *sc); - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } + StaticIfDeclaration *syntaxCopy(Dsymbol *s) override; + Dsymbols *include(Scope *sc) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void setScope(Scope *sc) override; + void importAll(Scope *sc) override; + const char *kind() const override; + void accept(Visitor *v) override { v->visit(this); } }; -class StaticForeachDeclaration : public AttribDeclaration +class StaticForeachDeclaration final : public AttribDeclaration { public: StaticForeach *sfe; @@ -198,31 +198,31 @@ public: bool cached; Dsymbols *cache; - StaticForeachDeclaration *syntaxCopy(Dsymbol *s); - bool oneMember(Dsymbol **ps, Identifier *ident); - Dsymbols *include(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - void addComment(const utf8_t *comment); - void setScope(Scope *sc); - void importAll(Scope *sc); - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } + StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; + bool oneMember(Dsymbol **ps, Identifier *ident) override; + Dsymbols *include(Scope *sc) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void addComment(const utf8_t *comment) override; + void setScope(Scope *sc) override; + void importAll(Scope *sc) override; + const char *kind() const override; + void accept(Visitor *v) override { v->visit(this); } }; -class ForwardingAttribDeclaration : public AttribDeclaration +class ForwardingAttribDeclaration final : public AttribDeclaration { public: ForwardingScopeDsymbol *sym; - Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds); - ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + Scope *newScope(Scope *sc) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; // Mixin declarations -class CompileDeclaration : public AttribDeclaration +class CompileDeclaration final : public AttribDeclaration { public: Expressions *exps; @@ -230,26 +230,26 @@ public: ScopeDsymbol *scopesym; bool compiled; - CompileDeclaration *syntaxCopy(Dsymbol *s); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } + CompileDeclaration *syntaxCopy(Dsymbol *s) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void setScope(Scope *sc) override; + const char *kind() const override; + void accept(Visitor *v) override { v->visit(this); } }; /** * User defined attributes look like: * @(args, ...) */ -class UserAttributeDeclaration : public AttribDeclaration +class UserAttributeDeclaration final : public AttribDeclaration { public: Expressions *atts; - UserAttributeDeclaration *syntaxCopy(Dsymbol *s); - Scope *newScope(Scope *sc); - void setScope(Scope *sc); + UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override; + Scope *newScope(Scope *sc) override; + void setScope(Scope *sc) override; Expressions *getAttributes(); - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } + const char *kind() const override; + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h index d69c13e..b33f288 100644 --- a/gcc/d/dmd/cond.h +++ b/gcc/d/dmd/cond.h @@ -35,14 +35,16 @@ public: Loc loc; Include inc; + DYNCAST dyncast() const override final { return DYNCAST_CONDITION; } + virtual Condition *syntaxCopy() = 0; virtual int include(Scope *sc) = 0; virtual DebugCondition *isDebugCondition() { return NULL; } virtual VersionCondition *isVersionCondition() { return NULL; } - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class StaticForeach +class StaticForeach final : public RootObject { public: Loc loc; @@ -62,37 +64,37 @@ public: Identifier *ident; Module *mod; - DVCondition *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + DVCondition *syntaxCopy() override final; + void accept(Visitor *v) override { v->visit(this); } }; -class DebugCondition : public DVCondition +class DebugCondition final : public DVCondition { public: static void addGlobalIdent(const char *ident); - int include(Scope *sc); - DebugCondition *isDebugCondition() { return this; } - void accept(Visitor *v) { v->visit(this); } + int include(Scope *sc) override; + DebugCondition *isDebugCondition() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class VersionCondition : public DVCondition +class VersionCondition final : public DVCondition { public: static void addGlobalIdent(const char *ident); static void addPredefinedGlobalIdent(const char *ident); - int include(Scope *sc); - VersionCondition *isVersionCondition() { return this; } - void accept(Visitor *v) { v->visit(this); } + int include(Scope *sc) override; + VersionCondition *isVersionCondition() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class StaticIfCondition : public Condition +class StaticIfCondition final : public Condition { public: Expression *exp; - StaticIfCondition *syntaxCopy(); - int include(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + StaticIfCondition *syntaxCopy() override; + int include(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index fde0648..344933a 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -59,8 +59,16 @@ final class CParser(AST) : Parser!AST */ Array!(void*) typedefTab; /// Array of AST.Type[Identifier], typedef's indexed by Identifier + /* This is passed in as a list of #define lines, as generated by the C preprocessor with the + * appropriate switch to emit them. We append to it any #define's and #undef's encountered in the source + * file, as cpp with the -dD embeds them in the preprocessed output file. + * Once the file is parsed, then the #define's are converted to D symbols and appended to the array + * of Dsymbols returned by parseModule(). + */ + OutBuffer* defines; + extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, - const ref TARGET target) + const ref TARGET target, OutBuffer* defines) { super(_module, input, doDocComment); @@ -69,6 +77,7 @@ final class CParser(AST) : Parser!AST linkage = LINK.c; Ccompile = true; this.packalign.setDefault(); + this.defines = defines; // Configure sizes for C `long`, `long double`, `wchar_t`, ... this.boolsize = target.boolsize; @@ -104,6 +113,8 @@ final class CParser(AST) : Parser!AST { if (token.value == TOK.endOfFile) { + addDefines(); // convert #define's to Dsymbols + // wrap the symbols in `extern (C) { symbols }` auto wrap = new AST.Dsymbols(); auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols); @@ -976,16 +987,19 @@ final class CParser(AST) : Parser!AST // ( type-name ) e = new AST.TypeExp(loc, t); } - e = new AST.DotIdExp(loc, e, Id.__sizeof); - break; } - // must be an expression - e = cparsePrimaryExp(); - e = new AST.DotIdExp(loc, e, Id.__sizeof); - break; + else + { + // must be an expression + e = cparseUnaryExp(); + } + } + else + { + //C11 6.5.3 + e = cparseUnaryExp(); } - e = cparseUnaryExp(); e = new AST.DotIdExp(loc, e, Id.__sizeof); break; } @@ -1697,7 +1711,7 @@ final class CParser(AST) : Parser!AST while (1) { Identifier id; - AST.Expression asmname; + AST.StringExp asmName; auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier); if (!dt) { @@ -1719,7 +1733,7 @@ final class CParser(AST) : Parser!AST case TOK.asm_: case TOK.__attribute__: if (token.value == TOK.asm_) - asmname = cparseSimpleAsmExpr(); + asmName = cparseSimpleAsmExpr(); if (token.value == TOK.__attribute__) { cparseGnuAttributes(specifier); @@ -1876,14 +1890,26 @@ final class CParser(AST) : Parser!AST s = new AST.LinkDeclaration(s.loc, linkage, decls); } // Saw `asm("name")` in the function, type, or variable definition. - // This maps directly to `pragma(mangle, "name")` - if (asmname) + // This is equivalent to `pragma(mangle, "name")` in D + if (asmName) { - auto args = new AST.Expressions(1); - (*args)[0] = asmname; - auto decls = new AST.Dsymbols(1); - (*decls)[0] = s; - s = new AST.PragmaDeclaration(asmname.loc, Id.mangle, args, decls); + /* + https://issues.dlang.org/show_bug.cgi?id=23012 + Ideally this would be translated to a pragma(mangle) + decl. This is not possible because ImportC symbols are + (currently) merged before semantic analysis is performed, + so the pragma(mangle) never effects any change on the declarations + it pertains too. + + Writing to mangleOverride directly avoids this, and is possible + because C only a StringExp is allowed unlike a full fat pragma(mangle) + which is more liberal. + */ + if (auto p = s.isDeclaration()) + { + auto str = asmName.peekString(); + p.mangleOverride = str; + } } symbols.push(s); } @@ -3062,7 +3088,7 @@ final class CParser(AST) : Parser!AST * asm-string-literal: * string-literal */ - private AST.Expression cparseSimpleAsmExpr() + private AST.StringExp cparseSimpleAsmExpr() { nextToken(); // move past asm check(TOK.leftParenthesis); @@ -3070,7 +3096,7 @@ final class CParser(AST) : Parser!AST error("string literal expected"); auto label = cparsePrimaryExp(); check(TOK.rightParenthesis); - return label; + return cast(AST.StringExp) label; } /************************* @@ -4250,12 +4276,21 @@ final class CParser(AST) : Parser!AST case TOK._Bool: //case TOK._Imaginary: // ? missing in Spec case TOK._Complex: - - // typedef-name - case TOK.identifier: // will not know until semantic if typedef t = peek(t); break; + case TOK.identifier: + // Use typedef table to disambiguate + if (isTypedef(t.ident)) + { + t = peek(t); + break; + } + else + { + return false; + } + // struct-or-union-specifier // enum-specifier case TOK.struct_: @@ -4891,6 +4926,17 @@ final class CParser(AST) : Parser!AST poundLine(n, false); return true; } + else if (defines && (n.ident == Id.define || n.ident == Id.undef)) + { + /* Append this line to `defines`. + * Not canonicalizing it - assume it already is + */ + defines.writeByte('#'); + defines.writestring(n.ident.toString()); + skipToNextLine(defines); + defines.writeByte('\n'); + return true; + } else if (n.ident == Id.__pragma) { pragmaDirective(scanloc); @@ -5078,4 +5124,70 @@ final class CParser(AST) : Parser!AST } //} + + /******************************************************************************/ + /********************************* #define Parser *****************************/ + //{ + + /** + * Go through the #define's in the defines buffer and see what we can convert + * to Dsymbols, which are then appended to symbols[] + */ + void addDefines() + { + if (!defines || defines.length < 10) // minimum length of a #define line + return; + const length = defines.length; + auto slice = defines.peekChars()[0 .. length]; + resetDefineLines(slice); // reset lexer + + const(char)* endp = &slice[length - 7]; + + Token n; + + while (p < endp) + { + if (p[0 .. 7] == "#define") + { + p += 7; + scan(&n); + //printf("%s\n", n.toChars()); + if (n.value == TOK.identifier) + { + auto id = n.ident; + scan(&n); + if (n.value == TOK.endOfLine) // #define identifier + { + nextDefineLine(); + continue; + } + if (n.value == TOK.int32Literal) + { + const value = n.intvalue; + scan(&n); + if (n.value == TOK.endOfLine) + { + /* Declare manifest constant: + * enum id = value; + */ + AST.Expression e = new AST.IntegerExp(scanloc, value, AST.Type.tint32); + auto v = new AST.VarDeclaration(scanloc, AST.Type.tint32, id, new AST.ExpInitializer(scanloc, e), STC.manifest); + symbols.push(v); + nextDefineLine(); + continue; + } + } + } + skipToNextLine(); + } + else if (n.value != TOK.endOfLine) + { + skipToNextLine(); + } + nextDefineLine(); + assert(p - slice.ptr <= length); + } + } + + //} } diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h index 5979aa7..ab022ff 100644 --- a/gcc/d/dmd/ctfe.h +++ b/gcc/d/dmd/ctfe.h @@ -17,7 +17,7 @@ A reference to a class, or an interface. We need this when we point to a base class (we must record what the type is). */ -class ClassReferenceExp : public Expression +class ClassReferenceExp final : public Expression { public: StructLiteralExp *value; @@ -26,39 +26,39 @@ public: /// Return index of the field, or -1 if not found /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration int findFieldIndexByName(VarDeclaration *v); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /** An uninitialized value */ -class VoidInitExp : public Expression +class VoidInitExp final : public Expression { public: VarDeclaration *var; - const char *toChars() const; - void accept(Visitor *v) { v->visit(this); } + const char *toChars() const override; + void accept(Visitor *v) override { v->visit(this); } }; /** Fake class which holds the thrown exception. Used for implementing exception handling. */ -class ThrownExceptionExp : public Expression +class ThrownExceptionExp final : public Expression { public: ClassReferenceExp *thrown; // the thing being tossed - const char *toChars() const; - void accept(Visitor *v) { v->visit(this); } + const char *toChars() const override; + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ // This type is only used by the interpreter. -class CTFEExp : public Expression +class CTFEExp final : public Expression { public: - const char *toChars() const; + const char *toChars() const override; }; diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index c0a86f5..4607d6f 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -824,9 +824,8 @@ MATCH implicitConvTo(Expression e, Type t) * convert to immutable */ if (e.f && - // lots of legacy code breaks with the following purity check - (global.params.useDIP1000 != FeatureState.enabled || e.f.isPure() >= PURE.const_) && - e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive. + (!global.params.fixImmutableConv || e.f.isPure() >= PURE.const_) && + e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive. ) { result = e.type.immutableOf().implicitConvTo(t); @@ -2768,16 +2767,14 @@ Expression scaleFactor(BinExp be, Scope* sc) else assert(0); - if (sc.func && !sc.intypeof) + + eoff = eoff.optimize(WANTvalue); + if (eoff.op == EXP.int64 && eoff.toInteger() == 0) { - eoff = eoff.optimize(WANTvalue); - if (eoff.op == EXP.int64 && eoff.toInteger() == 0) - { - } - else if (sc.func.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions")) - { - return ErrorExp.get(); - } + } + else if (sc.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions")) + { + return ErrorExp.get(); } return be; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 0bde33d..2c7d381 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -122,10 +122,10 @@ public: Symbol* isym; // import version of csym DString mangleOverride; // overridden symbol with pragma(mangle, "...") - const char *kind() const; - uinteger_t size(const Loc &loc); + const char *kind() const override; + uinteger_t size(const Loc &loc) override final; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; bool isStatic() const { return (storage_class & STCstatic) != 0; } LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one @@ -142,7 +142,7 @@ public: bool isScope() const { return (storage_class & STCscope) != 0; } bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; } bool isParameter() const { return (storage_class & STCparameter) != 0; } - bool isDeprecated() const { return (storage_class & STCdeprecated) != 0; } + bool isDeprecated() const override final { return (storage_class & STCdeprecated) != 0; } bool isOverride() const { return (storage_class & STCoverride) != 0; } bool isResult() const { return (storage_class & STCresult) != 0; } bool isField() const { return (storage_class & STCfield) != 0; } @@ -154,15 +154,15 @@ public: bool isFuture() const { return (storage_class & STCfuture) != 0; } - Visibility visible(); + Visibility visible() override final; - Declaration *isDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + Declaration *isDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ -class TupleDeclaration : public Declaration +class TupleDeclaration final : public Declaration { public: Objects *objects; @@ -170,19 +170,19 @@ public: TypeTuple *tupletype; // !=NULL if this is a type tuple - TupleDeclaration *syntaxCopy(Dsymbol *); - const char *kind() const; - Type *getType(); - Dsymbol *toAlias2(); - bool needThis(); + TupleDeclaration *syntaxCopy(Dsymbol *) override; + const char *kind() const override; + Type *getType() override; + Dsymbol *toAlias2() override; + bool needThis() override; - TupleDeclaration *isTupleDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + TupleDeclaration *isTupleDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ -class AliasDeclaration : public Declaration +class AliasDeclaration final : public Declaration { public: Dsymbol *aliassym; @@ -190,36 +190,36 @@ public: Dsymbol *_import; // !=NULL if unresolved internal alias for selective import static AliasDeclaration *create(const Loc &loc, Identifier *id, Type *type); - AliasDeclaration *syntaxCopy(Dsymbol *); - bool overloadInsert(Dsymbol *s); - const char *kind() const; - Type *getType(); - Dsymbol *toAlias(); - Dsymbol *toAlias2(); - bool isOverloadable() const; + AliasDeclaration *syntaxCopy(Dsymbol *) override; + bool overloadInsert(Dsymbol *s) override; + const char *kind() const override; + Type *getType() override; + Dsymbol *toAlias() override; + Dsymbol *toAlias2() override; + bool isOverloadable() const override; - AliasDeclaration *isAliasDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + AliasDeclaration *isAliasDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ -class OverDeclaration : public Declaration +class OverDeclaration final : public Declaration { public: Dsymbol *overnext; // next in overload list Dsymbol *aliassym; - const char *kind() const; - bool equals(const RootObject *o) const; - bool overloadInsert(Dsymbol *s); + const char *kind() const override; + bool equals(const RootObject *o) const override; + bool overloadInsert(Dsymbol *s) override; - Dsymbol *toAlias(); + Dsymbol *toAlias() override; Dsymbol *isUnique(); - bool isOverloadable() const; + bool isOverloadable() const override; - OverDeclaration *isOverDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + OverDeclaration *isOverDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ @@ -271,26 +271,26 @@ public: bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument bool isArgDtorVar(bool v); static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined); - VarDeclaration *syntaxCopy(Dsymbol *); - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); - const char *kind() const; - AggregateDeclaration *isThis(); - bool needThis(); - bool isExport() const; - bool isImportedSymbol() const; + 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; + bool isExport() const override final; + bool isImportedSymbol() const override final; bool isCtorinit() const; - bool isDataseg(); - bool isThreadlocal(); + bool isDataseg() override final; + bool isThreadlocal() override final; bool isCTFE(); bool isOverlappedWith(VarDeclaration *v); - bool hasPointers(); + bool hasPointers() override final; bool canTakeAddressOf(); bool needsScopeDtor(); - void checkCtorConstInit(); - Dsymbol *toAlias(); + void checkCtorConstInit() override final; + Dsymbol *toAlias() override final; // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - void accept(Visitor *v) { v->visit(this); } + VarDeclaration *isVarDeclaration() override final { return (VarDeclaration *)this; } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ @@ -303,23 +303,23 @@ public: unsigned fieldWidth; unsigned bitOffset; - BitFieldDeclaration *syntaxCopy(Dsymbol*); - BitFieldDeclaration *isBitFieldDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + BitFieldDeclaration *syntaxCopy(Dsymbol *) override; + BitFieldDeclaration *isBitFieldDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ // This is a shell around a back end symbol -class SymbolDeclaration : public Declaration +class SymbolDeclaration final : public Declaration { public: AggregateDeclaration *dsym; // Eliminate need for dynamic_cast - SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; } - void accept(Visitor *v) { v->visit(this); } + SymbolDeclaration *isSymbolDeclaration() override { return (SymbolDeclaration *)this; } + void accept(Visitor *v) override { v->visit(this); } }; class TypeInfoDeclaration : public VarDeclaration @@ -328,149 +328,149 @@ public: Type *tinfo; static TypeInfoDeclaration *create(Type *tinfo); - TypeInfoDeclaration *syntaxCopy(Dsymbol *); - const char *toChars() const; + TypeInfoDeclaration *syntaxCopy(Dsymbol *) override final; + const char *toChars() const override final; - TypeInfoDeclaration *isTypeInfoDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + TypeInfoDeclaration *isTypeInfoDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoStructDeclaration : public TypeInfoDeclaration +class TypeInfoStructDeclaration final : public TypeInfoDeclaration { public: static TypeInfoStructDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoClassDeclaration : public TypeInfoDeclaration +class TypeInfoClassDeclaration final : public TypeInfoDeclaration { public: static TypeInfoClassDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration +class TypeInfoInterfaceDeclaration final : public TypeInfoDeclaration { public: static TypeInfoInterfaceDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoPointerDeclaration : public TypeInfoDeclaration +class TypeInfoPointerDeclaration final : public TypeInfoDeclaration { public: static TypeInfoPointerDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoArrayDeclaration : public TypeInfoDeclaration +class TypeInfoArrayDeclaration final : public TypeInfoDeclaration { public: static TypeInfoArrayDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration +class TypeInfoStaticArrayDeclaration final : public TypeInfoDeclaration { public: static TypeInfoStaticArrayDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration +class TypeInfoAssociativeArrayDeclaration final : public TypeInfoDeclaration { public: static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoEnumDeclaration : public TypeInfoDeclaration +class TypeInfoEnumDeclaration final : public TypeInfoDeclaration { public: static TypeInfoEnumDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoFunctionDeclaration : public TypeInfoDeclaration +class TypeInfoFunctionDeclaration final : public TypeInfoDeclaration { public: static TypeInfoFunctionDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoDelegateDeclaration : public TypeInfoDeclaration +class TypeInfoDelegateDeclaration final : public TypeInfoDeclaration { public: static TypeInfoDelegateDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoTupleDeclaration : public TypeInfoDeclaration +class TypeInfoTupleDeclaration final : public TypeInfoDeclaration { public: static TypeInfoTupleDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoConstDeclaration : public TypeInfoDeclaration +class TypeInfoConstDeclaration final : public TypeInfoDeclaration { public: static TypeInfoConstDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoInvariantDeclaration : public TypeInfoDeclaration +class TypeInfoInvariantDeclaration final : public TypeInfoDeclaration { public: static TypeInfoInvariantDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoSharedDeclaration : public TypeInfoDeclaration +class TypeInfoSharedDeclaration final : public TypeInfoDeclaration { public: static TypeInfoSharedDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoWildDeclaration : public TypeInfoDeclaration +class TypeInfoWildDeclaration final : public TypeInfoDeclaration { public: static TypeInfoWildDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeInfoVectorDeclaration : public TypeInfoDeclaration +class TypeInfoVectorDeclaration final : public TypeInfoDeclaration { public: static TypeInfoVectorDeclaration *create(Type *tinfo); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ -class ThisDeclaration : public VarDeclaration +class ThisDeclaration final : public VarDeclaration { public: - ThisDeclaration *syntaxCopy(Dsymbol *); - ThisDeclaration *isThisDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + ThisDeclaration *syntaxCopy(Dsymbol *) override; + ThisDeclaration *isThisDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; enum class ILS : unsigned char @@ -614,9 +614,7 @@ public: FuncDeclarations *inlinedNestedCallees; -private: AttributeViolation* safetyViolation; -public: unsigned flags; // FUNCFLAGxxxxx @@ -625,31 +623,31 @@ public: ObjcFuncDeclaration objc; static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false); - FuncDeclaration *syntaxCopy(Dsymbol *); + FuncDeclaration *syntaxCopy(Dsymbol *) override; bool functionSemantic(); bool functionSemantic3(); - bool equals(const RootObject *o) const; + bool equals(const RootObject *o) const override final; int overrides(FuncDeclaration *fd); int findVtblIndex(Dsymbols *vtbl, int dim); BaseClass *overrideInterface(); - bool overloadInsert(Dsymbol *s); + bool overloadInsert(Dsymbol *s) override; bool inUnittest(); MATCH leastAsSpecialized(FuncDeclaration *g); LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc); int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd); - const char *toPrettyChars(bool QualifyTypes = false); + const char *toPrettyChars(bool QualifyTypes = false) override; const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' bool isMain() const; bool isCMain() const; bool isWinMain() const; bool isDllMain() const; - bool isExport() const; - bool isImportedSymbol() const; - bool isCodeseg() const; - bool isOverloadable() const; - bool isAbstract(); + bool isExport() const override final; + bool isImportedSymbol() const override final; + bool isCodeseg() const override final; + bool isOverloadable() const override final; + bool isAbstract() override final; PURE isPure(); PURE isPureBypassingInference(); bool isSafe(); @@ -676,14 +674,14 @@ public: void isCrtDtor(bool v); virtual bool isNested() const; - AggregateDeclaration *isThis(); - bool needThis(); + AggregateDeclaration *isThis() override; + bool needThis() override final; bool isVirtualMethod(); virtual bool isVirtual() const; bool isFinalFunc() const; virtual bool addPreInvariant(); virtual bool addPostInvariant(); - const char *kind() const; + const char *kind() const override; bool isUnique(); bool needsClosure(); bool hasNestedFrameRefs(); @@ -694,26 +692,26 @@ public: bool checkNRVO(); - FuncDeclaration *isFuncDeclaration() { return this; } + FuncDeclaration *isFuncDeclaration() override final { return this; } virtual FuncDeclaration *toAliasFunc() { return this; } - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class FuncAliasDeclaration : public FuncDeclaration +class FuncAliasDeclaration final : public FuncDeclaration { public: FuncDeclaration *funcalias; bool hasOverloads; - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind() const; + FuncAliasDeclaration *isFuncAliasDeclaration() override { return this; } + const char *kind() const override; - FuncDeclaration *toAliasFunc(); - void accept(Visitor *v) { v->visit(this); } + FuncDeclaration *toAliasFunc() override; + void accept(Visitor *v) override { v->visit(this); } }; -class FuncLiteralDeclaration : public FuncDeclaration +class FuncLiteralDeclaration final : public FuncDeclaration { public: TOK tok; // TOKfunction or TOKdelegate @@ -722,85 +720,85 @@ public: // backend bool deferToObj; - FuncLiteralDeclaration *syntaxCopy(Dsymbol *); - bool isNested() const; - AggregateDeclaration *isThis(); - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); + FuncLiteralDeclaration *syntaxCopy(Dsymbol *) override; + bool isNested() const override; + AggregateDeclaration *isThis() override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; void modifyReturns(Scope *sc, Type *tret); - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind() const; - const char *toPrettyChars(bool QualifyTypes = false); - void accept(Visitor *v) { v->visit(this); } + FuncLiteralDeclaration *isFuncLiteralDeclaration() override { return this; } + const char *kind() const override; + const char *toPrettyChars(bool QualifyTypes = false) override; + void accept(Visitor *v) override { v->visit(this); } }; -class CtorDeclaration : public FuncDeclaration +class CtorDeclaration final : public FuncDeclaration { public: bool isCpCtor; - CtorDeclaration *syntaxCopy(Dsymbol *); - const char *kind() const; - const char *toChars() const; - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); + CtorDeclaration *syntaxCopy(Dsymbol *) override; + const char *kind() const override; + const char *toChars() const override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; - CtorDeclaration *isCtorDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + CtorDeclaration *isCtorDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class PostBlitDeclaration : public FuncDeclaration +class PostBlitDeclaration final : public FuncDeclaration { public: - PostBlitDeclaration *syntaxCopy(Dsymbol *); - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); - bool overloadInsert(Dsymbol *s); + PostBlitDeclaration *syntaxCopy(Dsymbol *) override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + bool overloadInsert(Dsymbol *s) override; - PostBlitDeclaration *isPostBlitDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + PostBlitDeclaration *isPostBlitDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class DtorDeclaration : public FuncDeclaration +class DtorDeclaration final : public FuncDeclaration { public: - DtorDeclaration *syntaxCopy(Dsymbol *); - const char *kind() const; - const char *toChars() const; - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); - bool overloadInsert(Dsymbol *s); + DtorDeclaration *syntaxCopy(Dsymbol *) override; + const char *kind() const override; + const char *toChars() const override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + bool overloadInsert(Dsymbol *s) override; - DtorDeclaration *isDtorDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + DtorDeclaration *isDtorDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; class StaticCtorDeclaration : public FuncDeclaration { public: - StaticCtorDeclaration *syntaxCopy(Dsymbol *); - AggregateDeclaration *isThis(); - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); - bool hasStaticCtorOrDtor(); + StaticCtorDeclaration *syntaxCopy(Dsymbol *) override; + AggregateDeclaration *isThis() override final; + bool isVirtual() const override final; + bool addPreInvariant() override final; + bool addPostInvariant() override final; + bool hasStaticCtorOrDtor() override final; - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + StaticCtorDeclaration *isStaticCtorDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class SharedStaticCtorDeclaration : public StaticCtorDeclaration +class SharedStaticCtorDeclaration final : public StaticCtorDeclaration { public: - SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *); + SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *) override; - SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; class StaticDtorDeclaration : public FuncDeclaration @@ -808,39 +806,39 @@ class StaticDtorDeclaration : public FuncDeclaration public: VarDeclaration *vgate; // 'gate' variable - StaticDtorDeclaration *syntaxCopy(Dsymbol *); - AggregateDeclaration *isThis(); - bool isVirtual() const; - bool hasStaticCtorOrDtor(); - bool addPreInvariant(); - bool addPostInvariant(); + StaticDtorDeclaration *syntaxCopy(Dsymbol *) override; + AggregateDeclaration *isThis() override final; + bool isVirtual() const override final; + bool hasStaticCtorOrDtor() override final; + bool addPreInvariant() override final; + bool addPostInvariant() override final; - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + StaticDtorDeclaration *isStaticDtorDeclaration() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class SharedStaticDtorDeclaration : public StaticDtorDeclaration +class SharedStaticDtorDeclaration final : public StaticDtorDeclaration { public: - SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *); + SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *) override; - SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class InvariantDeclaration : public FuncDeclaration +class InvariantDeclaration final : public FuncDeclaration { public: - InvariantDeclaration *syntaxCopy(Dsymbol *); - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); + InvariantDeclaration *syntaxCopy(Dsymbol *) override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; - InvariantDeclaration *isInvariantDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + InvariantDeclaration *isInvariantDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class UnitTestDeclaration : public FuncDeclaration +class UnitTestDeclaration final : public FuncDeclaration { public: char *codedoc; /** For documented unittest. */ @@ -848,25 +846,25 @@ public: // toObjFile() these nested functions after this one FuncDeclarations deferredNested; - UnitTestDeclaration *syntaxCopy(Dsymbol *); - AggregateDeclaration *isThis(); - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); + UnitTestDeclaration *syntaxCopy(Dsymbol *) override; + AggregateDeclaration *isThis() override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; - UnitTestDeclaration *isUnitTestDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + UnitTestDeclaration *isUnitTestDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class NewDeclaration : public FuncDeclaration +class NewDeclaration final : public FuncDeclaration { public: - NewDeclaration *syntaxCopy(Dsymbol *); - const char *kind() const; - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); + NewDeclaration *syntaxCopy(Dsymbol *) override; + const char *kind() const override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; - NewDeclaration *isNewDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } + NewDeclaration *isNewDeclaration() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 26a0ff0..f8e5073a 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -363,6 +363,9 @@ extern (C++) final class Module : Package int selfimports; // 0: don't know, 1: does not, 2: does Dsymbol[void*] tagSymTab; /// ImportC: tag symbols that conflict with other symbols used as the index + private OutBuffer defines; // collect all the #define lines here + + /************************************* * Return true if module imports itself. */ @@ -677,33 +680,7 @@ extern (C++) final class Module : Package FileName.equalsExt(srcfile.toString(), c_ext) && FileName.exists(srcfile.toString())) { - /* Look for "importc.h" by searching along import path. - * It should be in the same place as "object.d" - */ - const(char)* importc_h; - - foreach (entry; (global.path ? (*global.path)[] : null)) - { - auto f = FileName.combine(entry, "importc.h"); - if (FileName.exists(f) == 1) - { - importc_h = f; - break; - } - FileName.free(f); - } - - if (importc_h) - { - if (global.params.verbose) - message("include %s", importc_h); - } - else - { - error("cannot find \"importc.h\" along import path"); - fatal(); - } - filename = global.preprocess(srcfile, importc_h, global.params.cppswitches, ifile); // run C preprocessor + filename = global.preprocess(srcfile, loc, global.params.cppswitches, ifile, &defines); // run C preprocessor } if (auto result = global.fileManager.lookup(filename)) @@ -1001,7 +978,7 @@ extern (C++) final class Module : Package { filetype = FileType.c; - scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c); + scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c, &defines); p.nextToken(); checkCompiledImport(); members = p.parseModule(); diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index b006940..3b3a527 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1978,8 +1978,9 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol } const DYNCAST kind = arrayContent.dyncast(); - if (kind == DYNCAST.dsymbol) + switch (kind) with (DYNCAST) { + case dsymbol: TupleDeclaration td = cast(TupleDeclaration) arrayContent; /* $ gives the number of elements in the tuple */ @@ -1989,10 +1990,10 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol v.storage_class |= STC.temp | STC.static_ | STC.const_; v.dsymbolSemantic(sc); return v; - } - if (kind == DYNCAST.type) - { + case type: return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc); + default: + break; } Expression exp = cast(Expression) arrayContent; if (auto ie = exp.isIndexExp()) @@ -2531,6 +2532,16 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (log) printf(" collision\n"); return null; } + /* + Handle merging declarations with asm("foo") and their definitions + */ + static void mangleWrangle(Declaration oldDecl, Declaration newDecl) + { + if (oldDecl && newDecl) + { + newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null; + } + } auto vd = s.isVarDeclaration(); // new declaration auto vd2 = s2.isVarDeclaration(); // existing declaration @@ -2548,6 +2559,8 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (i1 && i2) return collision(); // can't both have initializers + mangleWrangle(vd2, vd); + if (i1) // vd is the definition { vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it @@ -2593,6 +2606,8 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (fd.fbody && fd2.fbody) return collision(); // can't both have bodies + mangleWrangle(fd2, fd); + if (fd.fbody) // fd is the definition { if (log) printf(" replace existing with new\n"); diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 35500af..23a2c77 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -185,11 +185,11 @@ public: UserAttributeDeclaration *userAttribDecl; // user defined attributes static Dsymbol *create(Identifier *); - const char *toChars() const; + const char *toChars() const override; virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments Loc getLoc(); const char *locToChars(); - bool equals(const RootObject *o) const; + bool equals(const RootObject *o) const override; bool isAnonymous() const; void error(const Loc &loc, const char *format, ...); void error(const char *format, ...); @@ -211,7 +211,7 @@ public: Ungag ungagSpeculative(); // kludge for template.isSymbol() - DYNCAST dyncast() const { return DYNCAST_DSYMBOL; } + DYNCAST dyncast() const override final { return DYNCAST_DSYMBOL; } virtual Identifier *getIdent(); virtual const char *toPrettyChars(bool QualifyTypes = false); @@ -310,7 +310,7 @@ public: virtual OverloadSet *isOverloadSet() { return NULL; } virtual CompileDeclaration *isCompileDeclaration() { return NULL; } virtual StaticAssert *isStaticAssert() { return NULL; } - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // Dsymbol that generates a scope @@ -329,89 +329,89 @@ private: BitArray accessiblePackages, privateAccessiblePackages; public: - ScopeDsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); + ScopeDsymbol *syntaxCopy(Dsymbol *s) override; + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; virtual void importScope(Dsymbol *s, Visibility visibility); virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0); - bool isforwardRef(); + bool isforwardRef() override final; static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2); - const char *kind() const; + const char *kind() const override; FuncDeclaration *findGetMembers(); virtual Dsymbol *symtabInsert(Dsymbol *s); virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); - bool hasStaticCtorOrDtor(); + bool hasStaticCtorOrDtor() override; - ScopeDsymbol *isScopeDsymbol() { return this; } - void accept(Visitor *v) { v->visit(this); } + ScopeDsymbol *isScopeDsymbol() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; // With statement scope -class WithScopeSymbol : public ScopeDsymbol +class WithScopeSymbol final : public ScopeDsymbol { public: WithStatement *withstate; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; - WithScopeSymbol *isWithScopeSymbol() { return this; } - void accept(Visitor *v) { v->visit(this); } + WithScopeSymbol *isWithScopeSymbol() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; // Array Index/Slice scope -class ArrayScopeSymbol : public ScopeDsymbol +class ArrayScopeSymbol final : public ScopeDsymbol { private: RootObject *arrayContent; public: Scope *sc; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone); + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone) override; - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } - void accept(Visitor *v) { v->visit(this); } + ArrayScopeSymbol *isArrayScopeSymbol() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; // Overload Sets -class OverloadSet : public Dsymbol +class OverloadSet final : public Dsymbol { public: Dsymbols a; // array of Dsymbols void push(Dsymbol *s); - OverloadSet *isOverloadSet() { return this; } - const char *kind() const; - void accept(Visitor *v) { v->visit(this); } + OverloadSet *isOverloadSet() override { return this; } + const char *kind() const override; + void accept(Visitor *v) override { v->visit(this); } }; // Forwarding ScopeDsymbol -class ForwardingScopeDsymbol : public ScopeDsymbol +class ForwardingScopeDsymbol final : public ScopeDsymbol { public: ScopeDsymbol *forward; - Dsymbol *symtabInsert(Dsymbol *s); - Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); - void importScope(Dsymbol *s, Visibility visibility); - const char *kind() const; + Dsymbol *symtabInsert(Dsymbol *s) override; + Dsymbol *symtabLookup(Dsymbol *s, Identifier *id) override; + void importScope(Dsymbol *s, Visibility visibility) override; + const char *kind() const override; - ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; } + ForwardingScopeDsymbol *isForwardingScopeDsymbol() override { return this; } }; -class ExpressionDsymbol : public Dsymbol +class ExpressionDsymbol final : public Dsymbol { public: Expression *exp; - ExpressionDsymbol *isExpressionDsymbol() { return this; } + ExpressionDsymbol *isExpressionDsymbol() override { return this; } }; // Table of Dsymbol's -class DsymbolTable : public RootObject +class DsymbolTable final : public RootObject { public: AA *tab; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 5d88056..e491272 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -468,12 +468,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym.type.checkComplexTransition(dsym.loc, sc); // Calculate type size + safety checks - if (sc.func && !sc.intypeof) + if (dsym.storage_class & STC.gshared && !dsym.isMember()) { - if (dsym.storage_class & STC.gshared && !dsym.isMember()) - { - sc.func.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared"); - } + sc.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared"); } Dsymbol parent = dsym.toParent(); @@ -857,23 +854,23 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } // Calculate type size + safety checks - if (sc.func && !sc.intypeof) + if (1) { if (dsym._init && dsym._init.isVoidInitializer() && (dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size { if (dsym.type.hasPointers()) - sc.func.setUnsafe(false, dsym.loc, + sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions"); else - sc.func.setUnsafe(false, dsym.loc, + sc.setUnsafe(false, dsym.loc, "`void` initializers for structs with invariants are not allowed in safe functions"); } else if (!dsym._init && !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) && dsym.type.hasVoidInitPointers()) { - sc.func.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions"); + sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions"); } } @@ -3595,6 +3592,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor break; } + auto vtf = getFunctionType(fdv); + if (vtf.trust > TRUST.system && f.trust == TRUST.system) + funcdecl.error("cannot override `@safe` method `%s` with a `@system` attribute", + 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", diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index ed0126e..a450ea5 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -5352,7 +5352,7 @@ extern (C++) class TemplateParameter : ASTNode return this.ident.toChars(); } - override DYNCAST dyncast() const pure @nogc nothrow @safe + override DYNCAST dyncast() const { return DYNCAST.templateparameter; } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 55f7c72..9afcc7f 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -801,26 +801,22 @@ public: if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) writeProtection(AST.Visibility.Kind.private_); funcToBuffer(tf, fd); - // FIXME: How to determine if fd is const without tf? - if (adparent && tf && (tf.isConst() || tf.isImmutable())) + if (adparent) { - bool fdOverridesAreConst = true; - foreach (fdv; fd.foverrides) + if (tf && (tf.isConst() || tf.isImmutable())) + buf.writestring(" const"); + if (global.params.cplusplus >= CppStdRevision.cpp11) { - auto tfv = cast(AST.TypeFunction)fdv.type; - if (!tfv.isConst() && !tfv.isImmutable()) - { - fdOverridesAreConst = false; - break; - } + if (fd.vtblIndex != -1 && !(adparent.storage_class & AST.STC.final_) && fd.isFinalFunc()) + buf.writestring(" final"); + if (fd.isOverride()) + buf.writestring(" override"); } - - buf.writestring(fdOverridesAreConst ? " const" : " /* const */"); + if (fd.isAbstract()) + buf.writestring(" = 0"); + else if (global.params.cplusplus >= CppStdRevision.cpp11 && fd.isDisabled()) + buf.writestring(" = delete"); } - if (adparent && fd.isAbstract()) - buf.writestring(" = 0"); - if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11) - buf.writestring(" = delete"); buf.writestringln(";"); if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) writeProtection(AST.Visibility.Kind.public_); diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index ab80c8b..9ec1300 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -17,7 +17,7 @@ class Identifier; class Type; class Expression; -class EnumDeclaration : public ScopeDsymbol +class EnumDeclaration final : public ScopeDsymbol { public: /* The separate, and distinct, cases are: @@ -40,27 +40,27 @@ public: bool added; int inuse; - EnumDeclaration *syntaxCopy(Dsymbol *s); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - bool oneMember(Dsymbol **ps, Identifier *ident); - Type *getType(); - const char *kind() const; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); - bool isDeprecated() const; // is Dsymbol deprecated? - Visibility visible(); + EnumDeclaration *syntaxCopy(Dsymbol *s) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void setScope(Scope *sc) override; + bool oneMember(Dsymbol **ps, Identifier *ident) override; + Type *getType() override; + const char *kind() const override; + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) 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() { return this; } + EnumDeclaration *isEnumDeclaration() override { return this; } Symbol *sinit; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class EnumMember : public VarDeclaration +class EnumMember final : public VarDeclaration { public: /* Can take the following forms: @@ -78,9 +78,9 @@ public: EnumDeclaration *ed; - EnumMember *syntaxCopy(Dsymbol *s); - const char *kind() const; + EnumMember *syntaxCopy(Dsymbol *s) override; + const char *kind() const override; - EnumMember *isEnumMember() { return this; } - void accept(Visitor *v) { v->visit(this); } + EnumMember *isEnumMember() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 3f41c29..97a6552 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -145,7 +145,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, refs = true; auto var = outerVars[i - (len - outerVars.length)]; eb.isMutable = var.type.isMutable(); - eb.er.byref.push(var); + eb.er.pushRef(var, false); continue; } @@ -165,7 +165,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, if (!(eb.isMutable || eb2.isMutable)) return; - if (!(global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())) + if (!(global.params.useDIP1000 == FeatureState.enabled && sc.setUnsafe())) return; if (!gag) @@ -1185,6 +1185,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) if (v.isDataseg()) continue; + const vsr = buildScopeRef(v.storage_class); + Dsymbol p = v.toParent2(); if ((v.isScope() || (v.storage_class & STC.maybescope)) && @@ -1200,8 +1202,13 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) if (v.isScope()) { - if (v.storage_class & STC.return_) + /* If `return scope` applies to v. + */ + if (vsr == ScopeRef.ReturnScope || + vsr == ScopeRef.Ref_ReturnScope) + { continue; + } auto pfunc = p.isFuncDeclaration(); if (pfunc && @@ -1245,7 +1252,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } } - foreach (VarDeclaration v; er.byref) + foreach (i, VarDeclaration v; er.byref[]) { if (log) { @@ -1281,9 +1288,16 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } else { - if (!gag) - previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars()); - result = true; + if (er.refRetRefTransition[i]) + { + result |= sc.setUnsafeDIP1000(gag, e.loc, msg, e, v); + } + else + { + if (!gag) + previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars()); + result = true; + } } } @@ -1374,14 +1388,21 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } } - foreach (Expression ee; er.byexp) + foreach (i, Expression ee; er.byexp[]) { if (log) printf("byexp %s\n", ee.toChars()); - if (!gag) - error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars()); - result = true; + if (er.expRetRefTransition[i]) + { + result |= sc.setUnsafeDIP1000(gag, ee.loc, + "escaping reference to stack allocated value returned by `%s`", ee); + } + else + { + if (!gag) + error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars()); + result = true; + } } - return result; } @@ -1449,8 +1470,9 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) * e = expression to be returned by value * er = where to place collected data * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. + * retRefTransition = if `e` is returned through a `return ref scope` function call */ -void escapeByValue(Expression e, EscapeByResults* er, bool live = false) +void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false) { //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars()); @@ -1465,14 +1487,14 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) * but it'll be placed in static data so no need to check it. */ if (e.e1.op != EXP.structLiteral) - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } void visitSymOff(SymOffExp e) { VarDeclaration v = e.var.isVarDeclaration(); if (v) - er.byref.push(v); + er.pushRef(v, retRefTransition); } void visitVar(VarExp e) @@ -1494,7 +1516,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) void visitPtr(PtrExp e) { if (live && e.type.hasPointers()) - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } void visitDotVar(DotVarExp e) @@ -1502,7 +1524,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) auto t = e.e1.type.toBasetype(); if (e.type.hasPointers() && (live || t.ty == Tstruct)) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } } @@ -1510,9 +1532,9 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { Type t = e.e1.type.toBasetype(); if (t.ty == Tclass || t.ty == Tpointer) - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); else - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); er.byfunc.push(e.func); } @@ -1533,11 +1555,11 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) if (tb.ty == Tsarray || tb.ty == Tarray) { if (e.basis) - escapeByValue(e.basis, er, live); + escapeByValue(e.basis, er, live, retRefTransition); foreach (el; *e.elements) { if (el) - escapeByValue(el, er, live); + escapeByValue(el, er, live, retRefTransition); } } } @@ -1549,7 +1571,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) foreach (ex; *e.elements) { if (ex) - escapeByValue(ex, er, live); + escapeByValue(ex, er, live, retRefTransition); } } } @@ -1562,7 +1584,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) foreach (ex; *e.arguments) { if (ex) - escapeByValue(ex, er, live); + escapeByValue(ex, er, live, retRefTransition); } } } @@ -1574,10 +1596,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) Type tb = e.type.toBasetype(); if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray) { - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } else - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } void visitSlice(SliceExp e) @@ -1602,10 +1624,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { Type tb = e.type.toBasetype(); if (tb.ty != Tsarray) - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } else - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } void visitIndex(IndexExp e) @@ -1613,7 +1635,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) if (e.e1.type.toBasetype().ty == Tsarray || live && e.type.hasPointers()) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } } @@ -1622,30 +1644,30 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) Type tb = e.type.toBasetype(); if (tb.ty == Tpointer) { - escapeByValue(e.e1, er, live); - escapeByValue(e.e2, er, live); + escapeByValue(e.e1, er, live, retRefTransition); + escapeByValue(e.e2, er, live, retRefTransition); } } void visitBinAssign(BinAssignExp e) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } void visitAssign(AssignExp e) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } void visitComma(CommaExp e) { - escapeByValue(e.e2, er, live); + escapeByValue(e.e2, er, live, retRefTransition); } void visitCond(CondExp e) { - escapeByValue(e.e1, er, live); - escapeByValue(e.e2, er, live); + escapeByValue(e.e1, er, live, retRefTransition); + escapeByValue(e.e2, er, live, retRefTransition); } void visitCall(CallExp e) @@ -1686,7 +1708,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) const stc = tf.parameterStorageClass(null, p); ScopeRef psr = buildScopeRef(stc); if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(arg, er, live); + escapeByValue(arg, er, live, retRefTransition); else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) { if (tf.isref) @@ -1696,10 +1718,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) * as: * p; */ - escapeByValue(arg, er, live); + escapeByValue(arg, er, live, retRefTransition); } else - escapeByRef(arg, er, live); + escapeByRef(arg, er, live, retRefTransition); } } } @@ -1709,7 +1731,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { DotVarExp dve = e.e1.isDotVarExp(); FuncDeclaration fd = dve.var.isFuncDeclaration(); - if (global.params.useDIP1000 == FeatureState.enabled) + if (1) { if (fd && fd.isThis()) { @@ -1741,7 +1763,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) const psr = buildScopeRef(getThisStorageClass(fd)); if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(dve.e1, er, live); + escapeByValue(dve.e1, er, live, retRefTransition); else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) { if (tf.isref) @@ -1751,10 +1773,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) * as: * this; */ - escapeByValue(dve.e1, er, live); + escapeByValue(dve.e1, er, live, retRefTransition); } else - escapeByRef(dve.e1, er, live); + escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope); } } } @@ -1767,16 +1789,16 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) const psr = buildScopeRef(stc); if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(dve.e1, er, live); + escapeByValue(dve.e1, er, live, retRefTransition); else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - escapeByRef(dve.e1, er, live); + escapeByRef(dve.e1, er, live, retRefTransition); } // If it's also a nested function that is 'return scope' if (fd && fd.isNested()) { if (tf.isreturn && tf.isScopeQual) - er.byexp.push(e); + er.pushExp(e, false); } } @@ -1786,7 +1808,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) if (dg) { if (tf.isreturn) - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } /* If it's a nested function that is 'return scope' @@ -1797,7 +1819,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) if (fd && fd.isNested()) { if (tf.isreturn && tf.isScopeQual) - er.byexp.push(e); + er.pushExp(e, false); } } } @@ -1852,10 +1874,11 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) * e = expression to be returned by 'ref' * er = where to place collected data * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. + * retRefTransition = if `e` is returned through a `return ref scope` function call */ -void escapeByRef(Expression e, EscapeByResults* er, bool live = false) +void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false) { - //printf("[%s] escapeByRef, e: %s\n", e.loc.toChars(), e.toChars()); + //printf("[%s] escapeByRef, e: %s, retRefTransition: %d\n", e.loc.toChars(), e.toChars(), retRefTransition); void visit(Expression e) { } @@ -1874,27 +1897,27 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) if (ExpInitializer ez = v._init.isExpInitializer()) { if (auto ce = ez.exp.isConstructExp()) - escapeByRef(ce.e2, er, live); + escapeByRef(ce.e2, er, live, retRefTransition); else - escapeByRef(ez.exp, er, live); + escapeByRef(ez.exp, er, live, retRefTransition); } } else - er.byref.push(v); + er.pushRef(v, retRefTransition); } } void visitThis(ThisExp e) { if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext()) - escapeByValue(e, er, live); + escapeByValue(e, er, live, retRefTransition); else if (e.var) - er.byref.push(e.var); + er.pushRef(e.var, retRefTransition); } void visitPtr(PtrExp e) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } void visitIndex(IndexExp e) @@ -1907,18 +1930,18 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) { if (v && v.storage_class & STC.variadic) { - er.byref.push(v); + er.pushRef(v, retRefTransition); return; } } } if (tb.ty == Tsarray) { - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } else if (tb.ty == Tarray) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } } @@ -1929,40 +1952,40 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) foreach (ex; *e.elements) { if (ex) - escapeByRef(ex, er, live); + escapeByRef(ex, er, live, retRefTransition); } } - er.byexp.push(e); + er.pushExp(e, retRefTransition); } void visitDotVar(DotVarExp e) { Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Tclass) - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); else - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } void visitBinAssign(BinAssignExp e) { - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } void visitAssign(AssignExp e) { - escapeByRef(e.e1, er, live); + escapeByRef(e.e1, er, live, retRefTransition); } void visitComma(CommaExp e) { - escapeByRef(e.e2, er, live); + escapeByRef(e.e2, er, live, retRefTransition); } void visitCond(CondExp e) { - escapeByRef(e.e1, er, live); - escapeByRef(e.e2, er, live); + escapeByRef(e.e1, er, live, retRefTransition); + escapeByRef(e.e2, er, live, retRefTransition); } void visitCall(CallExp e) @@ -1997,16 +2020,16 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) const stc = tf.parameterStorageClass(null, p); ScopeRef psr = buildScopeRef(stc); if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - escapeByRef(arg, er, live); + escapeByRef(arg, er, live, retRefTransition); else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) { if (auto de = arg.isDelegateExp()) { if (de.func.isNested()) - er.byexp.push(de); + er.pushExp(de, false); } else - escapeByValue(arg, er, live); + escapeByValue(arg, er, live, retRefTransition); } } } @@ -2019,7 +2042,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) // https://issues.dlang.org/show_bug.cgi?id=20149#c10 if (dve.var.isCtorDeclaration()) { - er.byexp.push(e); + er.pushExp(e, false); return; } @@ -2035,23 +2058,23 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) const psr = buildScopeRef(stc); if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - escapeByRef(dve.e1, er, live); + escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope); else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(dve.e1, er, live); + escapeByValue(dve.e1, er, live, retRefTransition); // If it's also a nested function that is 'return ref' if (FuncDeclaration fd = dve.var.isFuncDeclaration()) { if (fd.isNested() && tf.isreturn) { - er.byexp.push(e); + er.pushExp(e, false); } } } // If it's a delegate, check it too if (e.e1.op == EXP.variable && t1.ty == Tdelegate) { - escapeByValue(e.e1, er, live); + escapeByValue(e.e1, er, live, retRefTransition); } /* If it's a nested function that is 'return ref' @@ -2062,12 +2085,12 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) if (fd && fd.isNested()) { if (tf.isreturn) - er.byexp.push(e); + er.pushExp(e, false); } } } else - er.byexp.push(e); + er.pushExp(e, retRefTransition); } switch (e.op) @@ -2091,7 +2114,6 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) } } - /************************************ * Aggregate the data collected by the escapeBy??() functions. */ @@ -2099,8 +2121,23 @@ struct EscapeByResults { VarDeclarations byref; // array into which variables being returned by ref are inserted VarDeclarations byvalue; // array into which variables with values containing pointers are inserted - FuncDeclarations byfunc; // nested functions that are turned into delegates - Expressions byexp; // array into which temporaries being returned by ref are inserted + private FuncDeclarations byfunc; // nested functions that are turned into delegates + private Expressions byexp; // array into which temporaries being returned by ref are inserted + + import dmd.root.array: Array; + + /** + * Whether the variable / expression went through a `return ref scope` function call + * + * This is needed for the dip1000 by default transition, since the rules for + * disambiguating `return scope ref` have changed. Therefore, functions in legacy code + * can be mistakenly treated as `return ref` making the compiler believe stack variables + * are being escaped, which is an error even in `@system` code. By keeping track of this + * information, variables escaped through `return ref` can be treated as a deprecation instead + * of error, see test/fail_compilation/dip1000_deprecation.d + */ + private Array!bool refRetRefTransition; + private Array!bool expRetRefTransition; /** Reset arrays so the storage can be used again */ @@ -2110,6 +2147,33 @@ struct EscapeByResults byvalue.setDim(0); byfunc.setDim(0); byexp.setDim(0); + + refRetRefTransition.setDim(0); + expRetRefTransition.setDim(0); + } + + /** + * Escape variable `v` by reference + * Params: + * v = variable to escape + * retRefTransition = `v` is escaped through a `return ref scope` function call + */ + void pushRef(VarDeclaration v, bool retRefTransition) + { + byref.push(v); + refRetRefTransition.push(retRefTransition); + } + + /** + * Escape a reference to expression `e` + * Params: + * e = expression to escape + * retRefTransition = `e` is escaped through a `return ref scope` function call + */ + void pushExp(Expression e, bool retRefTransition) + { + byexp.push(e); + expRetRefTransition.push(retRefTransition); } } @@ -2438,7 +2502,7 @@ private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, con } else if (fs == FeatureState.enabled) { - return sc.func.setUnsafe(gag, loc, msg, arg0, arg1); + return sc.setUnsafe(gag, loc, msg, arg0, arg1); } else { @@ -2449,6 +2513,11 @@ private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, con loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "" ); } + else if (!sc.func.safetyViolation) + { + import dmd.func : AttributeViolation; + sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1); + } return false; } } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 0872356..4d17105 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -1370,7 +1370,7 @@ extern (C++) abstract class Expression : ASTNode */ if (v.storage_class & STC.gshared) { - if (sc.func.setUnsafe(false, this.loc, + if (sc.setUnsafe(false, this.loc, "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v)) { err = true; @@ -1419,7 +1419,7 @@ extern (C++) abstract class Expression : ASTNode error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), prettyChars); - f.errorSupplementalInferredSafety(/*max depth*/ 10); + f.errorSupplementalInferredSafety(/*max depth*/ 10, /*deprecation*/ false); .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); @@ -1427,6 +1427,20 @@ extern (C++) abstract class Expression : ASTNode return true; } } + else if (f.isSafe() && f.safetyViolation) + { + // for dip1000 by default transition, print deprecations for calling functions that will become `@system` + if (sc.func.isSafeBypassingInference()) + { + .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars()); + errorSupplementalInferredSafety(f, 10, true); + } + else if (!sc.func.safetyViolation) + { + import dmd.func : AttributeViolation; + sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null); + } + } return false; } @@ -5761,7 +5775,7 @@ extern (C++) final class DelegatePtrExp : UnaExp override Expression modifiableLvalue(Scope* sc, Expression e) { - if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this)) + if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this)) { return ErrorExp.get(); } @@ -5799,7 +5813,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp override Expression modifiableLvalue(Scope* sc, Expression e) { - if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this)) + if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this)) { return ErrorExp.get(); } diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 330dcdb..9ab1cab 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -90,9 +90,9 @@ public: virtual Expression *syntaxCopy(); // kludge for template.isExpression() - DYNCAST dyncast() const { return DYNCAST_EXPRESSION; } + DYNCAST dyncast() const override final { return DYNCAST_EXPRESSION; } - const char *toChars() const; + const char *toChars() const override; void error(const char *format, ...) const; void warning(const char *format, ...) const; void deprecation(const char *format, ...) const; @@ -206,6 +206,8 @@ public: ShrAssignExp* isShrAssignExp(); UshrAssignExp* isUshrAssignExp(); CatAssignExp* isCatAssignExp(); + CatElemAssignExp* isCatElemAssignExp(); + CatDcharAssignExp* isCatDcharAssignExp(); AddExp* isAddExp(); MinExp* isMinExp(); CatExp* isCatExp(); @@ -238,71 +240,71 @@ public: BinExp* isBinExp(); BinAssignExp* isBinAssignExp(); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class IntegerExp : public Expression +class IntegerExp final : public Expression { public: dinteger_t value; static IntegerExp *create(const Loc &loc, dinteger_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, dinteger_t value, Type *type); - bool equals(const RootObject *o) const; - dinteger_t toInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Optional<bool> toBool(); - Expression *toLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool equals(const RootObject *o) const override; + dinteger_t toInteger() override; + real_t toReal() override; + real_t toImaginary() override; + complex_t toComplex() override; + Optional<bool> toBool() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } dinteger_t getInteger() { return value; } void setInteger(dinteger_t value); template<int v> static IntegerExp literal(); }; -class ErrorExp : public Expression +class ErrorExp final : public Expression { public: - Expression *toLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + Expression *toLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } static ErrorExp *errorexp; // handy shared value }; -class RealExp : public Expression +class RealExp final : public Expression { public: real_t value; static RealExp *create(const Loc &loc, real_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, real_t value, Type *type); - bool equals(const RootObject *o) const; - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Optional<bool> toBool(); - void accept(Visitor *v) { v->visit(this); } + bool equals(const RootObject *o) const override; + dinteger_t toInteger() override; + uinteger_t toUInteger() override; + real_t toReal() override; + real_t toImaginary() override; + complex_t toComplex() override; + Optional<bool> toBool() override; + void accept(Visitor *v) override { v->visit(this); } }; -class ComplexExp : public Expression +class ComplexExp final : public Expression { public: complex_t value; static ComplexExp *create(const Loc &loc, complex_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, complex_t value, Type *type); - bool equals(const RootObject *o) const; - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Optional<bool> toBool(); - void accept(Visitor *v) { v->visit(this); } + bool equals(const RootObject *o) const override; + dinteger_t toInteger() override; + uinteger_t toUInteger() override; + real_t toReal() override; + real_t toImaginary() override; + complex_t toComplex() override; + Optional<bool> toBool() override; + void accept(Visitor *v) override { v->visit(this); } }; class IdentifierExp : public Expression @@ -311,27 +313,27 @@ public: Identifier *ident; static IdentifierExp *create(const Loc &loc, Identifier *ident); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override final; + Expression *toLvalue(Scope *sc, Expression *e) override final; + void accept(Visitor *v) override { v->visit(this); } }; -class DollarExp : public IdentifierExp +class DollarExp final : public IdentifierExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DsymbolExp : public Expression +class DsymbolExp final : public Expression { public: Dsymbol *s; bool hasOverloads; - DsymbolExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + DsymbolExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } }; class ThisExp : public Expression @@ -339,30 +341,30 @@ class ThisExp : public Expression public: VarDeclaration *var; - ThisExp *syntaxCopy(); - Optional<bool> toBool(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); + ThisExp *syntaxCopy() override; + Optional<bool> toBool() override; + bool isLvalue() override final; + Expression *toLvalue(Scope *sc, Expression *e) override final; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class SuperExp : public ThisExp +class SuperExp final : public ThisExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class NullExp : public Expression +class NullExp final : public Expression { public: - bool equals(const RootObject *o) const; - Optional<bool> toBool(); - StringExp *toStringExp(); - void accept(Visitor *v) { v->visit(this); } + bool equals(const RootObject *o) const override; + Optional<bool> toBool() override; + StringExp *toStringExp() override; + void accept(Visitor *v) override { v->visit(this); } }; -class StringExp : public Expression +class StringExp final : public Expression { public: void *string; // char, wchar, or dchar data @@ -375,23 +377,23 @@ public: static StringExp *create(const Loc &loc, const char *s); static StringExp *create(const Loc &loc, const void *s, d_size_t len); static void emplace(UnionExp *pue, const Loc &loc, const char *s); - bool equals(const RootObject *o) const; + bool equals(const RootObject *o) const override; char32_t getCodeUnit(d_size_t i) const; void setCodeUnit(d_size_t i, char32_t c); - StringExp *toStringExp(); + StringExp *toStringExp() override; StringExp *toUTF8(Scope *sc); - Optional<bool> toBool(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + Optional<bool> toBool() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } size_t numberOfCodeUnits(int tynto = 0) const; void writeTo(void* dest, bool zero, int tyto = 0) const; }; // Tuple -class TupleExp : public Expression +class TupleExp final : public Expression { public: Expression *e0; // side-effect part @@ -405,13 +407,13 @@ public: Expressions *exps; static TupleExp *create(const Loc &loc, Expressions *exps); - TupleExp *syntaxCopy(); - bool equals(const RootObject *o) const; + TupleExp *syntaxCopy() override; + bool equals(const RootObject *o) const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ArrayLiteralExp : public Expression +class ArrayLiteralExp final : public Expression { public: Expression *basis; @@ -420,31 +422,31 @@ public: static ArrayLiteralExp *create(const Loc &loc, Expressions *elements); static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements); - ArrayLiteralExp *syntaxCopy(); - bool equals(const RootObject *o) const; + ArrayLiteralExp *syntaxCopy() override; + bool equals(const RootObject *o) const override; Expression *getElement(d_size_t i); // use opIndex instead Expression *opIndex(d_size_t i); - Optional<bool> toBool(); - StringExp *toStringExp(); + Optional<bool> toBool() override; + StringExp *toStringExp() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AssocArrayLiteralExp : public Expression +class AssocArrayLiteralExp final : public Expression { public: Expressions *keys; Expressions *values; OwnedBy ownedByCtfe; - bool equals(const RootObject *o) const; - AssocArrayLiteralExp *syntaxCopy(); - Optional<bool> toBool(); + bool equals(const RootObject *o) const override; + AssocArrayLiteralExp *syntaxCopy() override; + Optional<bool> toBool() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class StructLiteralExp : public Expression +class StructLiteralExp final : public Expression { public: StructDeclaration *sd; // which aggregate this is for @@ -475,50 +477,50 @@ public: OwnedBy ownedByCtfe; static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL); - bool equals(const RootObject *o) const; - StructLiteralExp *syntaxCopy(); + bool equals(const RootObject *o) const override; + StructLiteralExp *syntaxCopy() override; Expression *getField(Type *type, unsigned offset); int getFieldIndex(Type *type, unsigned offset); - Expression *addDtorHook(Scope *sc); - Expression *toLvalue(Scope *sc, Expression *e); + Expression *addDtorHook(Scope *sc) override; + Expression *toLvalue(Scope *sc, Expression *e) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeExp : public Expression +class TypeExp final : public Expression { public: - TypeExp *syntaxCopy(); - bool checkType(); - bool checkValue(); - void accept(Visitor *v) { v->visit(this); } + TypeExp *syntaxCopy() override; + bool checkType() override; + bool checkValue() override; + void accept(Visitor *v) override { v->visit(this); } }; -class ScopeExp : public Expression +class ScopeExp final : public Expression { public: ScopeDsymbol *sds; - ScopeExp *syntaxCopy(); - bool checkType(); - bool checkValue(); - void accept(Visitor *v) { v->visit(this); } + ScopeExp *syntaxCopy() override; + bool checkType() override; + bool checkValue() override; + void accept(Visitor *v) override { v->visit(this); } }; -class TemplateExp : public Expression +class TemplateExp final : public Expression { public: TemplateDeclaration *td; FuncDeclaration *fd; - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - bool checkType(); - bool checkValue(); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + bool checkType() override; + bool checkValue() override; + void accept(Visitor *v) override { v->visit(this); } }; -class NewExp : public Expression +class NewExp final : public Expression { public: /* newtype(arguments) @@ -534,12 +536,12 @@ public: bool thrownew; // this NewExp is the expression of a ThrowStatement static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments); - NewExp *syntaxCopy(); + NewExp *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class NewAnonClassExp : public Expression +class NewAnonClassExp final : public Expression { public: /* class baseclasses { } (arguments) @@ -548,8 +550,8 @@ public: ClassDeclaration *cd; // class being instantiated Expressions *arguments; // Array of Expression's to call class constructor - NewAnonClassExp *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + NewAnonClassExp *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; class SymbolExp : public Expression @@ -559,64 +561,64 @@ public: Dsymbol *originalScope; bool hasOverloads; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // Offset from symbol -class SymOffExp : public SymbolExp +class SymOffExp final : public SymbolExp { public: dinteger_t offset; - Optional<bool> toBool(); + Optional<bool> toBool() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // Variable -class VarExp : public SymbolExp +class VarExp final : public SymbolExp { public: bool delegateWasExtracted; static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true); - bool equals(const RootObject *o) const; - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); + bool equals(const RootObject *o) const override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // Overload Set -class OverExp : public Expression +class OverExp final : public Expression { public: OverloadSet *vars; - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } }; // Function/Delegate literal -class FuncExp : public Expression +class FuncExp final : public Expression { public: FuncLiteralDeclaration *fd; TemplateDeclaration *td; TOK tok; - bool equals(const RootObject *o) const; - FuncExp *syntaxCopy(); - const char *toChars() const; - bool checkType(); - bool checkValue(); + bool equals(const RootObject *o) const override; + FuncExp *syntaxCopy() override; + const char *toChars() const override; + bool checkType() override; + bool checkValue() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // Declaration of a symbol @@ -624,44 +626,44 @@ public: // D grammar allows declarations only as statements. However in AST representation // it can be part of any expression. This is used, for example, during internal // syntax re-writes to inject hidden symbols. -class DeclarationExp : public Expression +class DeclarationExp final : public Expression { public: Dsymbol *declaration; - DeclarationExp *syntaxCopy(); + DeclarationExp *syntaxCopy() override; - bool hasCode(); + bool hasCode() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeidExp : public Expression +class TypeidExp final : public Expression { public: RootObject *obj; - TypeidExp *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + TypeidExp *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class TraitsExp : public Expression +class TraitsExp final : public Expression { public: Identifier *ident; Objects *args; - TraitsExp *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + TraitsExp *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class HaltExp : public Expression +class HaltExp final : public Expression { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class IsExp : public Expression +class IsExp final : public Expression { public: /* is(targ id tok tspec) @@ -674,8 +676,8 @@ public: TOK tok; // ':' or '==' TOK tok2; // 'struct', 'union', etc. - IsExp *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + IsExp *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ @@ -686,11 +688,11 @@ public: Expression *e1; Type *att1; // Save alias this type to detect recursion - UnaExp *syntaxCopy(); + UnaExp *syntaxCopy() override; Expression *incompatibleTypes(); - Expression *resolveLoc(const Loc &loc, Scope *sc); + Expression *resolveLoc(const Loc &loc, Scope *sc) override final; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; class BinExp : public Expression @@ -702,56 +704,56 @@ public: Type *att1; // Save alias this type to detect recursion Type *att2; // Save alias this type to detect recursion - BinExp *syntaxCopy(); + BinExp *syntaxCopy() override; Expression *incompatibleTypes(); Expression *reorderSettingAAElem(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; class BinAssignExp : public BinExp { public: - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *ex); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override final; + Expression *toLvalue(Scope *sc, Expression *ex) override final; + Expression *modifiableLvalue(Scope *sc, Expression *e) override final; + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ -class MixinExp : public UnaExp +class MixinExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ImportExp : public UnaExp +class ImportExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AssertExp : public UnaExp +class AssertExp final : public UnaExp { public: Expression *msg; - AssertExp *syntaxCopy(); + AssertExp *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ThrowExp : public UnaExp +class ThrowExp final : public UnaExp { public: - ThrowExp *syntaxCopy(); + ThrowExp *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DotIdExp : public UnaExp +class DotIdExp final : public UnaExp { public: Identifier *ident; @@ -760,44 +762,44 @@ public: bool arrow; // ImportC: if -> instead of . static DotIdExp *create(const Loc &loc, Expression *e, Identifier *ident); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DotTemplateExp : public UnaExp +class DotTemplateExp final : public UnaExp { public: TemplateDeclaration *td; - bool checkType(); - bool checkValue(); - void accept(Visitor *v) { v->visit(this); } + bool checkType() override; + bool checkValue() override; + void accept(Visitor *v) override { v->visit(this); } }; -class DotVarExp : public UnaExp +class DotVarExp final : public UnaExp { public: Declaration *var; bool hasOverloads; - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } }; -class DotTemplateInstanceExp : public UnaExp +class DotTemplateInstanceExp final : public UnaExp { public: TemplateInstance *ti; - DotTemplateInstanceExp *syntaxCopy(); + DotTemplateInstanceExp *syntaxCopy() override; bool findTempDecl(Scope *sc); - bool checkType(); - bool checkValue(); - void accept(Visitor *v) { v->visit(this); } + bool checkType() override; + bool checkValue() override; + void accept(Visitor *v) override { v->visit(this); } }; -class DelegateExp : public UnaExp +class DelegateExp final : public UnaExp { public: FuncDeclaration *func; @@ -805,18 +807,18 @@ public: VarDeclaration *vthis2; // container for multi-context - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DotTypeExp : public UnaExp +class DotTypeExp final : public UnaExp { public: Dsymbol *sym; // symbol that represents a type - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CallExp : public UnaExp +class CallExp final : public UnaExp { public: Expressions *arguments; // function arguments @@ -831,76 +833,76 @@ public: static CallExp *create(const Loc &loc, Expression *e, Expression *earg1); static CallExp *create(const Loc &loc, FuncDeclaration *fd, Expression *earg1); - CallExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *addDtorHook(Scope *sc); + CallExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *addDtorHook(Scope *sc) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AddrExp : public UnaExp +class AddrExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class PtrExp : public UnaExp +class PtrExp final : public UnaExp { public: - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class NegExp : public UnaExp +class NegExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class UAddExp : public UnaExp +class UAddExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ComExp : public UnaExp +class ComExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class NotExp : public UnaExp +class NotExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DeleteExp : public UnaExp +class DeleteExp final : public UnaExp { public: bool isRAII; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CastExp : public UnaExp +class CastExp final : public UnaExp { public: // Possible to cast to one type while painting to another type Type *to; // type to cast to unsigned char mod; // MODxxxxx - CastExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); + CastExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class VectorExp : public UnaExp +class VectorExp final : public UnaExp { public: TypeVector *to; // the target vector type before semantic() @@ -909,19 +911,19 @@ public: static VectorExp *create(const Loc &loc, Expression *e, Type *t); static void emplace(UnionExp *pue, const Loc &loc, Expression *e, Type *t); - VectorExp *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + VectorExp *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class VectorArrayExp : public UnaExp +class VectorArrayExp final : public UnaExp { public: - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } }; -class SliceExp : public UnaExp +class SliceExp final : public UnaExp { public: Expression *upr; // NULL if implicit 0 @@ -931,115 +933,115 @@ public: bool lowerIsLessThanUpper; // true if lwr <= upr bool arrayop; // an array operation, rather than a slice - SliceExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Optional<bool> toBool(); + SliceExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; + Optional<bool> toBool() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ArrayLengthExp : public UnaExp +class ArrayLengthExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class IntervalExp : public Expression +class IntervalExp final : public Expression { public: Expression *lwr; Expression *upr; - IntervalExp *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + IntervalExp *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class DelegatePtrExp : public UnaExp +class DelegatePtrExp final : public UnaExp { public: - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } }; -class DelegateFuncptrExp : public UnaExp +class DelegateFuncptrExp final : public UnaExp { public: - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; + void accept(Visitor *v) override { v->visit(this); } }; // e1[a0,a1,a2,a3,...] -class ArrayExp : public UnaExp +class ArrayExp final : public UnaExp { public: Expressions *arguments; // Array of Expression's size_t currentDimension; // for opDollar VarDeclaration *lengthVar; - ArrayExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); + ArrayExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ -class DotExp : public BinExp +class DotExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CommaExp : public BinExp +class CommaExp final : public BinExp { public: bool isGenerated; bool allowCommaExp; - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Optional<bool> toBool(); - Expression *addDtorHook(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; + Optional<bool> toBool() override; + Expression *addDtorHook(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class IndexExp : public BinExp +class IndexExp final : public BinExp { public: VarDeclaration *lengthVar; bool modifiable; bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1 - IndexExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); + IndexExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /* For both i++ and i-- */ -class PostExp : public BinExp +class PostExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /* For both ++i and --i */ -class PreExp : public UnaExp +class PreExp final : public UnaExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; enum class MemorySet @@ -1054,245 +1056,257 @@ class AssignExp : public BinExp public: MemorySet memset; - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *ex); + bool isLvalue() override final; + Expression *toLvalue(Scope *sc, Expression *ex) override final; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ConstructExp : public AssignExp +class ConstructExp final : public AssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class BlitExp : public AssignExp +class BlitExp final : public AssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AddAssignExp : public BinAssignExp +class AddAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class MinAssignExp : public BinAssignExp +class MinAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class MulAssignExp : public BinAssignExp +class MulAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DivAssignExp : public BinAssignExp +class DivAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ModAssignExp : public BinAssignExp +class ModAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AndAssignExp : public BinAssignExp +class AndAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class OrAssignExp : public BinAssignExp +class OrAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class XorAssignExp : public BinAssignExp +class XorAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class PowAssignExp : public BinAssignExp +class PowAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ShlAssignExp : public BinAssignExp +class ShlAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ShrAssignExp : public BinAssignExp +class ShrAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class UshrAssignExp : public BinAssignExp +class UshrAssignExp final : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; class CatAssignExp : public BinAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AddExp : public BinExp +class CatElemAssignExp final : public CatAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class MinExp : public BinExp +class CatDcharAssignExp final : public CatAssignExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CatExp : public BinExp +class AddExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class MulExp : public BinExp +class MinExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DivExp : public BinExp +class CatExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ModExp : public BinExp +class MulExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class PowExp : public BinExp +class DivExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ShlExp : public BinExp +class ModExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ShrExp : public BinExp +class PowExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class UshrExp : public BinExp +class ShlExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class AndExp : public BinExp +class ShrExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class OrExp : public BinExp +class UshrExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class XorExp : public BinExp +class AndExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class LogicalExp : public BinExp +class OrExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CmpExp : public BinExp +class XorExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class InExp : public BinExp +class LogicalExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class RemoveExp : public BinExp +class CmpExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } +}; + +class InExp final : public BinExp +{ +public: + void accept(Visitor *v) override { v->visit(this); } +}; + +class RemoveExp final : public BinExp +{ +public: + void accept(Visitor *v) override { v->visit(this); } }; // == and != -class EqualExp : public BinExp +class EqualExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // is and !is -class IdentityExp : public BinExp +class IdentityExp final : public BinExp { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ -class CondExp : public BinExp +class CondExp final : public BinExp { public: Expression *econd; - CondExp *syntaxCopy(); - bool isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); + CondExp *syntaxCopy() override; + bool isLvalue() override; + Expression *toLvalue(Scope *sc, Expression *e) override; + Expression *modifiableLvalue(Scope *sc, Expression *e) override; void hookDtors(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class GenericExp : Expression +class GenericExp final : Expression { Expression *cntlExp; Types *types; Expressions *exps; - GenericExp *syntaxCopy(); + GenericExp *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ @@ -1300,42 +1314,42 @@ class GenericExp : Expression class DefaultInitExp : public Expression { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class FileInitExp : public DefaultInitExp +class FileInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc); - void accept(Visitor *v) { v->visit(this); } + Expression *resolveLoc(const Loc &loc, Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class LineInitExp : public DefaultInitExp +class LineInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc); - void accept(Visitor *v) { v->visit(this); } + Expression *resolveLoc(const Loc &loc, Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class ModuleInitExp : public DefaultInitExp +class ModuleInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc); - void accept(Visitor *v) { v->visit(this); } + Expression *resolveLoc(const Loc &loc, Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class FuncInitExp : public DefaultInitExp +class FuncInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc); - void accept(Visitor *v) { v->visit(this); } + Expression *resolveLoc(const Loc &loc, Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class PrettyFuncInitExp : public DefaultInitExp +class PrettyFuncInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc); - void accept(Visitor *v) { v->visit(this); } + Expression *resolveLoc(const Loc &loc, Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; /****************************************************************/ @@ -1396,10 +1410,10 @@ private: /****************************************************************/ -class ObjcClassReferenceExp : public Expression +class ObjcClassReferenceExp final : public Expression { public: ClassDeclaration* classDeclaration; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index b65b0ed..cb72027 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -4989,7 +4989,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } - if (tf.trust <= TRUST.system && sc.func.setUnsafe()) + if (tf.trust <= TRUST.system && sc.setUnsafe()) { exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); @@ -5995,7 +5995,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto idxReserved = FileName.findReservedChar(namez); if (idxReserved != size_t.max) { - e.error("`%s` is not a valid filename on this platform", se.toChars()); + e.error("`%s` is not a valid filename on this platform", se.toChars()); e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]); return setError(); } @@ -6543,8 +6543,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor RootObject o = (*tup.objects)[i]; Expression e; Declaration var; - if (o.dyncast() == DYNCAST.expression) + switch (o.dyncast()) with (DYNCAST) { + case expression: e = cast(Expression)o; if (auto se = e.isDsymbolExp()) var = se.s.isDeclaration(); @@ -6553,9 +6554,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Exempt functions for backwards compatibility reasons. // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 var = ve.var; - } - else if (o.dyncast() == DYNCAST.dsymbol) - { + break; + case dsymbol: Dsymbol s = cast(Dsymbol) o; Declaration d = s.isDeclaration(); if (!d || d.isFuncDeclaration()) @@ -6564,13 +6564,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e = new DsymbolExp(exp.loc, s); else var = d; - } - else if (o.dyncast() == DYNCAST.type) - { + break; + case type: e = new TypeExp(exp.loc, cast(Type)o); - } - else - { + break; + default: exp.error("`%s` is not an expression", o.toChars()); return setError(); } @@ -6894,9 +6892,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * because it might end up being a pointer to undefined * memory. */ - if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) + if (1) { - if (sc.func.setUnsafe(false, exp.loc, + if (sc.setUnsafe(false, exp.loc, "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func)) { setError(); @@ -7045,7 +7043,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) { - sc.func.setUnsafe(false, exp.loc, + sc.setUnsafe(false, exp.loc, "`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f, sc.func); } @@ -7552,10 +7550,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Check for unsafe casts - if (!sc.intypeof && - !(sc.flags & SCOPE.debug_) && - !isSafeCast(ex, t1b, tob) && - (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe())) + if (!isSafeCast(ex, t1b, tob) && + (!sc.func && sc.stc & STC.safe || sc.setUnsafe())) { exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); return setError(); @@ -7816,11 +7812,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) - { - if (sc.func.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions")) - return setError(); - } + if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions")) + return setError(); } else if (t1b.ty == Tarray) { @@ -8328,11 +8321,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0) { } - else if (sc.func && !(sc.flags & SCOPE.debug_)) + else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1)) { - if (sc.func.setUnsafe(false, exp.loc, - "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1)) - return setError(); + return setError(); } exp.type = (cast(TypeNext)t1b).next; break; @@ -9729,11 +9720,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) { - if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_)) - { - if (sc.func.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code")) - return setError(); - } + if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code")) + return setError(); } } else @@ -13089,9 +13077,8 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) v.storage_class &= ~STC.maybescope; v.doNotInferScope = true; if (global.params.useDIP1000 != FeatureState.enabled && - !(sc.flags & SCOPE.debug_) && !(v.storage_class & STC.temp) && - sc.func.setUnsafe()) + sc.setUnsafe()) { exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); return false; @@ -13304,7 +13291,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions { if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize || (v.offset & (target.ptrsize - 1))) && - (sc.func && sc.func.setUnsafe(false, loc, + (sc.setUnsafe(false, loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v))) { return false; diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index e53a540..0403948 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -346,7 +346,7 @@ extern (C++) class FuncDeclaration : Declaration /// In case of failed `@safe` inference, store the error that made the function `@system` for /// better diagnostics - private AttributeViolation* safetyViolation; + AttributeViolation* safetyViolation; /// Function flags: A collection of boolean packed for memory efficiency /// See the `FUNCFLAG` enum @@ -713,6 +713,44 @@ extern (C++) class FuncDeclaration : Declaration } } } + 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(); @@ -1447,7 +1485,7 @@ extern (C++) class FuncDeclaration : Declaration { flags &= ~FUNCFLAG.safetyInprocess; type.toTypeFunction().trust = TRUST.system; - if (!gag && !safetyViolation && (fmt || arg0)) + if (fmt || arg0) safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1); if (fes) @@ -4321,6 +4359,50 @@ extern (C++) final class NewDeclaration : FuncDeclaration } } +/************************************** + * A statement / expression in this scope is not `@safe`, + * so mark the enclosing function as `@system` + * + * Params: + * sc = scope that the unsafe statement / expression is in + * gag = surpress error message (used in escape.d) + * loc = location of error + * fmt = printf-style format string + * arg0 = (optional) argument for first %s format specifier + * arg1 = (optional) argument for second %s format specifier + * Returns: whether there's a safe error + */ +bool setUnsafe(Scope* sc, + bool gag = false, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null, RootObject arg1 = null) +{ + // TODO: + // For @system variables, unsafe initializers at global scope should mark + // the variable @system, see https://dlang.org/dips/1035 + + if (!sc.func) + return false; + + if (sc.intypeof) + return false; // typeof(cast(int*)0) is safe + + if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive + return false; + + if (sc.flags & SCOPE.compile) // __traits(compiles, x) + { + if (sc.func.isSafeBypassingInference()) + { + // Message wil be gagged, but still call error() to update global.errors and for + // -verrors=spec + .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : ""); + return true; + } + return false; + } + + return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1); +} + /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure` /// /// Has two modes: @@ -4329,7 +4411,7 @@ extern (C++) final class NewDeclaration : FuncDeclaration /// that function might recursively also have a `AttributeViolation`. This way, in case /// of a big call stack, the error can go down all the way to the root cause. /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`. -private struct AttributeViolation +struct AttributeViolation { /// location of error Loc loc = Loc.init; @@ -4345,21 +4427,25 @@ private struct AttributeViolation /// Params: /// fd = function to check /// maxDepth = up to how many functions deep to report errors -void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth) +/// deprecation = print deprecations instead of errors +void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool deprecation) { + auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental; if (auto s = fd.safetyViolation) { if (s.fmtStr) { - errorSupplemental(s.loc, "which was inferred `@system` because of:"); - errorSupplemental(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : ""); + errorFunc(s.loc, deprecation ? + "which would be `@system` because of:" : + "which was inferred `@system` because of:"); + errorFunc(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : ""); } else if (FuncDeclaration fd2 = cast(FuncDeclaration) s.arg0) { if (maxDepth > 0) { - errorSupplemental(s.loc, "which calls `%s`", fd2.toPrettyChars()); - errorSupplementalInferredSafety(fd2, maxDepth - 1); + errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars()); + errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation); } } } diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index ba4ccbe..3766a0b 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -118,6 +118,7 @@ extern (C++) struct Param bool useInline = false; // inline expand functions FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params + bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070 bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md bool release; // build release version bool preservePaths; // true means don't strip path from source file @@ -298,7 +299,7 @@ extern (C++) struct Global enum recursionLimit = 500; /// number of recursive template expansions before abort - extern (C++) FileName function(FileName, const(char)* importc_h, ref Array!(const(char)*) cppswitches, out bool) preprocess; + extern (C++) FileName function(FileName, ref const Loc, ref Array!(const(char)*) cppswitches, out bool, OutBuffer* defines) preprocess; nothrow: diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 5c164fd..07298dd 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -20,6 +20,7 @@ template <typename TYPE> struct Array; class FileManager; +struct Loc; typedef unsigned char Diagnostic; enum @@ -117,6 +118,7 @@ struct Param bool useInline; // inline expand functions FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params + bool fixImmutableConv; bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md bool release; // build release version bool preservePaths; // true means don't strip path from source file @@ -270,7 +272,7 @@ struct Global FileManager* fileManager; - FileName (*preprocess)(FileName, const char*, Array<const char *>& cppswitches, bool&); + FileName (*preprocess)(FileName, const Loc&, Array<const char *>& cppswitches, bool&, OutBuffer&); /* Start gagging. Return the current number of gagged errors */ diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index fd35e1c..fcc9b61 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -3835,26 +3835,24 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs) { foreach (id; t.idents) { - if (id.dyncast() == DYNCAST.dsymbol) + switch (id.dyncast()) with (DYNCAST) { + case dsymbol: buf.writeByte('.'); TemplateInstance ti = cast(TemplateInstance)id; ti.dsymbolToBuffer(buf, hgs); - } - else if (id.dyncast() == DYNCAST.expression) - { + break; + case expression: buf.writeByte('['); (cast(Expression)id).expressionToBuffer(buf, hgs); buf.writeByte(']'); - } - else if (id.dyncast() == DYNCAST.type) - { + break; + case type: buf.writeByte('['); typeToBufferx(cast(Type)id, buf, hgs); buf.writeByte(']'); - } - else - { + break; + default: buf.writeByte('.'); buf.writestring(id.toString()); } diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index ab9528a..4993a9e 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -523,6 +523,8 @@ immutable Msgtable[] msgtable = { "show" }, { "push" }, { "pop" }, + { "define" }, + { "undef" }, ]; diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h index 4c748be..fa7a25a 100644 --- a/gcc/d/dmd/identifier.h +++ b/gcc/d/dmd/identifier.h @@ -13,7 +13,7 @@ #include "root/dcompat.h" #include "root/object.h" -class Identifier : public RootObject +class Identifier final : public RootObject { private: int value; @@ -22,12 +22,11 @@ private: public: static Identifier* create(const char *string); - bool equals(const RootObject *o) const; - const char *toChars() const; + const char *toChars() const override; int getValue() const; bool isAnonymous() const; const char *toHChars2() const; - DYNCAST dyncast() const; + DYNCAST dyncast() const override; static Identifier *generateId(const char *prefix, size_t length, size_t suffix); static Identifier *idPool(const char *s, unsigned len); diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index 5e7550e..f749ef5 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -17,7 +17,7 @@ struct Scope; class Module; class Package; -class Import : public Dsymbol +class Import final : public Dsymbol { public: /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2; @@ -38,17 +38,17 @@ public: AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs - const char *kind() const; - Visibility visible(); - Import *syntaxCopy(Dsymbol *s); // copy only syntax trees + const char *kind() const override; + Visibility visible() override; + Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees void load(Scope *sc); - void importAll(Scope *sc); - Dsymbol *toAlias(); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope* sc); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); - bool overloadInsert(Dsymbol *s); - - Import *isImport() { return this; } - void accept(Visitor *v) { v->visit(this); } + void importAll(Scope *sc) override; + Dsymbol *toAlias() override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void setScope(Scope* sc) override; + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; + bool overloadInsert(Dsymbol *s) override; + + Import *isImport() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index 179e0b6..164a5f3 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -44,7 +44,7 @@ extern (C++) class Initializer : ASTNode Loc loc; InitKind kind; - override DYNCAST dyncast() const nothrow pure + override DYNCAST dyncast() const { return DYNCAST.initializer; } diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 73dc4bb..296c31d 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -33,7 +33,9 @@ public: Loc loc; unsigned char kind; - const char *toChars() const; + DYNCAST dyncast() const override { return DYNCAST_INITIALIZER; } + + const char *toChars() const override final; ErrorInitializer *isErrorInitializer(); VoidInitializer *isVoidInitializer(); @@ -42,33 +44,33 @@ public: ExpInitializer *isExpInitializer(); CInitializer *isCInitializer(); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class VoidInitializer : public Initializer +class VoidInitializer final : public Initializer { public: Type *type; // type that this will initialize to - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ErrorInitializer : public Initializer +class ErrorInitializer final : public Initializer { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class StructInitializer : public Initializer +class StructInitializer final : public Initializer { public: Identifiers field; // of Identifier *'s Initializers value; // parallel array of Initializer *'s - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ArrayInitializer : public Initializer +class ArrayInitializer final : public Initializer { public: Expressions index; // indices @@ -80,16 +82,16 @@ public: bool isAssociativeArray() const; Expression *toAssocArrayLiteral(); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ExpInitializer : public Initializer +class ExpInitializer final : public Initializer { public: bool expandTuples; Expression *exp; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; struct Designator @@ -104,14 +106,14 @@ struct DesigInit Initializer *initializer; }; -class CInitializer : public Initializer +class CInitializer final : public Initializer { public: DesigInits initializerList; Type *type; // type that array will be used to initialize bool sem; // true if semantic() is run - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false); diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 2cddd28..a1963da 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -197,10 +197,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (vd.type.hasPointers) { if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize || - (vd.offset & (target.ptrsize - 1))) && - sc.func) + (vd.offset & (target.ptrsize - 1)))) { - if (sc.func.setUnsafe(false, i.value[j].loc, + if (sc.setUnsafe(false, i.value[j].loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd)) { errors = true; diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 5945da3..ef918e2 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -146,6 +146,36 @@ class Lexer } } + /****************** + * Used for unittests for a mock Lexer + */ + this() { } + + /************************************** + * Reset lexer to lex #define's + */ + final void resetDefineLines(const(char)[] slice) + { + base = slice.ptr; + end = base + slice.length; + assert(*end == 0); + p = base; + line = p; + tokenizeNewlines = true; + inTokenStringConstant = 0; + lastDocLine = 0; + scanloc = Loc("#defines", 1, 1); + } + + /********************************** + * Set up for next #define line. + * p should be at start of next line. + */ + final void nextDefineLine() + { + tokenizeNewlines = true; + } + version (DMDLIB) { this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, @@ -1184,7 +1214,7 @@ class Lexer * Returns: * the escape sequence as a single character */ - private static dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile) + private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile) { const(char)* p = sequence; // cache sequence reference on stack scope(exit) sequence = p; @@ -1268,13 +1298,13 @@ class Lexer break; if (!ishex(cast(char)c)) { - .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); + error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); break; } } if (ndigits != 2 && !utf_isValidDchar(v)) { - .error(loc, "invalid UTF character \\U%08x", v); + error(loc, "invalid UTF character \\U%08x", v); v = '?'; // recover with valid UTF character } } @@ -1282,7 +1312,7 @@ class Lexer } else { - .error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); + error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); p++; } break; @@ -1299,7 +1329,7 @@ class Lexer c = HtmlNamedEntity(idstart, p - idstart); if (c == ~0) { - .error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); + error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); c = '?'; } p++; @@ -1307,7 +1337,7 @@ class Lexer default: if (isalpha(*p) || (p != idstart && isdigit(*p))) continue; - .error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); + error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); c = '?'; break; } @@ -1332,11 +1362,11 @@ class Lexer while (++n < 3 && isoctal(cast(char)c)); c = v; if (c > 0xFF) - .error(loc, "escape octal sequence \\%03o is larger than \\377", c); + error(loc, "escape octal sequence \\%03o is larger than \\377", c); } else { - .error(loc, "undefined escape sequence \\%c", c); + error(loc, "undefined escape sequence \\%c", c); p++; } break; @@ -2732,8 +2762,10 @@ class Lexer /*************************************** * Scan forward to start of next line. + * Params: + * defines = send characters to `defines` */ - final void skipToNextLine() + final void skipToNextLine(OutBuffer* defines = null) { while (1) { @@ -2754,7 +2786,9 @@ class Lexer break; default: - if (*p & 0x80) + if (defines) + defines.writeByte(*p); // don't care about Unicode line endings for C + else if (*p & 0x80) { const u = decodeUTF(); if (u == PS || u == LS) @@ -3146,7 +3180,8 @@ unittest static void test(T)(string sequence, T expected, bool Ccompile = false) { auto p = cast(const(char)*)sequence.ptr; - assert(expected == Lexer.escapeSequence(Loc.initial, p, Ccompile)); + Lexer lexer = new Lexer(); + assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile)); assert(p == sequence.ptr + sequence.length); } @@ -3212,7 +3247,8 @@ unittest gotError = false; expected = expectedError; auto p = cast(const(char)*)sequence.ptr; - auto actualReturnValue = Lexer.escapeSequence(Loc.initial, p, Ccompile); + Lexer lexer = new Lexer(); + auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile); assert(gotError); assert(expectedReturnValue == actualReturnValue); diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 048b3a0..5808c28 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -35,21 +35,21 @@ public: unsigned tag; // auto incremented tag, used to mask package tree in scopes Module *mod; // != NULL if isPkgMod == PKGmodule - const char *kind() const; + const char *kind() const override; - bool equals(const RootObject *o) const; + bool equals(const RootObject *o) const override; - Package *isPackage() { return this; } + Package *isPackage() override final { return this; } bool isAncestorPackageOf(const Package * const pkg) const; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); - void accept(Visitor *v) { v->visit(this); } + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; + void accept(Visitor *v) override { v->visit(this); } Module *isPackageMod(); }; -class Module : public Package +class Module final : public Package { public: static Module *rootModule; @@ -82,6 +82,7 @@ public: int needmoduleinfo; int selfimports; // 0: don't know, 1: does not, 2: does void* tagSymTab; // ImportC: tag symbols that conflict with other symbols used as the index + OutBuffer defines; // collect all the #define lines here bool selfImports(); // returns true if module imports itself int rootimports; // 0: don't know, 1: does not, 2: does @@ -119,14 +120,14 @@ public: static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident); - const char *kind() const; + 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); + void importAll(Scope *sc) override; int needModuleInfo(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); - bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0); - Dsymbol *symtabInsert(Dsymbol *s); + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; + bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override; + Dsymbol *symtabInsert(Dsymbol *s) override; void deleteObjFile(); static void runDeferredSemantic(); static void runDeferredSemantic2(); @@ -155,8 +156,8 @@ public: void *ctfe_cov; // stores coverage information from ctfe - Module *isModule() { return this; } - void accept(Visitor *v) { v->visit(this); } + Module *isModule() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index be17ab3..052c23d 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -525,10 +525,12 @@ extern (C++) abstract class Type : ASTNode * 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) + extern (D) + final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false) { version (none) { @@ -563,11 +565,11 @@ extern (C++) abstract class Type : ASTNode foreach (i, fparam1; t1.parameterList) { Parameter fparam2 = t2.parameterList[i]; + Type tp1 = fparam1.type; + Type tp2 = fparam2.type; - if (!fparam1.type.equals(fparam2.type)) + if (!tp1.equals(tp2)) { - Type tp1 = fparam1.type; - Type tp2 = fparam2.type; if (tp1.ty == tp2.ty) { if (auto tc1 = tp1.isTypeClass()) @@ -600,6 +602,16 @@ extern (C++) abstract class Type : ASTNode } 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) @@ -701,6 +713,12 @@ extern (C++) abstract class Type : ASTNode 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)) @@ -3237,7 +3255,7 @@ extern (C++) final class TypeBasic : Type return this; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { uint size; //printf("TypeBasic::size()\n"); @@ -3325,32 +3343,32 @@ extern (C++) final class TypeBasic : Type return (flags & TFlags.integral) != 0; } - override bool isfloating() const + override bool isfloating() { return (flags & TFlags.floating) != 0; } - override bool isreal() const + override bool isreal() { return (flags & TFlags.real_) != 0; } - override bool isimaginary() const + override bool isimaginary() { return (flags & TFlags.imaginary) != 0; } - override bool iscomplex() const + override bool iscomplex() { return (flags & TFlags.complex) != 0; } - override bool isscalar() const + override bool isscalar() { return (flags & (TFlags.integral | TFlags.floating)) != 0; } - override bool isunsigned() const + override bool isunsigned() { return (flags & TFlags.unsigned) != 0; } @@ -3447,7 +3465,7 @@ extern (C++) final class TypeBasic : Type return MATCH.convert; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { switch (ty) { @@ -3543,7 +3561,7 @@ extern (C++) final class TypeVector : Type return basetype.nextOf().isunsigned(); } - override bool isBoolean() const + override bool isBoolean() { return false; } @@ -3860,13 +3878,13 @@ extern (C++) final class TypeDArray : TypeArray return result; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { //printf("TypeDArray::size()\n"); return target.ptrsize * 2; } - override uint alignsize() const + override uint alignsize() { // A DArray consists of two ptr-sized values, so align it on pointer size // boundary @@ -3879,12 +3897,12 @@ extern (C++) final class TypeDArray : TypeArray return nty.isSomeChar; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { return true; } - override bool isBoolean() const + override bool isBoolean() { return true; } @@ -3918,7 +3936,7 @@ extern (C++) final class TypeDArray : TypeArray return Type.implicitConvTo(to); } - override bool hasPointers() const + override bool hasPointers() { return true; } @@ -3964,22 +3982,22 @@ extern (C++) final class TypeAArray : TypeArray return result; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return target.ptrsize; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { return true; } - override bool isBoolean() const + override bool isBoolean() { return true; } - override bool hasPointers() const + override bool hasPointers() { return true; } @@ -4056,7 +4074,7 @@ extern (C++) final class TypePointer : TypeNext return result; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return target.ptrsize; } @@ -4112,17 +4130,17 @@ extern (C++) final class TypePointer : TypeNext return TypeNext.constConv(to); } - override bool isscalar() const + override bool isscalar() { return true; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { return true; } - override bool hasPointers() const + override bool hasPointers() { return true; } @@ -4159,12 +4177,12 @@ extern (C++) final class TypeReference : TypeNext return result; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return target.ptrsize; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { return true; } @@ -4760,7 +4778,7 @@ extern (C++) final class TypeFunction : TypeNext char[] s; if (!f.isPure && sc.func.setImpure()) s ~= "pure "; - if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe()) + if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) s ~= "@safe "; if (!f.isNogc && sc.func.setGC()) s ~= "nogc "; @@ -5156,12 +5174,12 @@ extern (C++) final class TypeDelegate : TypeNext return t; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return target.ptrsize * 2; } - override uint alignsize() const + override uint alignsize() { return target.ptrsize; } @@ -5189,17 +5207,17 @@ extern (C++) final class TypeDelegate : TypeNext return MATCH.nomatch; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { return true; } - override bool isBoolean() const + override bool isBoolean() { return true; } - override bool hasPointers() const + override bool hasPointers() { return true; } @@ -5748,12 +5766,12 @@ extern (C++) final class TypeStruct : Type return assignable; } - override bool isBoolean() const + override bool isBoolean() { return false; } - override bool needsDestruction() const + override bool needsDestruction() { return sym.dtor !is null; } @@ -5985,6 +6003,7 @@ extern (C++) final class TypeEnum : Type { return sym.getMemtype(loc); } + override uint alignsize() { Type t = memType(); @@ -6143,7 +6162,7 @@ extern (C++) final class TypeClass : Type return "class"; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return target.ptrsize; } @@ -6268,22 +6287,22 @@ extern (C++) final class TypeClass : Type return this; } - override bool isZeroInit(const ref Loc loc) const + override bool isZeroInit(const ref Loc loc) { return true; } - override bool isscope() const + override bool isscope() { return sym.stack; } - override bool isBoolean() const + override bool isBoolean() { return true; } - override bool hasPointers() const + override bool hasPointers() { return true; } @@ -6538,12 +6557,12 @@ extern (C++) final class TypeNull : Type return true; } - override bool isBoolean() const + override bool isBoolean() { return true; } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return tvoidptr.size(loc); } @@ -6597,12 +6616,12 @@ extern (C++) final class TypeNoreturn : Type return this.implicitConvTo(to); } - override bool isBoolean() const + override bool isBoolean() { return true; // bottom type can be implicitly converted to any other type } - override uinteger_t size(const ref Loc loc) const + override uinteger_t size(const ref Loc loc) { return 0; } diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index d2b1364..3565913 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -119,14 +119,6 @@ enum MODFlags }; typedef unsigned char MOD; -enum class Covariant -{ - distinct = 0, - yes = 1, - no = 2, - fwdref = 3, -}; - enum VarArgValues { VARARGnone = 0, /// fixed number of arguments @@ -221,13 +213,12 @@ public: virtual const char *kind(); Type *copy() const; virtual Type *syntaxCopy(); - bool equals(const RootObject *o) const; + bool equals(const RootObject *o) const override; bool equivalent(Type *t); // kludge for template.isType() - DYNCAST dyncast() const { return DYNCAST_TYPE; } + DYNCAST dyncast() const override final { return DYNCAST_TYPE; } size_t getUniqueID() const; - Covariant covariant(Type *t, StorageClass *pstc = NULL); - const char *toChars() const; + const char *toChars() const override; char *toPrettyChars(bool QualifyTypes = false); static void _init(); @@ -306,7 +297,7 @@ public: virtual ClassDeclaration *isClassHandle(); virtual structalign_t alignment(); virtual Expression *defaultInitLiteral(const Loc &loc); - virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 + virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0 Identifier *getTypeInfoIdent(); virtual int hasWild() const; virtual bool hasPointers(); @@ -349,18 +340,18 @@ public: TypeNoreturn *isTypeNoreturn(); TypeTag *isTypeTag(); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeError : public Type +class TypeError final : public Type { public: - const char *kind(); - TypeError *syntaxCopy(); + const char *kind() override; + TypeError *syntaxCopy() override; - uinteger_t size(const Loc &loc); - Expression *defaultInitLiteral(const Loc &loc); - void accept(Visitor *v) { v->visit(this); } + uinteger_t size(const Loc &loc) override; + Expression *defaultInitLiteral(const Loc &loc) override; + void accept(Visitor *v) override { v->visit(this); } }; class TypeNext : public Type @@ -368,164 +359,164 @@ class TypeNext : public Type public: Type *next; - void checkDeprecated(const Loc &loc, Scope *sc); - int hasWild() const; - Type *nextOf(); - Type *makeConst(); - Type *makeImmutable(); - Type *makeShared(); - Type *makeSharedConst(); - Type *makeWild(); - Type *makeWildConst(); - Type *makeSharedWild(); - Type *makeSharedWildConst(); - Type *makeMutable(); - MATCH constConv(Type *to); - unsigned char deduceWild(Type *t, bool isRef); + void checkDeprecated(const Loc &loc, Scope *sc) override final; + int hasWild() const override final; + Type *nextOf() override final; + Type *makeConst() override final; + Type *makeImmutable() override final; + Type *makeShared() override final; + Type *makeSharedConst() override final; + Type *makeWild() override final; + Type *makeWildConst() override final; + Type *makeSharedWild() override final; + Type *makeSharedWildConst() override final; + Type *makeMutable() override final; + MATCH constConv(Type *to) override; + unsigned char deduceWild(Type *t, bool isRef) override final; void transitive(); - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeBasic : public Type +class TypeBasic final : public Type { public: const char *dstring; unsigned flags; - const char *kind(); - TypeBasic *syntaxCopy(); - uinteger_t size(const Loc &loc) /*const*/; - unsigned alignsize(); - bool isintegral(); - bool isfloating() /*const*/; - bool isreal() /*const*/; - bool isimaginary() /*const*/; - bool iscomplex() /*const*/; - bool isscalar() /*const*/; - bool isunsigned() /*const*/; - MATCH implicitConvTo(Type *to); - bool isZeroInit(const Loc &loc) /*const*/; + const char *kind() override; + TypeBasic *syntaxCopy() override; + uinteger_t size(const Loc &loc) override; + unsigned alignsize() override; + bool isintegral() override; + bool isfloating() override; + bool isreal() override; + bool isimaginary() override; + bool iscomplex() override; + bool isscalar() override; + bool isunsigned() override; + MATCH implicitConvTo(Type *to) override; + bool isZeroInit(const Loc &loc) override; // For eliminating dynamic_cast - TypeBasic *isTypeBasic(); - void accept(Visitor *v) { v->visit(this); } + TypeBasic *isTypeBasic() override; + void accept(Visitor *v) override { v->visit(this); } }; -class TypeVector : public Type +class TypeVector final : public Type { public: Type *basetype; static TypeVector *create(Type *basetype); - const char *kind(); - TypeVector *syntaxCopy(); - uinteger_t size(const Loc &loc); - unsigned alignsize(); - bool isintegral(); - bool isfloating(); - bool isscalar(); - bool isunsigned(); - bool isBoolean() /*const*/; - MATCH implicitConvTo(Type *to); - Expression *defaultInitLiteral(const Loc &loc); + const char *kind() override; + TypeVector *syntaxCopy() override; + uinteger_t size(const Loc &loc) override; + unsigned alignsize() override; + bool isintegral() override; + bool isfloating() override; + bool isscalar() override; + bool isunsigned() override; + bool isBoolean() override; + MATCH implicitConvTo(Type *to) override; + Expression *defaultInitLiteral(const Loc &loc) override; TypeBasic *elementType(); - bool isZeroInit(const Loc &loc); + bool isZeroInit(const Loc &loc) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; class TypeArray : public TypeNext { public: - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; // Static array, one with a fixed dimension -class TypeSArray : public TypeArray +class TypeSArray final : public TypeArray { public: Expression *dim; - const char *kind(); - TypeSArray *syntaxCopy(); + const char *kind() override; + TypeSArray *syntaxCopy() override; bool isIncomplete(); - uinteger_t size(const Loc &loc); - unsigned alignsize(); - bool isString(); - bool isZeroInit(const Loc &loc); - structalign_t alignment(); - MATCH constConv(Type *to); - MATCH implicitConvTo(Type *to); - Expression *defaultInitLiteral(const Loc &loc); - bool hasPointers(); - bool hasInvariant(); - bool needsDestruction(); - bool needsCopyOrPostblit(); - bool needsNested(); - - void accept(Visitor *v) { v->visit(this); } + uinteger_t size(const Loc &loc) override; + unsigned alignsize() override; + bool isString() override; + bool isZeroInit(const Loc &loc) override; + structalign_t alignment() override; + MATCH constConv(Type *to) override; + MATCH implicitConvTo(Type *to) override; + Expression *defaultInitLiteral(const Loc &loc) override; + bool hasPointers() override; + bool hasInvariant() override; + bool needsDestruction() override; + bool needsCopyOrPostblit() override; + bool needsNested() override; + + void accept(Visitor *v) override { v->visit(this); } }; // Dynamic array, no dimension -class TypeDArray : public TypeArray +class TypeDArray final : public TypeArray { public: - const char *kind(); - TypeDArray *syntaxCopy(); - uinteger_t size(const Loc &loc) /*const*/; - unsigned alignsize() /*const*/; - bool isString(); - bool isZeroInit(const Loc &loc) /*const*/; - bool isBoolean() /*const*/; - MATCH implicitConvTo(Type *to); - bool hasPointers() /*const*/; + const char *kind() override; + TypeDArray *syntaxCopy() override; + uinteger_t size(const Loc &loc) override; + unsigned alignsize() override; + bool isString() override; + bool isZeroInit(const Loc &loc) override; + bool isBoolean() override; + MATCH implicitConvTo(Type *to) override; + bool hasPointers() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeAArray : public TypeArray +class TypeAArray final : public TypeArray { public: Type *index; // key type Loc loc; static TypeAArray *create(Type *t, Type *index); - const char *kind(); - TypeAArray *syntaxCopy(); - uinteger_t size(const Loc &loc); - bool isZeroInit(const Loc &loc) /*const*/; - bool isBoolean() /*const*/; - bool hasPointers() /*const*/; - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); + const char *kind() override; + TypeAArray *syntaxCopy() override; + 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; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypePointer : public TypeNext +class TypePointer final : public TypeNext { public: static TypePointer *create(Type *t); - const char *kind(); - TypePointer *syntaxCopy(); - uinteger_t size(const Loc &loc) /*const*/; - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - bool isscalar() /*const*/; - bool isZeroInit(const Loc &loc) /*const*/; - bool hasPointers() /*const*/; + const char *kind() override; + TypePointer *syntaxCopy() override; + uinteger_t size(const Loc &loc) override; + MATCH implicitConvTo(Type *to) override; + MATCH constConv(Type *to) override; + bool isscalar() override; + bool isZeroInit(const Loc &loc) override; + bool hasPointers() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeReference : public TypeNext +class TypeReference final : public TypeNext { public: - const char *kind(); - TypeReference *syntaxCopy(); - uinteger_t size(const Loc &loc) /*const*/; - bool isZeroInit(const Loc &loc) /*const*/; - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeReference *syntaxCopy() override; + uinteger_t size(const Loc &loc) override; + bool isZeroInit(const Loc &loc) override; + void accept(Visitor *v) override { v->visit(this); } }; enum RET @@ -556,7 +547,7 @@ enum class PURE : unsigned char const_ = 3, // parameters are values or const }; -class Parameter : public ASTNode +class Parameter final : public ASTNode { public: StorageClass storageClass; @@ -570,12 +561,12 @@ public: Parameter *syntaxCopy(); Type *isLazyArray(); // kludge for template.isType() - DYNCAST dyncast() const { return DYNCAST_PARAMETER; } - void accept(Visitor *v) { v->visit(this); } + DYNCAST dyncast() const override { return DYNCAST_PARAMETER; } + void accept(Visitor *v) override { v->visit(this); } static size_t dim(Parameters *parameters); static Parameter *getNth(Parameters *parameters, d_size_t nth); - const char *toChars() const; + const char *toChars() const override; bool isCovariant(bool returnByRef, const Parameter *p, bool previewIn) const; }; @@ -590,7 +581,7 @@ struct ParameterList Parameter *operator[](size_t i) { return Parameter::getNth(parameters, i); } }; -class TypeFunction : public TypeNext +class TypeFunction final : public TypeNext { public: // .next is the return type @@ -604,16 +595,16 @@ public: Expressions *fargs; // function arguments static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0); - const char *kind(); - TypeFunction *syntaxCopy(); + const char *kind() override; + TypeFunction *syntaxCopy() override; void purityLevel(); bool hasLazyParameters(); bool isDstyleVariadic() const; StorageClass parameterStorageClass(Parameter *p); - Type *addStorageClass(StorageClass stc); + Type *addStorageClass(StorageClass stc) override; - Type *substWildTo(unsigned mod); - MATCH constConv(Type *to); + Type *substWildTo(unsigned mod) override; + MATCH constConv(Type *to) override; bool isnothrow() const; void isnothrow(bool v); @@ -643,29 +634,29 @@ public: void isInOutQual(bool v); bool iswild() const; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeDelegate : public TypeNext +class TypeDelegate final : public TypeNext { public: // .next is a TypeFunction static TypeDelegate *create(TypeFunction *t); - const char *kind(); - TypeDelegate *syntaxCopy(); - Type *addStorageClass(StorageClass stc); - uinteger_t size(const Loc &loc) /*const*/; - unsigned alignsize() /*const*/; - MATCH implicitConvTo(Type *to); - bool isZeroInit(const Loc &loc) /*const*/; - bool isBoolean() /*const*/; - bool hasPointers() /*const*/; + const char *kind() override; + TypeDelegate *syntaxCopy() override; + Type *addStorageClass(StorageClass stc) override; + uinteger_t size(const Loc &loc) override; + unsigned alignsize() override; + MATCH implicitConvTo(Type *to) override; + bool isZeroInit(const Loc &loc) override; + bool isBoolean() override; + bool hasPointers() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeTraits : public Type +class TypeTraits final : public Type { Loc loc; /// The expression to resolve as type or symbol. @@ -673,23 +664,23 @@ class TypeTraits : public Type /// Cached type/symbol after semantic analysis. RootObject *obj; - const char *kind(); - TypeTraits *syntaxCopy(); - uinteger_t size(const Loc &loc); - Dsymbol *toDsymbol(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + 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); } }; -class TypeMixin : public Type +class TypeMixin final : public Type { Loc loc; Expressions *exps; RootObject *obj; - const char *kind(); - TypeMixin *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeMixin *syntaxCopy() override; + Dsymbol *toDsymbol(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; class TypeQualified : public Type @@ -704,57 +695,57 @@ public: void addIdent(Identifier *ident); void addInst(TemplateInstance *inst); void addIndex(RootObject *expr); - uinteger_t size(const Loc &loc); + uinteger_t size(const Loc &loc) override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeIdentifier : public TypeQualified +class TypeIdentifier final : public TypeQualified { public: Identifier *ident; Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution static TypeIdentifier *create(const Loc &loc, Identifier *ident); - const char *kind(); - TypeIdentifier *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeIdentifier *syntaxCopy() override; + Dsymbol *toDsymbol(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; /* Similar to TypeIdentifier, but with a TemplateInstance as the root */ -class TypeInstance : public TypeQualified +class TypeInstance final : public TypeQualified { public: TemplateInstance *tempinst; - const char *kind(); - TypeInstance *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeInstance *syntaxCopy() override; + Dsymbol *toDsymbol(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; -class TypeTypeof : public TypeQualified +class TypeTypeof final : public TypeQualified { public: Expression *exp; int inuse; - const char *kind(); - TypeTypeof *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - uinteger_t size(const Loc &loc); - void accept(Visitor *v) { v->visit(this); } + 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); } }; -class TypeReturn : public TypeQualified +class TypeReturn final : public TypeQualified { public: - const char *kind(); - TypeReturn *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeReturn *syntaxCopy() override; + Dsymbol *toDsymbol(Scope *sc) override; + void accept(Visitor *v) override { v->visit(this); } }; // Whether alias this dependency is recursive or not. @@ -769,7 +760,7 @@ enum AliasThisRec RECtracingDT = 0x8 // mark in progress of deduceType }; -class TypeStruct : public Type +class TypeStruct final : public Type { public: StructDeclaration *sym; @@ -777,91 +768,91 @@ public: bool inuse; static TypeStruct *create(StructDeclaration *sym); - const char *kind(); - uinteger_t size(const Loc &loc); - unsigned alignsize(); - TypeStruct *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - structalign_t alignment(); - Expression *defaultInitLiteral(const Loc &loc); - bool isZeroInit(const Loc &loc); - bool isAssignable(); - bool isBoolean() /*const*/; - bool needsDestruction() /*const*/; - bool needsCopyOrPostblit(); - bool needsNested(); - bool hasPointers(); - bool hasVoidInitPointers(); - bool hasInvariant(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - unsigned char deduceWild(Type *t, bool isRef); - Type *toHeadMutable(); - - void accept(Visitor *v) { v->visit(this); } -}; - -class TypeEnum : public Type + const char *kind() override; + 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; + bool isAssignable() override; + bool isBoolean() override; + bool needsDestruction() override; + bool needsCopyOrPostblit() override; + bool needsNested() override; + bool hasPointers() override; + bool hasVoidInitPointers() override; + bool hasInvariant() override; + MATCH implicitConvTo(Type *to) override; + MATCH constConv(Type *to) override; + unsigned char deduceWild(Type *t, bool isRef) override; + Type *toHeadMutable() override; + + void accept(Visitor *v) override { v->visit(this); } +}; + +class TypeEnum final : public Type { public: EnumDeclaration *sym; - const char *kind(); - TypeEnum *syntaxCopy(); - uinteger_t size(const Loc &loc); - unsigned alignsize(); + const char *kind() override; + TypeEnum *syntaxCopy() override; + uinteger_t size(const Loc &loc) override; + unsigned alignsize() override; Type *memType(const Loc &loc = Loc()); - Dsymbol *toDsymbol(Scope *sc); - bool isintegral(); - bool isfloating(); - bool isreal(); - bool isimaginary(); - bool iscomplex(); - bool isscalar(); - bool isunsigned(); - bool isBoolean(); - bool isString(); - bool isAssignable(); - bool needsDestruction(); - bool needsCopyOrPostblit(); - bool needsNested(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - bool isZeroInit(const Loc &loc); - bool hasPointers(); - bool hasVoidInitPointers(); - bool hasInvariant(); - Type *nextOf(); - - void accept(Visitor *v) { v->visit(this); } -}; - -class TypeClass : public Type + Dsymbol *toDsymbol(Scope *sc) override; + bool isintegral() override; + bool isfloating() override; + bool isreal() override; + bool isimaginary() override; + bool iscomplex() override; + bool isscalar() override; + bool isunsigned() override; + bool isBoolean() override; + bool isString() override; + bool isAssignable() override; + bool needsDestruction() override; + bool needsCopyOrPostblit() override; + bool needsNested() override; + MATCH implicitConvTo(Type *to) override; + MATCH constConv(Type *to) override; + bool isZeroInit(const Loc &loc) override; + bool hasPointers() override; + bool hasVoidInitPointers() override; + bool hasInvariant() override; + Type *nextOf() override; + + void accept(Visitor *v) override { v->visit(this); } +}; + +class TypeClass final : public Type { public: ClassDeclaration *sym; AliasThisRec att; CPPMANGLE cppmangle; - const char *kind(); - uinteger_t size(const Loc &loc) /*const*/; - TypeClass *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - ClassDeclaration *isClassHandle(); - bool isBaseOf(Type *t, int *poffset); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - unsigned char deduceWild(Type *t, bool isRef); - Type *toHeadMutable(); - bool isZeroInit(const Loc &loc) /*const*/; - bool isscope() /*const*/; - bool isBoolean() /*const*/; - bool hasPointers() /*const*/; + 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; + Type *toHeadMutable() override; + bool isZeroInit(const Loc &loc) override; + bool isscope() override; + bool isBoolean() override; + bool hasPointers() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TypeTuple : public Type +class TypeTuple final : public Type { public: // 'logically immutable' cached global - don't modify (neither pointer nor pointee)! @@ -873,56 +864,57 @@ public: static TypeTuple *create(); static TypeTuple *create(Type *t1); static TypeTuple *create(Type *t1, Type *t2); - const char *kind(); - TypeTuple *syntaxCopy(); - bool equals(const RootObject *o) const; - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeTuple *syntaxCopy() override; + bool equals(const RootObject *o) const override; + void accept(Visitor *v) override { v->visit(this); } }; -class TypeSlice : public TypeNext +class TypeSlice final : public TypeNext { public: Expression *lwr; Expression *upr; - const char *kind(); - TypeSlice *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + const char *kind() override; + TypeSlice *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class TypeNull : public Type +class TypeNull final : public Type { public: - const char *kind(); + const char *kind() override; - TypeNull *syntaxCopy(); - MATCH implicitConvTo(Type *to); - bool isBoolean() /*const*/; + TypeNull *syntaxCopy() override; + MATCH implicitConvTo(Type *to) override; + bool hasPointers() override; + bool isBoolean() override; - uinteger_t size(const Loc &loc) /*const*/; - void accept(Visitor *v) { v->visit(this); } + uinteger_t size(const Loc &loc) override; + void accept(Visitor *v) override { v->visit(this); } }; class TypeNoreturn final : public Type { public: - const char *kind(); - TypeNoreturn *syntaxCopy(); - MATCH implicitConvTo(Type* to); - MATCH constConv(Type* to); - bool isBoolean() /* const */; - uinteger_t size(const Loc& loc) /* const */; - unsigned alignsize(); + const char *kind() override; + TypeNoreturn *syntaxCopy() override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + bool isBoolean() override; + uinteger_t size(const Loc& loc) override; + unsigned alignsize() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; class TypeTag final : public Type { public: - TypeTag *syntaxCopy(); + TypeTag *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /**************************************************************/ diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index 7d6f65d..9dbbdf2 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -16,17 +16,17 @@ * Implies extern(C++). */ -class Nspace : public ScopeDsymbol +class Nspace final : public ScopeDsymbol { public: Expression *identExp; - Nspace *syntaxCopy(Dsymbol *s); - void addMember(Scope *sc, ScopeDsymbol *sds); - void setScope(Scope *sc); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); - bool hasPointers(); - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); - const char *kind() const; - Nspace *isNspace() { return this; } - void accept(Visitor *v) { v->visit(this); } + Nspace *syntaxCopy(Dsymbol *s) override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + void setScope(Scope *sc) override; + Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) 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/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index 7d5e19d..387b28c 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -272,6 +272,10 @@ public: void visit(AST.UshrAssignExp e) { visit(cast(AST.BinAssignExp)e); } void visit(AST.CatAssignExp e) { visit(cast(AST.BinAssignExp)e); } + // CatAssignExp + void visit(AST.CatElemAssignExp e) { visit(cast(AST.CatAssignExp)e); } + void visit(AST.CatDcharAssignExp e) { visit(cast(AST.CatAssignExp)e); } + //=============================================================================== // TemplateParameter void visit(AST.TemplateAliasParameter tp) { visit(cast(AST.TemplateParameter)tp); } diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h index 609e763..0c92a9a 100644 --- a/gcc/d/dmd/root/object.h +++ b/gcc/d/dmd/root/object.h @@ -26,7 +26,9 @@ enum DYNCAST DYNCAST_TUPLE, DYNCAST_PARAMETER, DYNCAST_STATEMENT, - DYNCAST_TEMPLATEPARAMETER + DYNCAST_CONDITION, + DYNCAST_TEMPLATEPARAMETER, + DYNCAST_INITIALIZER }; /* diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 1c5275b..4446b5e 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -26,7 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; - +import dmd.func : setUnsafe; /************************************************************* * Check for unsafe access in @safe code: @@ -66,7 +66,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) { if (v.overlapped) { - if (sc.func.setUnsafe(!printmsg, e.loc, + if (sc.setUnsafe(!printmsg, e.loc, "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v)) return true; } @@ -76,7 +76,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) { if (v.overlapped) { - if (sc.func.setUnsafe(!printmsg, e.loc, + if (sc.setUnsafe(!printmsg, e.loc, "field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields", ad, v)) return true; @@ -91,7 +91,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize || (v.offset & (target.ptrsize - 1)))) { - if (sc.func.setUnsafe(!printmsg, e.loc, + if (sc.setUnsafe(!printmsg, e.loc, "field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v)) return true; } @@ -99,7 +99,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) if (v.overlapUnsafe) { - if (sc.func.setUnsafe(!printmsg, e.loc, + if (sc.setUnsafe(!printmsg, e.loc, "field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes", ad, v)) { @@ -211,15 +211,12 @@ bool isSafeCast(Expression e, Type tfrom, Type tto) */ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag) { - if (!(flag & DotExpFlag.noDeref) && // this use is attempting a dereference - sc.func && // inside a function - !sc.intypeof && // allow unsafe code in typeof expressions - !(sc.flags & SCOPE.debug_)) // allow unsafe code in debug statements + if (!(flag & DotExpFlag.noDeref)) // this use is attempting a dereference { if (id == Id.ptr) - return sc.func.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e); + return sc.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e); else - return sc.func.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id); + return sc.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id); } return false; } diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 5691f3b..f7a3836 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -203,10 +203,9 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false) Type t = ce.e1.type.toBasetype(); if (t.ty == Tdelegate) t = (cast(TypeDelegate)t).next; - if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0) - { - } - else + + const level = t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)); + if (level == 0) // 0 means the function has a side effect return true; } break; @@ -251,8 +250,9 @@ bool discardValue(Expression e) } break; // complain } + // Assumption that error => no side effect case EXP.error: - return false; + return true; case EXP.variable: { VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); @@ -356,6 +356,25 @@ bool discardValue(Expression e) if (!hasSideEffect(e)) break; return false; + case EXP.identity, EXP.notIdentity: + case EXP.equal, EXP.notEqual: + /* + `[side effect] == 0` + Technically has a side effect but is clearly wrong; + */ + BinExp tmp = e.isBinExp(); + assert(tmp); + + e.error("the result of the equality expression `%s` is discarded", e.toChars()); + bool seenSideEffect = false; + foreach(expr; [tmp.e1, tmp.e2]) + { + if (hasSideEffect(expr)) { + expr.errorSupplemental("note that `%s` may have a side effect", expr.toChars()); + seenSideEffect |= true; + } + } + return !seenSideEffect; default: break; } diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index 7171324..0654625 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -696,7 +696,7 @@ extern (C++) final class UnrolledLoopStatement : Statement /*********************************************************** */ -extern (C++) class ScopeStatement : Statement +extern (C++) final class ScopeStatement : Statement { Statement statement; Loc endloc; // location of closing curly bracket diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index 66eddd8..681b481 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -109,9 +109,11 @@ public: Loc loc; STMT stmt; + DYNCAST dyncast() const override final { return DYNCAST_STATEMENT; } + virtual Statement *syntaxCopy(); - const char *toChars() const; + const char *toChars() const override final; void error(const char *format, ...); void warning(const char *format, ...); @@ -159,26 +161,26 @@ public: ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; } CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : NULL; } - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /** Any Statement that fails semantic() or has a component that is an ErrorExp or * a TypeError should return an ErrorStatement from semantic(). */ -class ErrorStatement : public Statement +class ErrorStatement final : public Statement { public: - ErrorStatement *syntaxCopy(); + ErrorStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class PeelStatement : public Statement +class PeelStatement final : public Statement { public: Statement *s; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; class ExpStatement : public Statement @@ -187,12 +189,12 @@ public: Expression *exp; static ExpStatement *create(const Loc &loc, Expression *exp); - ExpStatement *syntaxCopy(); + ExpStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DtorExpStatement : public ExpStatement +class DtorExpStatement final : public ExpStatement { public: /* Wraps an expression that is the destruction of 'var' @@ -200,17 +202,17 @@ public: VarDeclaration *var; - DtorExpStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + DtorExpStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class CompileStatement : public Statement +class CompileStatement final : public Statement { public: Expressions *exps; - CompileStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + CompileStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; class CompoundStatement : public Statement @@ -219,60 +221,60 @@ public: Statements *statements; static CompoundStatement *create(const Loc &loc, Statement *s1, Statement *s2); - CompoundStatement *syntaxCopy(); - ReturnStatement *endsWithReturnStatement(); - Statement *last(); + CompoundStatement *syntaxCopy() override; + ReturnStatement *endsWithReturnStatement() override final; + Statement *last() override final; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CompoundDeclarationStatement : public CompoundStatement +class CompoundDeclarationStatement final : public CompoundStatement { public: - CompoundDeclarationStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + CompoundDeclarationStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; /* The purpose of this is so that continue will go to the next * of the statements, and break will go to the end of the statements. */ -class UnrolledLoopStatement : public Statement +class UnrolledLoopStatement final : public Statement { public: Statements *statements; - UnrolledLoopStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + UnrolledLoopStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ScopeStatement : public Statement +class ScopeStatement final : public Statement { public: Statement *statement; Loc endloc; // location of closing curly bracket - ScopeStatement *syntaxCopy(); - ReturnStatement *endsWithReturnStatement(); - bool hasBreak() const; - bool hasContinue() const; + ScopeStatement *syntaxCopy() override; + ReturnStatement *endsWithReturnStatement() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ForwardingStatement : public Statement +class ForwardingStatement final : public Statement { public: ForwardingScopeDsymbol *sym; Statement *statement; - ForwardingStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + ForwardingStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class WhileStatement : public Statement +class WhileStatement final : public Statement { public: Parameter *param; @@ -280,28 +282,28 @@ public: Statement *_body; Loc endloc; // location of closing curly bracket - WhileStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + WhileStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DoStatement : public Statement +class DoStatement final : public Statement { public: Statement *_body; Expression *condition; Loc endloc; // location of ';' after while - DoStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + DoStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ForStatement : public Statement +class ForStatement final : public Statement { public: Statement *_init; @@ -315,15 +317,15 @@ public: // treat that label as referring to this loop. Statement *relatedLabeled; - ForStatement *syntaxCopy(); - Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; } - bool hasBreak() const; - bool hasContinue() const; + ForStatement *syntaxCopy() override; + Statement *getRelatedLabeled() override { return relatedLabeled ? relatedLabeled : this; } + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ForeachStatement : public Statement +class ForeachStatement final : public Statement { public: TOK op; // TOKforeach or TOKforeach_reverse @@ -340,14 +342,14 @@ public: Statements *cases; // put breaks, continues, gotos and returns here ScopeStatements *gotos; // forward referenced goto's go here - ForeachStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + ForeachStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ForeachRangeStatement : public Statement +class ForeachRangeStatement final : public Statement { public: TOK op; // TOKforeach or TOKforeach_reverse @@ -359,14 +361,14 @@ public: VarDeclaration *key; - ForeachRangeStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + ForeachRangeStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class IfStatement : public Statement +class IfStatement final : public Statement { public: Parameter *prm; @@ -376,56 +378,56 @@ public: VarDeclaration *match; // for MatchExpression results Loc endloc; // location of closing curly bracket - IfStatement *syntaxCopy(); + IfStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ConditionalStatement : public Statement +class ConditionalStatement final : public Statement { public: Condition *condition; Statement *ifbody; Statement *elsebody; - ConditionalStatement *syntaxCopy(); + ConditionalStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class StaticForeachStatement : public Statement +class StaticForeachStatement final : public Statement { public: StaticForeach *sfe; - StaticForeachStatement *syntaxCopy(); + StaticForeachStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class PragmaStatement : public Statement +class PragmaStatement final : public Statement { public: Identifier *ident; Expressions *args; // array of Expression's Statement *_body; - PragmaStatement *syntaxCopy(); + PragmaStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class StaticAssertStatement : public Statement +class StaticAssertStatement final : public Statement { public: StaticAssert *sa; - StaticAssertStatement *syntaxCopy(); + StaticAssertStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class SwitchStatement : public Statement +class SwitchStatement final : public Statement { public: Expression *condition; @@ -441,13 +443,13 @@ public: int hasVars; // !=0 if has variable case values VarDeclaration *lastVar; - SwitchStatement *syntaxCopy(); - bool hasBreak() const; + SwitchStatement *syntaxCopy() override; + bool hasBreak() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CaseStatement : public Statement +class CaseStatement final : public Statement { public: Expression *exp; @@ -457,110 +459,110 @@ public: VarDeclaration *lastVar; void* extra; // for use by Statement_toIR() - CaseStatement *syntaxCopy(); + CaseStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class CaseRangeStatement : public Statement +class CaseRangeStatement final : public Statement { public: Expression *first; Expression *last; Statement *statement; - CaseRangeStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + CaseRangeStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class DefaultStatement : public Statement +class DefaultStatement final : public Statement { public: Statement *statement; VarDeclaration *lastVar; - DefaultStatement *syntaxCopy(); + DefaultStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class GotoDefaultStatement : public Statement +class GotoDefaultStatement final : public Statement { public: SwitchStatement *sw; - GotoDefaultStatement *syntaxCopy(); + GotoDefaultStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class GotoCaseStatement : public Statement +class GotoCaseStatement final : public Statement { public: Expression *exp; // NULL, or which case to goto CaseStatement *cs; // case statement it resolves to - GotoCaseStatement *syntaxCopy(); + GotoCaseStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class SwitchErrorStatement : public Statement +class SwitchErrorStatement final : public Statement { public: Expression *exp; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ReturnStatement : public Statement +class ReturnStatement final : public Statement { public: Expression *exp; size_t caseDim; - ReturnStatement *syntaxCopy(); + ReturnStatement *syntaxCopy() override; - ReturnStatement *endsWithReturnStatement() { return this; } - void accept(Visitor *v) { v->visit(this); } + ReturnStatement *endsWithReturnStatement() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class BreakStatement : public Statement +class BreakStatement final : public Statement { public: Identifier *ident; - BreakStatement *syntaxCopy(); + BreakStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ContinueStatement : public Statement +class ContinueStatement final : public Statement { public: Identifier *ident; - ContinueStatement *syntaxCopy(); + ContinueStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class SynchronizedStatement : public Statement +class SynchronizedStatement final : public Statement { public: Expression *exp; Statement *_body; - SynchronizedStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + SynchronizedStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class WithStatement : public Statement +class WithStatement final : public Statement { public: Expression *exp; @@ -568,12 +570,12 @@ public: VarDeclaration *wthis; Loc endloc; - WithStatement *syntaxCopy(); + WithStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class TryCatchStatement : public Statement +class TryCatchStatement final : public Statement { public: Statement *_body; @@ -581,13 +583,13 @@ public: Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion - TryCatchStatement *syntaxCopy(); - bool hasBreak() const; + TryCatchStatement *syntaxCopy() override; + bool hasBreak() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class Catch : public RootObject +class Catch final : public RootObject { public: Loc loc; @@ -606,7 +608,7 @@ public: Catch *syntaxCopy(); }; -class TryFinallyStatement : public Statement +class TryFinallyStatement final : public Statement { public: Statement *_body; @@ -616,25 +618,25 @@ public: bool bodyFallsThru; // true if _body falls through to finally static TryFinallyStatement *create(const Loc &loc, Statement *body, Statement *finalbody); - TryFinallyStatement *syntaxCopy(); - bool hasBreak() const; - bool hasContinue() const; + TryFinallyStatement *syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ScopeGuardStatement : public Statement +class ScopeGuardStatement final : public Statement { public: TOK tok; Statement *statement; - ScopeGuardStatement *syntaxCopy(); + ScopeGuardStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ThrowStatement : public Statement +class ThrowStatement final : public Statement { public: Expression *exp; @@ -642,21 +644,21 @@ public: // wasn't present in source code bool internalThrow; - ThrowStatement *syntaxCopy(); + ThrowStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class DebugStatement : public Statement +class DebugStatement final : public Statement { public: Statement *statement; - DebugStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + DebugStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class GotoStatement : public Statement +class GotoStatement final : public Statement { public: Identifier *ident; @@ -666,12 +668,12 @@ public: ScopeGuardStatement *os; VarDeclaration *lastVar; - GotoStatement *syntaxCopy(); + GotoStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class LabelStatement : public Statement +class LabelStatement final : public Statement { public: Identifier *ident; @@ -684,12 +686,12 @@ public: void* extra; // used by Statement_toIR() bool breaks; // someone did a 'break ident' - LabelStatement *syntaxCopy(); + LabelStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class LabelDsymbol : public Dsymbol +class LabelDsymbol final : public Dsymbol { public: LabelStatement *statement; @@ -698,8 +700,8 @@ public: bool iasm; // set if used by inline assembler static LabelDsymbol *create(Identifier *ident); - LabelDsymbol *isLabel(); - void accept(Visitor *v) { v->visit(this); } + LabelDsymbol *isLabel() override; + void accept(Visitor *v) override { v->visit(this); } }; Statement* asmSemantic(AsmStatement *s, Scope *sc); @@ -709,11 +711,11 @@ class AsmStatement : public Statement public: Token *tokens; - AsmStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + AsmStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; -class InlineAsmStatement : public AsmStatement +class InlineAsmStatement final : public AsmStatement { public: code *asmcode; @@ -722,12 +724,12 @@ public: bool refparam; // true if function parameter is referenced bool naked; // true if function is to be naked - InlineAsmStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + InlineAsmStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; // A GCC asm statement - assembler instructions with D expression operands -class GccAsmStatement : public AsmStatement +class GccAsmStatement final : public AsmStatement { public: StorageClass stc; // attributes of the asm {} block @@ -740,27 +742,27 @@ public: Identifiers *labels; // list of goto labels GotoStatements *gotos; // of the goto labels, the equivalent statements they represent - GccAsmStatement *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + GccAsmStatement *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; // a complete asm {} block -class CompoundAsmStatement : public CompoundStatement +class CompoundAsmStatement final : public CompoundStatement { public: StorageClass stc; // postfix attributes like nothrow/pure/@trusted - CompoundAsmStatement *syntaxCopy(); + CompoundAsmStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; -class ImportStatement : public Statement +class ImportStatement final : public Statement { public: Dsymbols *imports; // Array of Import's - ImportStatement *syntaxCopy(); + ImportStatement *syntaxCopy() override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index a7ad84f..ed47b91 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -1616,9 +1616,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor static FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld) { auto params = new Parameters(); - foreach (i; 0 .. fs.parameters.dim) + foreach (i, p; *fs.parameters) { - Parameter p = (*fs.parameters)[i]; StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_); Identifier id; @@ -3929,7 +3928,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); if (!(cas.stc & (STC.trusted | STC.safe))) { - sc.func.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); + sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); } sc.pop(); @@ -4034,9 +4033,9 @@ void catchSemantic(Catch c, Scope* sc) error(c.loc, "catching C++ class objects not supported for this target"); c.errors = true; } - if (sc.func && !sc.intypeof && !c.internalCatch) + if (!c.internalCatch) { - if (sc.func.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code")) + if (sc.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code")) c.errors = true; } } @@ -4045,9 +4044,9 @@ void catchSemantic(Catch c, Scope* sc) error(c.loc, "can only catch class objects derived from `Throwable`, not `%s`", c.type.toChars()); c.errors = true; } - else if (sc.func && !sc.intypeof && !c.internalCatch && ClassDeclaration.exception && + else if (!c.internalCatch && ClassDeclaration.exception && cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) && - sc.func.setUnsafe(false, c.loc, + sc.setUnsafe(false, c.loc, "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type)) { c.errors = true; diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h index 38142bc..d938990 100644 --- a/gcc/d/dmd/staticassert.h +++ b/gcc/d/dmd/staticassert.h @@ -20,10 +20,10 @@ public: Expression *exp; Expression *msg; - StaticAssert *syntaxCopy(Dsymbol *s); - void addMember(Scope *sc, ScopeDsymbol *sds); - bool oneMember(Dsymbol **ps, Identifier *ident); - const char *kind() const; - StaticAssert *isStaticAssert() { return this; } - void accept(Visitor *v) { v->visit(this); } + StaticAssert *syntaxCopy(Dsymbol *s) override; + void addMember(Scope *sc, ScopeDsymbol *sds) 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/template.h b/gcc/d/dmd/template.h index 8686376..9ad027a 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -28,15 +28,15 @@ class Expression; class FuncDeclaration; class Parameter; -class Tuple : public RootObject +class Tuple final : public RootObject { public: Objects objects; // kludge for template.isType() - DYNCAST dyncast() const { return DYNCAST_TUPLE; } + DYNCAST dyncast() const override { return DYNCAST_TUPLE; } - const char *toChars() const { return objects.toChars(); } + const char *toChars() const override { return objects.toChars(); } }; struct TemplatePrevious @@ -46,7 +46,7 @@ struct TemplatePrevious Objects *dedargs; }; -class TemplateDeclaration : public ScopeDsymbol +class TemplateDeclaration final : public ScopeDsymbol { public: TemplateParameters *parameters; // array of TemplateParameter's @@ -74,24 +74,24 @@ public: TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack - TemplateDeclaration *syntaxCopy(Dsymbol *); - bool overloadInsert(Dsymbol *s); - bool hasStaticCtorOrDtor(); - const char *kind() const; - const char *toChars() const; + TemplateDeclaration *syntaxCopy(Dsymbol *) override; + bool overloadInsert(Dsymbol *s) override; + bool hasStaticCtorOrDtor() override; + const char *kind() const override; + const char *toChars() const override; - Visibility visible(); + Visibility visible() override; MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs); RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o); - TemplateDeclaration *isTemplateDeclaration() { return this; } + TemplateDeclaration *isTemplateDeclaration() override { return this; } TemplateTupleParameter *isVariadic(); - bool isDeprecated() const; - bool isOverloadable() const; + bool isDeprecated() const override; + bool isOverloadable() const override; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /* For type-parameter: @@ -134,10 +134,12 @@ public: virtual RootObject *defaultArg(const Loc &instLoc, Scope *sc) = 0; virtual bool hasDefaultArg() = 0; + DYNCAST dyncast() const override { return DYNCAST_TEMPLATEPARAMETER; } + /* Create dummy argument based on parameter. */ virtual RootObject *dummyArg() = 0; - void accept(Visitor *v) { v->visit(this); } + void accept(Visitor *v) override { v->visit(this); } }; /* Syntax: @@ -149,85 +151,85 @@ public: Type *specType; // type parameter: if !=NULL, this is the type specialization Type *defaultType; - TemplateTypeParameter *isTemplateTypeParameter(); - TemplateTypeParameter *syntaxCopy(); - bool declareParameter(Scope *sc); - void print(RootObject *oarg, RootObject *oded); - RootObject *specialization(); - RootObject *defaultArg(const Loc &instLoc, Scope *sc); - bool hasDefaultArg(); - RootObject *dummyArg(); - void accept(Visitor *v) { v->visit(this); } + TemplateTypeParameter *isTemplateTypeParameter() override final; + TemplateTypeParameter *syntaxCopy() override; + bool declareParameter(Scope *sc) override final; + void print(RootObject *oarg, RootObject *oded) override final; + RootObject *specialization() override final; + RootObject *defaultArg(const Loc &instLoc, Scope *sc) override final; + bool hasDefaultArg() override final; + RootObject *dummyArg() override final; + void accept(Visitor *v) override { v->visit(this); } }; /* Syntax: * this ident : specType = defaultType */ -class TemplateThisParameter : public TemplateTypeParameter +class TemplateThisParameter final : public TemplateTypeParameter { public: - TemplateThisParameter *isTemplateThisParameter(); - TemplateThisParameter *syntaxCopy(); - void accept(Visitor *v) { v->visit(this); } + TemplateThisParameter *isTemplateThisParameter() override; + TemplateThisParameter *syntaxCopy() override; + void accept(Visitor *v) override { v->visit(this); } }; /* Syntax: * valType ident : specValue = defaultValue */ -class TemplateValueParameter : public TemplateParameter +class TemplateValueParameter final : public TemplateParameter { public: Type *valType; Expression *specValue; Expression *defaultValue; - TemplateValueParameter *isTemplateValueParameter(); - TemplateValueParameter *syntaxCopy(); - bool declareParameter(Scope *sc); - void print(RootObject *oarg, RootObject *oded); - RootObject *specialization(); - RootObject *defaultArg(const Loc &instLoc, Scope *sc); - bool hasDefaultArg(); - RootObject *dummyArg(); - void accept(Visitor *v) { v->visit(this); } + TemplateValueParameter *isTemplateValueParameter() override; + TemplateValueParameter *syntaxCopy() override; + bool declareParameter(Scope *sc) override; + void print(RootObject *oarg, RootObject *oded) override; + RootObject *specialization() override; + RootObject *defaultArg(const Loc &instLoc, Scope *sc) override; + bool hasDefaultArg() override; + RootObject *dummyArg() override; + void accept(Visitor *v) override { v->visit(this); } }; /* Syntax: * specType ident : specAlias = defaultAlias */ -class TemplateAliasParameter : public TemplateParameter +class TemplateAliasParameter final : public TemplateParameter { public: Type *specType; RootObject *specAlias; RootObject *defaultAlias; - TemplateAliasParameter *isTemplateAliasParameter(); - TemplateAliasParameter *syntaxCopy(); - bool declareParameter(Scope *sc); - void print(RootObject *oarg, RootObject *oded); - RootObject *specialization(); - RootObject *defaultArg(const Loc &instLoc, Scope *sc); - bool hasDefaultArg(); - RootObject *dummyArg(); - void accept(Visitor *v) { v->visit(this); } + TemplateAliasParameter *isTemplateAliasParameter() override; + TemplateAliasParameter *syntaxCopy() override; + bool declareParameter(Scope *sc) override; + void print(RootObject *oarg, RootObject *oded) override; + RootObject *specialization() override; + RootObject *defaultArg(const Loc &instLoc, Scope *sc) override; + bool hasDefaultArg() override; + RootObject *dummyArg() override; + void accept(Visitor *v) override { v->visit(this); } }; /* Syntax: * ident ... */ -class TemplateTupleParameter : public TemplateParameter +class TemplateTupleParameter final : public TemplateParameter { public: - TemplateTupleParameter *isTemplateTupleParameter(); - TemplateTupleParameter *syntaxCopy(); - bool declareParameter(Scope *sc); - void print(RootObject *oarg, RootObject *oded); - RootObject *specialization(); - RootObject *defaultArg(const Loc &instLoc, Scope *sc); - bool hasDefaultArg(); - RootObject *dummyArg(); - void accept(Visitor *v) { v->visit(this); } + TemplateTupleParameter *isTemplateTupleParameter() override; + TemplateTupleParameter *syntaxCopy() override; + bool declareParameter(Scope *sc) override; + void print(RootObject *oarg, RootObject *oded) override; + RootObject *specialization() override; + RootObject *defaultArg(const Loc &instLoc, Scope *sc) override; + bool hasDefaultArg() override; + RootObject *dummyArg() override; + void accept(Visitor *v) override { v->visit(this); } }; /* Given: @@ -275,36 +277,36 @@ private: public: unsigned char inuse; // for recursive expansion detection - TemplateInstance *syntaxCopy(Dsymbol *); - Dsymbol *toAlias(); // resolve real symbol - const char *kind() const; - bool oneMember(Dsymbol **ps, Identifier *ident); - const char *toChars() const; - const char* toPrettyCharsHelper(); - Identifier *getIdent(); + TemplateInstance *syntaxCopy(Dsymbol *) override; + Dsymbol *toAlias() override final; // resolve real symbol + const char *kind() const override; + bool oneMember(Dsymbol **ps, Identifier *ident) override; + const char *toChars() const override; + const char* toPrettyCharsHelper() override final; + Identifier *getIdent() override final; hash_t toHash(); bool isDiscardable(); bool needsCodegen(); - TemplateInstance *isTemplateInstance() { return this; } - void accept(Visitor *v) { v->visit(this); } + TemplateInstance *isTemplateInstance() override final { return this; } + void accept(Visitor *v) override { v->visit(this); } }; -class TemplateMixin : public TemplateInstance +class TemplateMixin final : public TemplateInstance { public: TypeQualified *tqual; - TemplateMixin *syntaxCopy(Dsymbol *s); - const char *kind() const; - bool oneMember(Dsymbol **ps, Identifier *ident); - bool hasPointers(); - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); - const char *toChars() const; + TemplateMixin *syntaxCopy(Dsymbol *s) override; + const char *kind() const 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() { return this; } - void accept(Visitor *v) { v->visit(this); } + TemplateMixin *isTemplateMixin() override { return this; } + void accept(Visitor *v) override { v->visit(this); } }; Expression *isExpression(RootObject *o); diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 0acad6a..25dee7f 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -423,12 +423,20 @@ package mixin template ParseVisitMethods(AST) //printf("Visiting TypeQualified\n"); foreach (id; t.idents) { - if (id.dyncast() == DYNCAST.dsymbol) + switch(id.dyncast()) with(DYNCAST) + { + case dsymbol: (cast(AST.TemplateInstance)id).accept(this); - else if (id.dyncast() == DYNCAST.expression) + break; + case expression: (cast(AST.Expression)id).accept(this); - else if (id.dyncast() == DYNCAST.type) + break; + case type: (cast(AST.Type)id).accept(this); + break; + default: + break; + } } } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index ac4c23b..4c9ca28f 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -239,9 +239,10 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb for (size_t i = 0; i < mt.idents.dim; i++) { RootObject id = mt.idents[i]; - if (id.dyncast() == DYNCAST.expression || - id.dyncast() == DYNCAST.type) + switch (id.dyncast()) with (DYNCAST) { + case expression: + case type: Type tx; Expression ex; Dsymbol sx; @@ -259,6 +260,8 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb ex = ex.expressionSemantic(sc); resolveExp(ex, pt, pe, ps); return; + default: + break; } Type t = s.getType(); // type symbol, type alias, or type tuple? @@ -2799,21 +2802,20 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type } RootObject o = (*tup.objects)[cast(size_t)d]; - if (o.dyncast() == DYNCAST.dsymbol) + switch (o.dyncast()) with (DYNCAST) { + case dsymbol: return returnSymbol(cast(Dsymbol)o); - } - if (o.dyncast() == DYNCAST.expression) - { + case expression: Expression e = cast(Expression)o; if (e.op == EXP.dSymbol) return returnSymbol(e.isDsymbolExp().s); else return returnExp(e); - } - if (o.dyncast() == DYNCAST.type) - { + case type: return returnType((cast(Type)o).addMod(mt.mod)); + default: + break; } /* Create a new TupleDeclaration which diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h index afc4557..b76393b 100644 --- a/gcc/d/dmd/version.h +++ b/gcc/d/dmd/version.h @@ -12,30 +12,30 @@ #include "dsymbol.h" -class DebugSymbol : public Dsymbol +class DebugSymbol final : public Dsymbol { public: unsigned level; - DebugSymbol *syntaxCopy(Dsymbol *); + DebugSymbol *syntaxCopy(Dsymbol *) override; - const char *toChars() const; - void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind() const; - DebugSymbol *isDebugSymbol(); - void accept(Visitor *v) { v->visit(this); } + const char *toChars() const override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + const char *kind() const override; + DebugSymbol *isDebugSymbol() override; + void accept(Visitor *v) override { v->visit(this); } }; -class VersionSymbol : public Dsymbol +class VersionSymbol final : public Dsymbol { public: unsigned level; - VersionSymbol *syntaxCopy(Dsymbol *); + VersionSymbol *syntaxCopy(Dsymbol *) override; - const char *toChars() const; - void addMember(Scope *sc, ScopeDsymbol *sds); - const char *kind() const; - VersionSymbol *isVersionSymbol(); - void accept(Visitor *v) { v->visit(this); } + const char *toChars() const override; + void addMember(Scope *sc, ScopeDsymbol *sds) override; + const char *kind() const override; + VersionSymbol *isVersionSymbol() override; + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 5d6b94c..b45ef79 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -265,6 +265,8 @@ class ShlAssignExp; class ShrAssignExp; class UshrAssignExp; class CatAssignExp; +class CatElemAssignExp; +class CatDcharAssignExp; class AddExp; class MinExp; class CatExp; @@ -564,6 +566,10 @@ public: virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); } virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); } + // CatAssignExp + virtual void visit(CatElemAssignExp *e) { visit((CatAssignExp *)e); } + virtual void visit(CatDcharAssignExp *e) { visit((CatAssignExp *)e); } + // TemplateParameter virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); } virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); } diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 7f5e683..7edcbc4 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -234,7 +234,7 @@ public: /* Visitor interfaces, each Expression class should have overridden the default. */ - void visit (Expression *) + void visit (Expression *) final override { gcc_unreachable (); } @@ -243,7 +243,7 @@ public: expression is void, then the resulting type is void. Otherwise they are implicitly converted to a common type. */ - void visit (CondExp *e) + void visit (CondExp *e) final override { tree cond = convert_for_condition (build_expr (e->econd), e->econd->type); @@ -263,7 +263,7 @@ public: usual conversions to bring them to a common type before comparison. The result type is bool. */ - void visit (IdentityExp *e) + void visit (IdentityExp *e) final override { tree_code code = (e->op == EXP::identity) ? EQ_EXPR : NE_EXPR; Type *tb1 = e->e1->type->toBasetype (); @@ -328,7 +328,7 @@ public: equality or inequality. Operands go through the usual conversions to bring them to a common type before comparison. The result type is bool. */ - void visit (EqualExp *e) + void visit (EqualExp *e) final override { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); @@ -475,7 +475,7 @@ public: exists in an associative array. The result is a pointer to the element, or null if false. */ - void visit (InExp *e) + void visit (InExp *e) final override { Type *tb2 = e->e2->type->toBasetype (); Type *tkey = tb2->isTypeAArray ()->index->toBasetype (); @@ -490,7 +490,7 @@ public: /* Build a relational expression. The result type is bool. */ - void visit (CmpExp *e) + void visit (CmpExp *e) final override { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); @@ -539,7 +539,7 @@ public: expression is void, then the resulting type is void. Otherwise the result is bool. */ - void visit (LogicalExp *e) + void visit (LogicalExp *e) final override { tree_code code = (e->op == EXP::andAnd) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR; @@ -571,7 +571,7 @@ public: /* Build a binary operand expression. Operands go through usual arithmetic conversions to bring them to a common type before evaluating. */ - void visit (BinExp *e) + void visit (BinExp *e) final override { tree_code code; @@ -666,7 +666,7 @@ public: same type, producing a dynamic array with the result. If one operand is an element type, that element is converted to an array of length 1. */ - void visit (CatExp *e) + void visit (CatExp *e) final override { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); @@ -745,7 +745,7 @@ public: /* Build an assignment operator expression. The right operand is implicitly converted to the type of the left operand, and assigned to it. */ - void visit (BinAssignExp *e) + void visit (BinAssignExp *e) final override { tree_code code; Expression *e1b = e->e1; @@ -818,7 +818,7 @@ public: /* Build a concat assignment expression. The right operand is appended to the left operand. */ - void visit (CatAssignExp *e) + void visit (CatAssignExp *e) final override { Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); @@ -861,7 +861,7 @@ public: /* Build an assignment expression. The right operand is implicitly converted to the type of the left operand, and assigned to it. */ - void visit (AssignExp *e) + void visit (AssignExp *e) final override { /* First, handle special assignment semantics. */ @@ -1146,7 +1146,7 @@ public: /* Build a throw expression. */ - void visit (ThrowExp *e) + void visit (ThrowExp *e) final override { tree arg = build_expr_dtor (e->e1); this->result_ = build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg); @@ -1154,7 +1154,7 @@ public: /* Build a postfix expression. */ - void visit (PostExp *e) + void visit (PostExp *e) final override { tree result; @@ -1177,7 +1177,7 @@ public: /* Build an index expression. */ - void visit (IndexExp *e) + void visit (IndexExp *e) final override { Type *tb1 = e->e1->type->toBasetype (); @@ -1254,7 +1254,7 @@ public: /* Build a comma expression. The type is the type of the right operand. */ - void visit (CommaExp *e) + void visit (CommaExp *e) final override { tree t1 = build_expr (e->e1); tree t2 = build_expr (e->e2); @@ -1266,7 +1266,7 @@ public: /* Build an array length expression. Returns the number of elements in the array. The result is of type size_t. */ - void visit (ArrayLengthExp *e) + void visit (ArrayLengthExp *e) final override { if (e->e1->type->toBasetype ()->ty == TY::Tarray) this->result_ = d_array_length (build_expr (e->e1)); @@ -1281,7 +1281,7 @@ public: /* Build a delegate pointer expression. This will return the frame pointer value as a type void*. */ - void visit (DelegatePtrExp *e) + void visit (DelegatePtrExp *e) final override { tree t1 = build_expr (e->e1); this->result_ = delegate_object (t1); @@ -1290,7 +1290,7 @@ public: /* Build a delegate function pointer expression. This will return the function pointer value as a function type. */ - void visit (DelegateFuncptrExp *e) + void visit (DelegateFuncptrExp *e) final override { tree t1 = build_expr (e->e1); this->result_ = delegate_method (t1); @@ -1298,7 +1298,7 @@ public: /* Build a slice expression. */ - void visit (SliceExp *e) + void visit (SliceExp *e) final override { Type *tb = e->type->toBasetype (); Type *tb1 = e->e1->type->toBasetype (); @@ -1371,7 +1371,7 @@ public: /* Build a cast expression, which converts the given unary expression to the type of result. */ - void visit (CastExp *e) + void visit (CastExp *e) final override { Type *ebtype = e->e1->type->toBasetype (); Type *tbtype = e->to->toBasetype (); @@ -1386,7 +1386,7 @@ public: /* Build a delete expression. */ - void visit (DeleteExp *e) + void visit (DeleteExp *e) final override { tree t1 = build_expr (e->e1); Type *tb1 = e->e1->type->toBasetype (); @@ -1416,7 +1416,7 @@ public: /* Build a remove expression, which removes a particular key from an associative array. */ - void visit (RemoveExp *e) + void visit (RemoveExp *e) final override { /* Check that the array is actually an associative array. */ if (e->e1->type->toBasetype ()->ty == TY::Taarray) @@ -1439,7 +1439,7 @@ public: /* Build an unary not expression. */ - void visit (NotExp *e) + void visit (NotExp *e) final override { tree result = convert_for_condition (build_expr (e->e1), e->e1->type); /* Need to convert to boolean type or this will fail. */ @@ -1452,7 +1452,7 @@ public: complemented. Note: unlike in C, the usual integral promotions are not performed prior to the complement operation. */ - void visit (ComExp *e) + void visit (ComExp *e) final override { TY ty1 = e->e1->type->toBasetype ()->ty; gcc_assert (ty1 != TY::Tarray && ty1 != TY::Tsarray); @@ -1463,7 +1463,7 @@ public: /* Build an unary negation expression. */ - void visit (NegExp *e) + void visit (NegExp *e) final override { TY ty1 = e->e1->type->toBasetype ()->ty; gcc_assert (ty1 != TY::Tarray && ty1 != TY::Tsarray); @@ -1484,7 +1484,7 @@ public: /* Build a pointer index expression. */ - void visit (PtrExp *e) + void visit (PtrExp *e) final override { Type *tnext = NULL; size_t offset; @@ -1547,7 +1547,7 @@ public: /* Build an unary address expression. */ - void visit (AddrExp *e) + void visit (AddrExp *e) final override { tree type = build_ctype (e->type); tree exp; @@ -1581,7 +1581,7 @@ public: /* Build a function call expression. */ - void visit (CallExp *e) + void visit (CallExp *e) final override { Type *tb = e->e1->type->toBasetype (); Expression *e1b = e->e1; @@ -1763,7 +1763,7 @@ public: /* Build a delegate expression. */ - void visit (DelegateExp *e) + void visit (DelegateExp *e) final override { if (e->func->semanticRun == PASS::semantic3done) { @@ -1827,7 +1827,7 @@ public: /* Build a type component expression. */ - void visit (DotTypeExp *e) + void visit (DotTypeExp *e) final override { /* Just a pass through to underlying expression. */ this->result_ = build_expr (e->e1); @@ -1835,7 +1835,7 @@ public: /* Build a component reference expression. */ - void visit (DotVarExp *e) + void visit (DotVarExp *e) final override { VarDeclaration *vd = e->var->isVarDeclaration (); @@ -1873,7 +1873,7 @@ public: /* Build an assert expression, used to declare conditions that must hold at that a given point in the program. */ - void visit (AssertExp *e) + void visit (AssertExp *e) final override { Type *tb1 = e->e1->type->toBasetype (); tree arg = build_expr (e->e1); @@ -1958,7 +1958,7 @@ public: /* Build a declaration expression. */ - void visit (DeclarationExp *e) + void visit (DeclarationExp *e) final override { /* Compile the declaration. */ push_stmt_list (); @@ -1977,7 +1977,7 @@ public: /* Build a typeid expression. Returns an instance of class TypeInfo corresponding to. */ - void visit (TypeidExp *e) + void visit (TypeidExp *e) final override { if (Type *tid = isType (e->obj)) { @@ -2011,7 +2011,7 @@ public: /* Build a function/lambda expression. */ - void visit (FuncExp *e) + void visit (FuncExp *e) final override { Type *ftype = e->type->toBasetype (); @@ -2053,7 +2053,7 @@ public: /* Build a halt expression. */ - void visit (HaltExp *) + void visit (HaltExp *) final override { /* Should we use trap() or abort()? */ tree ttrap = builtin_decl_explicit (BUILT_IN_TRAP); @@ -2062,7 +2062,7 @@ public: /* Build a symbol pointer offset expression. */ - void visit (SymOffExp *e) + void visit (SymOffExp *e) final override { /* Build the address and offset of the symbol. */ size_t soffset = e->isSymOffExp ()->offset; @@ -2088,7 +2088,7 @@ public: /* Build a variable expression. */ - void visit (VarExp *e) + void visit (VarExp *e) final override { if (e->var->needThis ()) { @@ -2192,7 +2192,7 @@ public: /* Build a this variable expression. */ - void visit (ThisExp *e) + void visit (ThisExp *e) final override { FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL; tree result = NULL_TREE; @@ -2214,7 +2214,7 @@ public: /* Build a new expression, which allocates memory either on the garbage collected heap or by using a class or struct specific allocator. */ - void visit (NewExp *e) + void visit (NewExp *e) final override { Type *tb = e->type->toBasetype (); tree result; @@ -2464,7 +2464,7 @@ public: /* Build an integer literal. */ - void visit (IntegerExp *e) + void visit (IntegerExp *e) final override { tree ctype = build_ctype (e->type->toBasetype ()); this->result_ = build_integer_cst (e->value, ctype); @@ -2472,14 +2472,14 @@ public: /* Build a floating-point literal. */ - void visit (RealExp *e) + void visit (RealExp *e) final override { this->result_ = build_float_cst (e->value, e->type->toBasetype ()); } /* Build a complex literal. */ - void visit (ComplexExp *e) + void visit (ComplexExp *e) final override { Type *tnext; @@ -2509,7 +2509,7 @@ public: /* Build a string literal, all strings are null terminated except for static arrays. */ - void visit (StringExp *e) + void visit (StringExp *e) final override { Type *tb = e->type->toBasetype (); tree type = build_ctype (e->type); @@ -2556,7 +2556,7 @@ public: /* Build a tuple literal. Just an argument list that may have side effects that need evaluation. */ - void visit (TupleExp *e) + void visit (TupleExp *e) final override { tree result = NULL_TREE; @@ -2579,7 +2579,7 @@ public: be the type of the array element, and all elements are implicitly converted to that type. */ - void visit (ArrayLiteralExp *e) + void visit (ArrayLiteralExp *e) final override { Type *tb = e->type->toBasetype (); @@ -2711,7 +2711,7 @@ public: taken to be the key type, and common type of all values the value type. All keys and values are then implicitly converted as needed. */ - void visit (AssocArrayLiteralExp *e) + void visit (AssocArrayLiteralExp *e) final override { /* Want the mutable type for typeinfo reference. */ Type *tb = e->type->toBasetype ()->mutableOf (); @@ -2758,7 +2758,7 @@ public: /* Build a struct literal. */ - void visit (StructLiteralExp *e) + void visit (StructLiteralExp *e) final override { /* Handle empty struct literals. */ if (e->elements == NULL || e->sd->fields.length == 0) @@ -2880,14 +2880,14 @@ public: /* Build a null literal. */ - void visit (NullExp *e) + void visit (NullExp *e) final override { this->result_ = build_typeof_null_value (e->type); } /* Build a vector literal. */ - void visit (VectorExp *e) + void visit (VectorExp *e) final override { tree type = build_ctype (e->type); @@ -2927,7 +2927,7 @@ public: /* Build a static array representation of a vector expression. */ - void visit (VectorArrayExp *e) + void visit (VectorArrayExp *e) final override { this->result_ = convert_expr (build_expr (e->e1, this->constp_, true), e->e1->type, e->type); @@ -2935,7 +2935,7 @@ public: /* Build a static class literal, return its reference. */ - void visit (ClassReferenceExp *e) + void visit (ClassReferenceExp *e) final override { /* The result of build_new_class_expr is a RECORD_TYPE, we want the reference. */ @@ -2965,7 +2965,7 @@ public: /* Build an uninitialized value, generated from void initializers. */ - void visit (VoidInitExp *e) + void visit (VoidInitExp *e) final override { /* The front-end only generates these for the initializer of globals. Represent `void' as zeroes, regardless of the type's default value. */ @@ -2976,14 +2976,14 @@ public: /* These expressions are mainly just a placeholders in the frontend. We shouldn't see them here. */ - void visit (ScopeExp *e) + void visit (ScopeExp *e) final override { error_at (make_location_t (e->loc), "%qs is not an expression", e->toChars ()); this->result_ = error_mark_node; } - void visit (TypeExp *e) + void visit (TypeExp *e) final override { error_at (make_location_t (e->loc), "type %qs is not an expression", e->toChars ()); diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc index 6747ee5..133d93d 100644 --- a/gcc/d/imports.cc +++ b/gcc/d/imports.cc @@ -67,14 +67,14 @@ public: } /* This should be overridden by each symbol class. */ - void visit (Dsymbol *) + void visit (Dsymbol *) final override { gcc_unreachable (); } /* Build the module decl for M, this is considered toplevel, regardless of whether there are any parent packages in the module system. */ - void visit (Module *m) + void visit (Module *m) final override { Loc loc = (m->md != NULL) ? m->md->loc : Loc (m->srcfile.toChars (), 1, 0); @@ -93,7 +93,7 @@ public: /* Build an import of another module symbol. */ - void visit (Import *m) + void visit (Import *m) final override { tree module = build_import_decl (m->mod); this->result_ = this->make_import (module); @@ -101,7 +101,7 @@ public: /* Build an import for any kind of user defined type. Use the TYPE_DECL associated with the type symbol. */ - void visit (EnumDeclaration *d) + void visit (EnumDeclaration *d) final override { tree type = build_ctype (d->type); /* Not all kinds of D enums create a TYPE_DECL. */ @@ -109,13 +109,13 @@ public: this->result_ = this->make_import (TYPE_STUB_DECL (type)); } - void visit (AggregateDeclaration *d) + void visit (AggregateDeclaration *d) final override { tree type = build_ctype (d->type); this->result_ = this->make_import (TYPE_STUB_DECL (type)); } - void visit (ClassDeclaration *d) + void visit (ClassDeclaration *d) final override { /* Want the RECORD_TYPE, not POINTER_TYPE. */ tree type = TREE_TYPE (build_ctype (d->type)); @@ -123,12 +123,12 @@ public: } /* For now, ignore importing other kinds of dsymbols. */ - void visit (ScopeDsymbol *) + void visit (ScopeDsymbol *) final override { } /* Alias symbols aren't imported, but their targets are. */ - void visit (AliasDeclaration *d) + void visit (AliasDeclaration *d) final override { Dsymbol *dsym = d->toAlias (); @@ -154,14 +154,14 @@ public: } /* Visit the underlying alias symbol of overloadable aliases. */ - void visit (OverDeclaration *d) + void visit (OverDeclaration *d) final override { if (d->aliassym != NULL) d->aliassym->accept (this); } /* Function aliases are the same as alias symbols. */ - void visit (FuncAliasDeclaration *d) + void visit (FuncAliasDeclaration *d) final override { FuncDeclaration *fd = d->toAliasFunc (); @@ -170,17 +170,17 @@ public: } /* Skip over importing templates and tuples. */ - void visit (TemplateDeclaration *) + void visit (TemplateDeclaration *) final override { } - void visit (TupleDeclaration *) + void visit (TupleDeclaration *) final override { } /* Import any other kind of declaration. If the class does not implement symbol generation routines, the compiler will throw an error. */ - void visit (Declaration *d) + void visit (Declaration *d) final override { this->result_ = this->make_import (get_symbol_decl (d)); } diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index c263582..954eb9a 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -372,6 +372,10 @@ fpreview=fixaliasthis D RejectNegative When a symbol is resolved, check `alias this' scope before going to upper scopes. +fpreview=fiximmutableconv +D RejectNegative +Disallow unsound immutable conversions that were formerly incorrectly permitted. + fpreview=in D RejectNegative Implement 'in' parameters to mean scope const. diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index 534f866..1ad0369 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -145,10 +145,6 @@ DEF_D_RUNTIME (ARRAYAPPENDCD, "_d_arrayappendcd", RT(ARRAY_VOID), DEF_D_RUNTIME (ARRAYAPPENDWD, "_d_arrayappendwd", RT(ARRAY_VOID), P2(ARRAYPTR_BYTE, DCHAR), 0) -/* Used for appending an existing array to another. */ -DEF_D_RUNTIME (ARRAYAPPENDT, "_d_arrayappendT", RT(ARRAY_VOID), - P3(TYPEINFO, ARRAYPTR_BYTE, ARRAY_BYTE), 0) - /* Used for allocating a new associative array. */ DEF_D_RUNTIME (ASSOCARRAYLITERALTX, "_d_assocarrayliteralTX", RT(VOIDPTR), P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index d20c5c3..50d4415 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -534,7 +534,7 @@ public: /* This should be overridden by each statement class. */ - void visit (Statement *) + void visit (Statement *) final override { gcc_unreachable (); } @@ -543,13 +543,13 @@ public: try/catch/finally. At this point, this statement is just an empty placeholder. Maybe the frontend shouldn't leak these. */ - void visit (ScopeGuardStatement *) + void visit (ScopeGuardStatement *) final override { } /* If statements provide simple conditional execution of statements. */ - void visit (IfStatement *s) + void visit (IfStatement *s) final override { this->start_scope (level_cond); @@ -588,7 +588,7 @@ public: here would be the place to do it. For now, all pragmas are handled by the frontend. */ - void visit (PragmaStatement *) + void visit (PragmaStatement *) final override { } @@ -596,7 +596,7 @@ public: This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ - void visit (WhileStatement *) + void visit (WhileStatement *) final override { gcc_unreachable (); } @@ -604,7 +604,7 @@ public: /* Do while statments implement simple loops. The body is executed, then the condition is evaluated. */ - void visit (DoStatement *s) + void visit (DoStatement *s) final override { tree lbreak = this->push_break_label (s); @@ -633,7 +633,7 @@ public: /* For statements implement loops with initialization, test, and increment clauses. */ - void visit (ForStatement *s) + void visit (ForStatement *s) final override { tree lbreak = this->push_break_label (s); this->start_scope (level_loop); @@ -674,7 +674,7 @@ public: This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ - void visit (ForeachStatement *) + void visit (ForeachStatement *) final override { gcc_unreachable (); } @@ -683,7 +683,7 @@ public: loops. This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ - void visit (ForeachRangeStatement *) + void visit (ForeachRangeStatement *) final override { gcc_unreachable (); } @@ -691,7 +691,7 @@ public: /* Jump to the associated exit label for the current loop. If IDENT for the Statement is not null, then the label is user defined. */ - void visit (BreakStatement *s) + void visit (BreakStatement *s) final override { if (s->ident) { @@ -710,7 +710,7 @@ public: /* Jump to the associated continue label for the current loop. If IDENT for the Statement is not null, then the label is user defined. */ - void visit (ContinueStatement *s) + void visit (ContinueStatement *s) final override { if (s->ident) { @@ -726,7 +726,7 @@ public: /* A goto statement jumps to the statement identified by the given label. */ - void visit (GotoStatement *s) + void visit (GotoStatement *s) final override { gcc_assert (s->label->statement != NULL); gcc_assert (s->tf == s->label->statement->tf); @@ -742,7 +742,7 @@ public: /* Statements can be labeled. A label is an identifier that precedes a statement. */ - void visit (LabelStatement *s) + void visit (LabelStatement *s) final override { LabelDsymbol *sym; @@ -766,7 +766,7 @@ public: /* A switch statement goes to one of a collection of case statements depending on the value of the switch expression. */ - void visit (SwitchStatement *s) + void visit (SwitchStatement *s) final override { this->start_scope (level_switch); tree lbreak = this->push_break_label (s); @@ -855,7 +855,7 @@ public: /* Declare the case label associated with the current SwitchStatement. */ - void visit (CaseStatement *s) + void visit (CaseStatement *s) final override { /* Emit the case label. */ tree label = this->define_label (s); @@ -881,7 +881,7 @@ public: /* Declare the default label associated with the current SwitchStatement. */ - void visit (DefaultStatement *s) + void visit (DefaultStatement *s) final override { /* Emit the default case label. */ tree label = this->define_label (s); @@ -902,7 +902,7 @@ public: /* Implements `goto default' by jumping to the label associated with the DefaultStatement in a switch block. */ - void visit (GotoDefaultStatement *s) + void visit (GotoDefaultStatement *s) final override { tree label = this->lookup_label (s->sw->sdefault); this->do_jump (label); @@ -911,7 +911,7 @@ public: /* Implements `goto case' by jumping to the label associated with the CaseStatement in a switch block. */ - void visit (GotoCaseStatement *s) + void visit (GotoCaseStatement *s) final override { tree label = this->lookup_label (s->cs); this->do_jump (label); @@ -920,7 +920,7 @@ public: /* Throw a SwitchError exception, called when a switch statement has no DefaultStatement, yet none of the cases match. */ - void visit (SwitchErrorStatement *s) + void visit (SwitchErrorStatement *s) final override { /* A throw SwitchError statement gets turned into a library call. The call is wrapped in the enclosed expression. */ @@ -931,7 +931,7 @@ public: /* A return statement exits the current function and supplies its return value, if the return type is not void. */ - void visit (ReturnStatement *s) + void visit (ReturnStatement *s) final override { if (s->exp == NULL || s->exp->type->toBasetype ()->ty == TY::Tvoid) { @@ -1044,7 +1044,7 @@ public: /* Evaluate the enclosed expression, and add it to the statement list. */ - void visit (ExpStatement *s) + void visit (ExpStatement *s) final override { if (s->exp) { @@ -1056,7 +1056,7 @@ public: /* Evaluate all enclosed statements. */ - void visit (CompoundStatement *s) + void visit (CompoundStatement *s) final override { if (s->statements == NULL) return; @@ -1074,7 +1074,7 @@ public: These are compiled down as a `do ... while (0)', where each unrolled loop is nested inside and given their own continue label to jump to. */ - void visit (UnrolledLoopStatement *s) + void visit (UnrolledLoopStatement *s) final override { if (s->statements == NULL) return; @@ -1105,7 +1105,7 @@ public: /* Start a new scope and visit all nested statements, wrapping them up into a BIND_EXPR at the end of the scope. */ - void visit (ScopeStatement *s) + void visit (ScopeStatement *s) final override { if (s->statement == NULL) return; @@ -1118,7 +1118,7 @@ public: /* A with statement is a way to simplify repeated references to the same object, where the handle is either a class or struct instance. */ - void visit (WithStatement *s) + void visit (WithStatement *s) final override { this->start_scope (level_with); @@ -1143,7 +1143,7 @@ public: thrown is a class type, but does not check if it is derived from Object. Foreign objects are not currently supported at run-time. */ - void visit (ThrowStatement *s) + void visit (ThrowStatement *s) final override { ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle (); InterfaceDeclaration *id = cd->isInterfaceDeclaration (); @@ -1174,7 +1174,7 @@ public: handling generated by the frontend. This is also used to implement `scope (failure)' statements. */ - void visit (TryCatchStatement *s) + void visit (TryCatchStatement *s) final override { this->start_scope (level_try); if (s->_body) @@ -1263,7 +1263,7 @@ public: handling generated by the frontend. This is also used to implement `scope (exit)' statements. */ - void visit (TryFinallyStatement *s) + void visit (TryFinallyStatement *s) final override { this->start_scope (level_try); if (s->_body) @@ -1285,7 +1285,7 @@ public: This visitor is not strictly required other than to enforce that these kinds of statements never reach here. */ - void visit (SynchronizedStatement *) + void visit (SynchronizedStatement *) final override { gcc_unreachable (); } @@ -1294,7 +1294,7 @@ public: an assembly parser for each supported target. Instead we leverage GCC extended assembler using the GccAsmStatement class. */ - void visit (AsmStatement *) + void visit (AsmStatement *) final override { sorry ("D inline assembler statements are not supported in GDC."); } @@ -1302,7 +1302,7 @@ public: /* Build a GCC extended assembler expression, whose components are an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS. */ - void visit (GccAsmStatement *s) + void visit (GccAsmStatement *s) final override { StringExp *insn = s->insn->toStringExp (); tree outputs = NULL_TREE; @@ -1454,7 +1454,7 @@ public: /* Import symbols from another module. */ - void visit (ImportStatement *s) + void visit (ImportStatement *s) final override { if (s->imports == NULL) return; diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 668b7b3..a6507e8 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -556,7 +556,7 @@ public: void **__vptr; void *__monitor; */ - void visit (TypeInfoDeclaration *) + void visit (TypeInfoDeclaration *) final override { /* The vtable for TypeInfo. */ this->layout_base (Type::dtypeinfo); @@ -567,7 +567,7 @@ public: void *__monitor; TypeInfo base; */ - void visit (TypeInfoConstDeclaration *d) + void visit (TypeInfoConstDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); tm = tm->merge2 (); @@ -584,7 +584,7 @@ public: void *__monitor; TypeInfo base; */ - void visit (TypeInfoInvariantDeclaration *d) + void visit (TypeInfoInvariantDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); tm = tm->merge2 (); @@ -601,7 +601,7 @@ public: void *__monitor; TypeInfo base; */ - void visit (TypeInfoSharedDeclaration *d) + void visit (TypeInfoSharedDeclaration *d) final override { Type *tm = d->tinfo->unSharedOf (); tm = tm->merge2 (); @@ -618,7 +618,7 @@ public: void *__monitor; TypeInfo base; */ - void visit (TypeInfoWildDeclaration *d) + void visit (TypeInfoWildDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); tm = tm->merge2 (); @@ -637,7 +637,7 @@ public: string name; void[] m_init; */ - void visit (TypeInfoEnumDeclaration *d) + void visit (TypeInfoEnumDeclaration *d) final override { TypeEnum *ti = d->tinfo->isTypeEnum (); EnumDeclaration *ed = ti->sym; @@ -669,7 +669,7 @@ public: void *__monitor; TypeInfo m_next; */ - void visit (TypeInfoPointerDeclaration *d) + void visit (TypeInfoPointerDeclaration *d) final override { TypePointer *ti = d->tinfo->isTypePointer (); @@ -685,7 +685,7 @@ public: void *__monitor; TypeInfo value; */ - void visit (TypeInfoArrayDeclaration *d) + void visit (TypeInfoArrayDeclaration *d) final override { TypeDArray *ti = d->tinfo->isTypeDArray (); @@ -702,7 +702,7 @@ public: TypeInfo value; size_t len; */ - void visit (TypeInfoStaticArrayDeclaration *d) + void visit (TypeInfoStaticArrayDeclaration *d) final override { TypeSArray *ti = d->tinfo->isTypeSArray (); @@ -722,7 +722,7 @@ public: TypeInfo value; TypeInfo key; */ - void visit (TypeInfoAssociativeArrayDeclaration *d) + void visit (TypeInfoAssociativeArrayDeclaration *d) final override { TypeAArray *ti = d->tinfo->isTypeAArray (); @@ -741,7 +741,7 @@ public: void *__monitor; TypeInfo base; */ - void visit (TypeInfoVectorDeclaration *d) + void visit (TypeInfoVectorDeclaration *d) final override { TypeVector *ti = d->tinfo->isTypeVector (); @@ -758,7 +758,7 @@ public: TypeInfo next; string deco; */ - void visit (TypeInfoFunctionDeclaration *d) + void visit (TypeInfoFunctionDeclaration *d) final override { TypeFunction *ti = d->tinfo->isTypeFunction (); gcc_assert (ti->deco != NULL); @@ -779,7 +779,7 @@ public: TypeInfo next; string deco; */ - void visit (TypeInfoDelegateDeclaration *d) + void visit (TypeInfoDelegateDeclaration *d) final override { TypeDelegate *ti = d->tinfo->isTypeDelegate (); gcc_assert (ti->deco != NULL); @@ -813,7 +813,7 @@ public: Information relating to interfaces, and their vtables are laid out immediately after the named fields, if there is anything to write. */ - void visit (TypeInfoClassDeclaration *d) + void visit (TypeInfoClassDeclaration *d) final override { TypeClass *ti = d->tinfo->isTypeClass (); ClassDeclaration *cd = ti->sym; @@ -1004,7 +1004,7 @@ public: void *__monitor; TypeInfo_Class info; */ - void visit (TypeInfoInterfaceDeclaration *d) + void visit (TypeInfoInterfaceDeclaration *d) final override { TypeClass *ti = d->tinfo->isTypeClass (); @@ -1034,7 +1034,7 @@ public: uint m_align; immutable(void)* xgetRTInfo; */ - void visit (TypeInfoStructDeclaration *d) + void visit (TypeInfoStructDeclaration *d) final override { TypeStruct *ti = d->tinfo->isTypeStruct (); StructDeclaration *sd = ti->sym; @@ -1119,7 +1119,7 @@ public: void *__monitor; TypeInfo[] elements; */ - void visit (TypeInfoTupleDeclaration *d) + void visit (TypeInfoTupleDeclaration *d) final override { TypeTuple *ti = d->tinfo->isTypeTuple (); @@ -1328,7 +1328,7 @@ public: { } - void visit (TypeInfoDeclaration *tid) + void visit (TypeInfoDeclaration *tid) final override { tree ident = get_identifier (tid->ident->toChars ()); tree type = tinfo_types[get_typeinfo_kind (tid->tinfo)]; @@ -1342,7 +1342,7 @@ public: TREE_READONLY (tid->csym) = 1; } - void visit (TypeInfoClassDeclaration *tid) + void visit (TypeInfoClassDeclaration *tid) final override { TypeClass *tc = tid->tinfo->isTypeClass (); tid->csym = get_classinfo_decl (tc->sym); @@ -1716,40 +1716,40 @@ public: return this->result_; } - void visit (Type *t) + void visit (Type *t) final override { Type *tb = t->toBasetype (); if (tb != t) tb->accept (this); } - void visit (TypeNext *t) + void visit (TypeNext *t) final override { if (t->next) t->next->accept (this); } - void visit (TypeBasic *) + void visit (TypeBasic *) final override { } - void visit (TypeVector *t) + void visit (TypeVector *t) final override { t->basetype->accept (this); } - void visit (TypeAArray *t) + void visit (TypeAArray *t) final override { t->index->accept (this); visit ((TypeNext *) t); } - void visit (TypeFunction *t) + void visit (TypeFunction *t) final override { visit ((TypeNext *) t); } - void visit (TypeStruct *t) + void visit (TypeStruct *t) final override { StructDeclaration *sd = t->sym; if (TemplateInstance *ti = sd->isInstantiated ()) @@ -1764,7 +1764,7 @@ public: } } - void visit (TypeClass *t) + void visit (TypeClass *t) final override { ClassDeclaration *cd = t->sym; if (TemplateInstance *ti = cd->isInstantiated ()) @@ -1776,7 +1776,7 @@ public: } } - void visit (TypeTuple *t) + void visit (TypeTuple *t) final override { if (!t->arguments) return; diff --git a/gcc/d/types.cc b/gcc/d/types.cc index c54049d..b17b153 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -665,7 +665,7 @@ public: /* This should be overridden by each type class. */ - void visit (Type *) + void visit (Type *) final override { gcc_unreachable (); } @@ -673,21 +673,21 @@ public: /* Type assigned to erroneous expressions or constructs that failed during the semantic stage. */ - void visit (TypeError *t) + void visit (TypeError *t) final override { t->ctype = error_mark_node; } /* Type assigned to generic nullable types. */ - void visit (TypeNull *t) + void visit (TypeNull *t) final override { t->ctype = ptr_type_node; } /* Bottom type used for functions that never return. */ - void visit (TypeNoreturn *t) + void visit (TypeNoreturn *t) final override { t->ctype = noreturn_type_node; TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); @@ -695,7 +695,7 @@ public: /* Basic Data Types. */ - void visit (TypeBasic *t) + void visit (TypeBasic *t) final override { /* [type/basic-data-types] @@ -761,7 +761,7 @@ public: /* Build a simple pointer to data type, analogous to C pointers. */ - void visit (TypePointer *t) + void visit (TypePointer *t) final override { t->ctype = build_pointer_type (build_ctype (t->next)); } @@ -769,7 +769,7 @@ public: /* Build a dynamic array type, consisting of a length and a pointer to the array data. */ - void visit (TypeDArray *t) + void visit (TypeDArray *t) final override { /* In [abi/arrays], dynamic array layout is: .length array dimension. @@ -787,7 +787,7 @@ public: /* Build a static array type, distinguished from dynamic arrays by having a length fixed at compile-time, analogous to C arrays. */ - void visit (TypeSArray *t) + void visit (TypeSArray *t) final override { if (t->dim->isConst () && t->dim->type->isintegral ()) { @@ -804,7 +804,7 @@ public: /* Build a vector type, a fixed array of floating or integer types. */ - void visit (TypeVector *t) + void visit (TypeVector *t) final override { int nunits = t->basetype->isTypeSArray ()->dim->toUInteger (); tree inner = build_ctype (t->elementType ()); @@ -821,7 +821,7 @@ public: /* Build an associative array type, distinguished from arrays by having an index that's not necessarily an integer, and can be sparsely populated. */ - void visit (TypeAArray *t) + void visit (TypeAArray *t) final override { /* In [abi/associative-arrays], associative arrays are a struct that only consist of a pointer to an opaque, implementation defined type. */ @@ -835,7 +835,7 @@ public: /* Build type for a function declaration, which consists of a return type, and a list of parameter types, and a linkage attribute. */ - void visit (TypeFunction *t) + void visit (TypeFunction *t) final override { tree fnparams = NULL_TREE; tree fntype; @@ -925,7 +925,7 @@ public: reference and a pointer to a non-static member function, or a pointer to a closure and a pointer to a nested function. */ - void visit (TypeDelegate *t) + void visit (TypeDelegate *t) final override { /* In [abi/delegates], delegate layout is: .ptr context pointer. @@ -952,7 +952,7 @@ public: /* Build a named enum type, a distinct value whose values are restrict to a group of constants of the same underlying base type. */ - void visit (TypeEnum *t) + void visit (TypeEnum *t) final override { tree basetype = (t->sym->memtype) ? build_ctype (t->sym->memtype) : void_type_node; @@ -1067,7 +1067,7 @@ public: /* Build a struct or union type. Layout should be exactly represented as an equivalent C struct, except for non-POD or nested structs. */ - void visit (TypeStruct *t) + void visit (TypeStruct *t) final override { /* Merge types in the back-end if the front-end did not itself do so. */ tree deco = get_identifier (d_mangle_decl (t->sym)); @@ -1123,7 +1123,7 @@ public: /* Build a class type. Whereas structs are value types, classes are reference types, with all the object-orientated features. */ - void visit (TypeClass *t) + void visit (TypeClass *t) final override { /* Merge types in the back-end if the front-end did not itself do so. */ tree deco = get_identifier (d_mangle_decl (t->sym)); diff --git a/gcc/dbgcnt.def b/gcc/dbgcnt.def index 3aa18cd..365d5cb 100644 --- a/gcc/dbgcnt.def +++ b/gcc/dbgcnt.def @@ -187,6 +187,7 @@ DEBUG_COUNTER (ira_move) DEBUG_COUNTER (ivopts_loop) DEBUG_COUNTER (lim) DEBUG_COUNTER (local_alloc_for_sched) +DEBUG_COUNTER (loop_unswitch) DEBUG_COUNTER (match) DEBUG_COUNTER (merged_ipa_icf) DEBUG_COUNTER (phiopt_edge_range) diff --git a/gcc/doc/avr-mmcu.texi b/gcc/doc/avr-mmcu.texi index 8c09f08..c3e9817 100644 --- a/gcc/doc/avr-mmcu.texi +++ b/gcc/doc/avr-mmcu.texi @@ -50,15 +50,15 @@ @item 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}. +@*@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}. @item 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{attiny804}, @code{attiny806}, @code{attiny807}, @code{attiny814}, @code{attiny816}, @code{attiny817}, @code{attiny1604}, @code{attiny1606}, @code{attiny1607}, @code{attiny1614}, @code{attiny1616}, @code{attiny1617}, @code{attiny3214}, @code{attiny3216}, @code{attiny3217}, @code{atmega808}, @code{atmega809}, @code{atmega1608}, @code{atmega1609}, @code{atmega3208}, @code{atmega3209}, @code{atmega4808}, @code{atmega4809}. +@*@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{attiny804}, @code{attiny806}, @code{attiny807}, @code{attiny814}, @code{attiny816}, @code{attiny817}, @code{attiny1604}, @code{attiny1606}, @code{attiny1607}, @code{attiny1614}, @code{attiny1616}, @code{attiny1617}, @code{attiny3214}, @code{attiny3216}, @code{attiny3217}, @code{atmega808}, @code{atmega809}, @code{atmega1608}, @code{atmega1609}, @code{atmega3208}, @code{atmega3209}, @code{atmega4808}, @code{atmega4809}, @code{avr32da28}, @code{avr32da32}, @code{avr32da48}, @code{avr32db28}, @code{avr32db32}, @code{avr32db48}. @item avrxmega4 ``XMEGA'' devices with more than 64@tie{}KiB and up to 128@tie{}KiB of program memory. -@*@var{mcu}@tie{}= @code{atxmega64a3}, @code{atxmega64a3u}, @code{atxmega64a4u}, @code{atxmega64b1}, @code{atxmega64b3}, @code{atxmega64c3}, @code{atxmega64d3}, @code{atxmega64d4}. +@*@var{mcu}@tie{}= @code{atxmega64a3}, @code{atxmega64a3u}, @code{atxmega64a4u}, @code{atxmega64b1}, @code{atxmega64b3}, @code{atxmega64c3}, @code{atxmega64d3}, @code{atxmega64d4}, @code{avr128da28}, @code{avr128da32}, @code{avr128da48}, @code{avr128da64}, @code{avr128db28}, @code{avr128db32}, @code{avr128db48}, @code{avr128db64}. @item avrxmega5 ``XMEGA'' devices with more than 64@tie{}KiB and up to 128@tie{}KiB of program memory and more than 64@tie{}KiB of RAM. diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index a5d1ec8..7ee44a3 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -2365,10 +2365,20 @@ default is derived from glibc's behavior. When glibc clamps float_t to double, GCC follows and enables the option. For other cross compiles, the default is disabled. -@item --with-zstd -Specify prefix directory for installed zstd library. -Equivalent to @option{--with-zstd-include=PATH/include} plus -@option{--with-zstd-lib=PATH/lib}. +@item --with-zstd=@var{pathname} +@itemx --with-zstd-include=@var{pathname} +@itemx --with-zstd-lib=@var{pathname} +If you do not have the @code{zstd} library installed in a standard +location and you want to build GCC, you can explicitly specify the +directory where it is installed (@samp{--with-zstd=@/@var{zstdinstalldir}}). +The @option{--with-zstd=@/@var{zstdinstalldir}} option is shorthand for +@option{--with-zstd-lib=@/@var{zstdinstalldir}/lib} and +@option{--with-zstd-include=@/@var{zstdinstalldir}/include}. If this +shorthand assumption is not correct, you can use the explicit +include and lib options directly. + +These flags are applicable to the host platform only. When building +a cross compiler, they will not be used to configure target libraries. @end table @subheading Cross-Compiler-Specific Options diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8becba3..71098d8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1425,7 +1425,8 @@ See RS/6000 and PowerPC Options. -msse4a -m3dnow -m3dnowa -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop @gol -madx -mlzcnt -mbmi2 -mfxsr -mxsave -mxsaveopt -mrtm -mhle -mlwp @gol -mmwaitx -mclzero -mpku -mthreads -mgfni -mvaes -mwaitpkg @gol --mshstk -mmanual-endbr -mforce-indirect-call -mavx512vbmi2 -mavx512bf16 -menqcmd @gol +-mshstk -mmanual-endbr -mcet-switch -mforce-indirect-call @gol +-mavx512vbmi2 -mavx512bf16 -menqcmd @gol -mvpclmulqdq -mavx512bitalg -mmovdiri -mmovdir64b -mavx512vpopcntdq @gol -mavx5124fmaps -mavx512vnni -mavx5124vnniw -mprfchw -mrdpid @gol -mrdseed -msgx -mavx512vp2intersect -mserialize -mtsxldtrk@gol @@ -14203,9 +14204,6 @@ The maximum depth of a loop nest suitable for complete peeling. @item max-unswitch-insns The maximum number of insns of an unswitched loop. -@item max-unswitch-level -The maximum number of branches unswitched in a single loop. - @item lim-expensive The minimum cost of an expensive expression in the loop invariant motion. @@ -19739,7 +19737,6 @@ Set architecture type or tuning for @var{gpu}. Supported values for @var{gpu} are @table @samp -@opindex fiji @item fiji Compile for GCN3 Fiji devices (gfx803). @@ -19749,6 +19746,12 @@ Compile for GCN5 Vega 10 devices (gfx900). @item gfx906 Compile for GCN5 Vega 20 devices (gfx906). +@item gfx908 +Compile for CDNA1 Instinct MI100 series devices (gfx908). + +@item gfx90a +Compile for CDNA2 Instinct MI200 series devices (gfx90a). + @end table @item -msram-ecc=on @@ -32724,6 +32727,17 @@ function attribute. This is useful when used with the option @option{-fcf-protection=branch} to control ENDBR insertion at the function entry. +@item -mcet-switch +@opindex mcet-switch +By default, CET instrumentation is turned off on switch statements that +use a jump table and indirect branch track is disabled. Since jump +tables are stored in read-only memory, this does not result in a direct +loss of hardening. But if the jump table index is attacker-controlled, +the indirect jump may not be constrained by CET. This option turns on +CET instrumentation to enable indirect branch track for switch statements +with jump tables which leads to the jump targets reachable via any indirect +jumps. + @item -mcall-ms2sysv-xlogues @opindex mcall-ms2sysv-xlogues @opindex mno-call-ms2sysv-xlogues diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 9c9b337..7805e84 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -27,9 +27,9 @@ distributions such as that of GNU Binutils. It also contains several subdirectories that contain parts of GCC and its runtime libraries: @table @file -@item boehm-gc -The Boehm conservative garbage collector, optionally used as part of -the ObjC runtime library when configured with @option{--enable-objc-gc}. +@item c++tools +Contains the sources for the g++-mapper-server, a tool used with +C++ modules. @item config Autoconf macros and Makefile fragments used throughout the tree. @@ -58,6 +58,9 @@ Support tools for Modula-2. @item gnattools Support tools for GNAT. +@item gotools +Support tools for Go. + @item include Headers for the @code{libiberty} library. @@ -72,6 +75,16 @@ The Ada runtime library. The runtime support library for atomic operations (e.g.@: for @code{__sync} and @code{__atomic}). +@item libbacktrace +A library that allows gcc to produce backtraces when it crashes. + +@item libcc1 +A library that allows gdb to make use of the compiler. + +@item libcody +A compiler dynamism library to allow communication between compilers and +build systems, for purposes such as C++ modules. + @item libcpp The C preprocessor library. @@ -109,19 +122,30 @@ The runtime support library for transactional memory. @item libobjc The Objective-C and Objective-C++ runtime library. -@item libquadmath -The runtime support library for quad-precision math operations. +@item liboffloadmic +A library to allow OpenMP to Intel MIC targets. @item libphobos The D standard and runtime library. The bulk of this library is mirrored from the @uref{https://github.com/@/dlang, master D repositories}. +@item libquadmath +The runtime support library for quad-precision math operations. + +@item libsanitizer +Libraries for various sanitizers. The bulk of this directory is mirrored +from the @uref{https://github.com/google/sanitizers, Google sanitizers +repositories}. + @item libssp The Stack protector runtime library. @item libstdc++-v3 The C++ runtime library. +@item libvtv +The vtable verification library. + @item lto-plugin Plugin used by the linker if link-time optimizations are enabled. diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c5006af..b0ea398 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -6088,14 +6088,18 @@ for the given scalar type @var{type}. @var{is_packed} is false if the scalar access using @var{type} is known to be naturally aligned. @end deftypefn -@deftypefn {Target Hook} bool TARGET_VECTORIZE_VEC_PERM_CONST (machine_mode @var{mode}, rtx @var{output}, rtx @var{in0}, rtx @var{in1}, const vec_perm_indices @var{&sel}) +@deftypefn {Target Hook} bool TARGET_VECTORIZE_VEC_PERM_CONST (machine_mode @var{mode}, machine_mode @var{op_mode}, rtx @var{output}, rtx @var{in0}, rtx @var{in1}, const vec_perm_indices @var{&sel}) This hook is used to test whether the target can permute up to two -vectors of mode @var{mode} using the permutation vector @code{sel}, and -also to emit such a permutation. In the former case @var{in0}, @var{in1} -and @var{out} are all null. In the latter case @var{in0} and @var{in1} are -the source vectors and @var{out} is the destination vector; all three are -operands of mode @var{mode}. @var{in1} is the same as @var{in0} if -@var{sel} describes a permutation on one vector instead of two. +vectors of mode @var{op_mode} using the permutation vector @code{sel}, +producing a vector of mode @var{mode}. The hook is also used to emit such +a permutation. + +When the hook is being used to test whether the target supports a permutation, +@var{in0}, @var{in1}, and @var{out} are all null. When the hook is being used +to emit a permutation, @var{in0} and @var{in1} are the source vectors of mode +@var{op_mode} and @var{out} is the destination vector of mode @var{mode}. +@var{in1} is the same as @var{in0} if @var{sel} describes a permutation on one +vector instead of two. Return true if the operation is possible, emitting instructions for it if rtxes are provided. diff --git a/gcc/expmed.cc b/gcc/expmed.cc index 41738c1..c3e4aa8 100644 --- a/gcc/expmed.cc +++ b/gcc/expmed.cc @@ -1605,20 +1605,22 @@ extract_bit_field_using_extv (const extraction_insn *extv, rtx op0, return NULL_RTX; } -/* See whether it would be valid to extract the part of OP0 described - by BITNUM and BITSIZE into a value of mode MODE using a subreg - operation. Return the subreg if so, otherwise return null. */ +/* See whether it would be valid to extract the part of OP0 with + mode OP0_MODE described by BITNUM and BITSIZE into a value of + mode MODE using a subreg operation. + Return the subreg if so, otherwise return null. */ static rtx extract_bit_field_as_subreg (machine_mode mode, rtx op0, + machine_mode op0_mode, poly_uint64 bitsize, poly_uint64 bitnum) { poly_uint64 bytenum; if (multiple_p (bitnum, BITS_PER_UNIT, &bytenum) && known_eq (bitsize, GET_MODE_BITSIZE (mode)) - && lowpart_bit_field_p (bitnum, bitsize, GET_MODE (op0)) - && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (op0))) - return simplify_gen_subreg (mode, op0, GET_MODE (op0), bytenum); + && lowpart_bit_field_p (bitnum, bitsize, op0_mode) + && TRULY_NOOP_TRUNCATION_MODES_P (mode, op0_mode)) + return simplify_gen_subreg (mode, op0, op0_mode, bytenum); return NULL_RTX; } @@ -1777,7 +1779,8 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum, for valid bitsize and bitnum, so we don't need to do that here. */ if (VECTOR_MODE_P (mode)) { - rtx sub = extract_bit_field_as_subreg (mode, op0, bitsize, bitnum); + rtx sub = extract_bit_field_as_subreg (mode, op0, outermode, + bitsize, bitnum); if (sub) return sub; } @@ -1824,9 +1827,10 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum, /* Extraction of a full MODE1 value can be done with a subreg as long as the least significant bit of the value is the least significant bit of either OP0 or a word of OP0. */ - if (!MEM_P (op0) && !reverse) + if (!MEM_P (op0) && !reverse && op0_mode.exists (&imode)) { - rtx sub = extract_bit_field_as_subreg (mode1, op0, bitsize, bitnum); + rtx sub = extract_bit_field_as_subreg (mode1, op0, imode, + bitsize, bitnum); if (sub) return convert_extracted_bit_field (sub, mode, tmode, unsignedp); } diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 7bf1231..fbdf3c8 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -9516,6 +9516,16 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) > min_align_of_type (TREE_TYPE (TREE_TYPE (arg00))))) return NULL_TREE; + /* Similarly, avoid this optimization in GENERIC for -fsanitize=null + when type is a reference type and arg00's type is not, + because arg00 could be validly nullptr and if arg01 doesn't return, + we don't want false positive binding of reference to nullptr. */ + if (TREE_CODE (type) == REFERENCE_TYPE + && !in_gimple_form + && sanitize_flags_p (SANITIZE_NULL) + && TREE_CODE (TREE_TYPE (arg00)) != REFERENCE_TYPE) + return NULL_TREE; + arg00 = fold_convert_loc (loc, type, arg00); return fold_build_pointer_plus_loc (loc, arg00, arg01); } diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 1b9cb91..d009192 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,31 @@ +2022-05-28 Tobias Burnus <tobias@codesourcery.com> + + * dump-parse-tree.cc (show_omp_clauses): Handle OMP_LIST_ENTER. + * gfortran.h: Add OMP_LIST_ENTER. + * openmp.cc (enum omp_mask2, OMP_DECLARE_TARGET_CLAUSES): Add + OMP_CLAUSE_ENTER. + (gfc_match_omp_clauses, gfc_match_omp_declare_target, + resolve_omp_clauses): Handle 'enter' clause. + +2022-05-27 Tobias Burnus <tobias@codesourcery.com> + Chung-Lin Tang <cltang@codesourcery.com> + + * openmp.cc (gfc_check_omp_requires): Fix clause name in error. + +2022-05-24 Tobias Burnus <tobias@codesourcery.com> + + PR c/105378 + * openmp.cc (gfc_match_omp_taskwait): Accept nowait. + +2022-05-23 Tobias Burnus <tobias@codesourcery.com> + + PR fortran/104949 + * f95-lang.cc (LANG_HOOKS_OMP_ARRAY_SIZE): Redefine. + * trans-openmp.cc (gfc_omp_array_size): New. + (gfc_trans_omp_variable_list): Never turn has_device_addr + to firstprivate. + * trans.h (gfc_omp_array_size): New. + 2022-05-18 Tobias Burnus <tobias@codesourcery.com> * gfortran.h (enum gfc_omp_depend_op): Add OMP_DEPEND_INOUTSET. diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc index 4e8986b..e3affb8 100644 --- a/gcc/fortran/dump-parse-tree.cc +++ b/gcc/fortran/dump-parse-tree.cc @@ -1679,6 +1679,7 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) case OMP_LIST_IN_REDUCTION: type = "IN_REDUCTION"; break; case OMP_LIST_TASK_REDUCTION: type = "TASK_REDUCTION"; break; case OMP_LIST_DEVICE_RESIDENT: type = "DEVICE_RESIDENT"; break; + case OMP_LIST_ENTER: type = "ENTER"; break; case OMP_LIST_LINK: type = "LINK"; break; case OMP_LIST_USE_DEVICE: type = "USE_DEVICE"; break; case OMP_LIST_CACHE: type = "CACHE"; break; diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 5d970bc..0bac865 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1395,6 +1395,7 @@ enum OMP_LIST_NONTEMPORAL, OMP_LIST_ALLOCATE, OMP_LIST_HAS_DEVICE_ADDR, + OMP_LIST_ENTER, OMP_LIST_NUM /* Must be the last. */ }; diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index 63fd4dd..a1aa88c 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -986,6 +986,7 @@ enum omp_mask2 OMP_CLAUSE_ATTACH, OMP_CLAUSE_NOHOST, OMP_CLAUSE_HAS_DEVICE_ADDR, /* OpenMP 5.1 */ + OMP_CLAUSE_ENTER, /* OpenMP 5.2 */ /* This must come last. */ OMP_MASK2_LAST }; @@ -2101,6 +2102,16 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, continue; } break; + case 'e': + if ((mask & OMP_CLAUSE_ENTER)) + { + m = gfc_match_omp_to_link ("enter (", &c->lists[OMP_LIST_ENTER]); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_YES) + continue; + } + break; case 'f': if ((mask & OMP_CLAUSE_FAIL) && (m = gfc_match_dupl_check (c->fail == OMP_MEMORDER_UNSET, @@ -2921,8 +2932,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, continue; if ((mask & OMP_CLAUSE_TO) && (mask & OMP_CLAUSE_LINK)) { - if (gfc_match_omp_to_link ("to (", &c->lists[OMP_LIST_TO]) - == MATCH_YES) + /* Declare target: 'to' is an alias for 'enter'; + 'to' is deprecated since 5.2. */ + m = gfc_match_omp_to_link ("to (", &c->lists[OMP_LIST_TO]); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_YES) continue; } else if ((mask & OMP_CLAUSE_TO) @@ -3724,7 +3739,8 @@ cleanup: #define OMP_ORDERED_CLAUSES \ (omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD) #define OMP_DECLARE_TARGET_CLAUSES \ - (omp_mask (OMP_CLAUSE_TO) | OMP_CLAUSE_LINK | OMP_CLAUSE_DEVICE_TYPE) + (omp_mask (OMP_CLAUSE_ENTER) | OMP_CLAUSE_LINK | OMP_CLAUSE_DEVICE_TYPE \ + | OMP_CLAUSE_TO) #define OMP_ATOMIC_CLAUSES \ (omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT \ | OMP_CLAUSE_MEMORDER | OMP_CLAUSE_COMPARE | OMP_CLAUSE_FAIL \ @@ -4530,7 +4546,7 @@ gfc_match_omp_declare_target (void) { c = gfc_get_omp_clauses (); gfc_current_locus = old_loc; - m = gfc_match_omp_to_link (" (", &c->lists[OMP_LIST_TO]); + m = gfc_match_omp_to_link (" (", &c->lists[OMP_LIST_ENTER]); if (m != MATCH_YES) goto syntax; if (gfc_match_omp_eos () != MATCH_YES) @@ -4544,38 +4560,40 @@ gfc_match_omp_declare_target (void) gfc_buffer_error (false); - for (list = OMP_LIST_TO; list != OMP_LIST_NUM; - list = (list == OMP_LIST_TO ? OMP_LIST_LINK : OMP_LIST_NUM)) + static const int to_enter_link_lists[] + = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK }; + for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists) + && (list = to_enter_link_lists[listn], true); ++listn) for (n = c->lists[list]; n; n = n->next) if (n->sym) n->sym->mark = 0; else if (n->u.common->head) n->u.common->head->mark = 0; - for (list = OMP_LIST_TO; list != OMP_LIST_NUM; - list = (list == OMP_LIST_TO ? OMP_LIST_LINK : OMP_LIST_NUM)) + for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists) + && (list = to_enter_link_lists[listn], true); ++listn) for (n = c->lists[list]; n; n = n->next) if (n->sym) { if (n->sym->attr.in_common) gfc_error_now ("OMP DECLARE TARGET variable at %L is an " "element of a COMMON block", &n->where); + else if (n->sym->mark) + gfc_error_now ("Variable at %L mentioned multiple times in " + "clauses of the same OMP DECLARE TARGET directive", + &n->where); else if (n->sym->attr.omp_declare_target && n->sym->attr.omp_declare_target_link && list != OMP_LIST_LINK) gfc_error_now ("OMP DECLARE TARGET variable at %L previously " - "mentioned in LINK clause and later in TO clause", - &n->where); + "mentioned in LINK clause and later in %s clause", + &n->where, list == OMP_LIST_TO ? "TO" : "ENTER"); else if (n->sym->attr.omp_declare_target && !n->sym->attr.omp_declare_target_link && list == OMP_LIST_LINK) gfc_error_now ("OMP DECLARE TARGET variable at %L previously " - "mentioned in TO clause and later in LINK clause", - &n->where); - else if (n->sym->mark) - gfc_error_now ("Variable at %L mentioned multiple times in " - "clauses of the same OMP DECLARE TARGET directive", - &n->where); + "mentioned in TO or ENTER clause and later in " + "LINK clause", &n->where); else if (gfc_add_omp_declare_target (&n->sym->attr, n->sym->name, &n->sym->declared_at)) { @@ -4598,14 +4616,14 @@ gfc_match_omp_declare_target (void) && n->u.common->omp_declare_target_link && list != OMP_LIST_LINK) gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously " - "mentioned in LINK clause and later in TO clause", - &n->where); + "mentioned in LINK clause and later in %s clause", + &n->where, list == OMP_LIST_TO ? "TO" : "ENTER"); else if (n->u.common->omp_declare_target && !n->u.common->omp_declare_target_link && list == OMP_LIST_LINK) gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously " - "mentioned in TO clause and later in LINK clause", - &n->where); + "mentioned in TO or ENTER clause and later in " + "LINK clause", &n->where); else if (n->u.common->head && n->u.common->head->mark) gfc_error_now ("COMMON at %L mentioned multiple times in " "clauses of the same OMP DECLARE TARGET directive", @@ -4639,7 +4657,10 @@ gfc_match_omp_declare_target (void) s->attr.omp_device_type = c->device_type; } } - if (c->device_type && !c->lists[OMP_LIST_TO] && !c->lists[OMP_LIST_LINK]) + if (c->device_type + && !c->lists[OMP_LIST_ENTER] + && !c->lists[OMP_LIST_TO] + && !c->lists[OMP_LIST_LINK]) gfc_warning_now (0, "OMP DECLARE TARGET directive at %L with only " "DEVICE_TYPE clause is ignored", &old_loc); @@ -5272,7 +5293,7 @@ gfc_check_omp_requires (gfc_namespace *ns, int ref_omp_requires) if ((ref_omp_requires & OMP_REQ_REVERSE_OFFLOAD) && !(ns->omp_requires & OMP_REQ_REVERSE_OFFLOAD)) gfc_error ("Program unit at %L has OpenMP device constructs/routines " - "but does not set !$OMP REQUIRES REVERSE_OFFSET but other " + "but does not set !$OMP REQUIRES REVERSE_OFFLOAD but other " "program units do", &ns->proc_name->declared_at); if ((ref_omp_requires & OMP_REQ_UNIFIED_ADDRESS) && !(ns->omp_requires & OMP_REQ_UNIFIED_ADDRESS)) @@ -5701,7 +5722,8 @@ gfc_match_omp_taskwait (void) new_st.ext.omp_clauses = NULL; return MATCH_YES; } - return match_omp (EXEC_OMP_TASKWAIT, omp_mask (OMP_CLAUSE_DEPEND)); + return match_omp (EXEC_OMP_TASKWAIT, + omp_mask (OMP_CLAUSE_DEPEND) | OMP_CLAUSE_NOWAIT); } @@ -6330,7 +6352,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, "IN_REDUCTION", "TASK_REDUCTION", "DEVICE_RESIDENT", "LINK", "USE_DEVICE", "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR", - "NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR" }; + "NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER" }; STATIC_ASSERT (ARRAY_SIZE (clause_names) == OMP_LIST_NUM); if (omp_clauses == NULL) diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc index f71da09..4571ac7 100644 --- a/gcc/genpreds.cc +++ b/gcc/genpreds.cc @@ -1089,10 +1089,15 @@ write_lookup_constraint_1 (void) { do { - printf (" if (!strncmp (str + 1, \"%s\", %lu))\n" - " return CONSTRAINT_%s;\n", - c->name + 1, (unsigned long int) c->namelen - 1, - c->c_name); + if (c->namelen > 2) + printf (" if (!strncmp (str + 1, \"%s\", %lu))\n" + " return CONSTRAINT_%s;\n", + c->name + 1, (unsigned long int) c->namelen - 1, + c->c_name); + else + printf (" if (str[1] == '%c')\n" + " return CONSTRAINT_%s;\n", + c->name[1], c->c_name); c = c->next_this_letter; } while (c); diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index c726393..6e73ac7 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -944,7 +944,7 @@ bool ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode) { exit_range (r, name, e->src, mode); - // If this is not an abnormal edge, check for side effects on exit. + // If this is not an abnormal edge, check for inferred ranges on exit. if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0) m_exit.maybe_adjust_range (r, name, e->src); int_range_max er; @@ -1251,12 +1251,12 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) } // Regardless of whether we have visited pred or not, if the - // pred has side_effects, revisit this block. + // pred has inferred ranges, revisit this block. // Don't search the DOM tree. if (m_exit.has_range_p (name, pred)) { if (DEBUG_RANGE_CACHE) - fprintf (dump_file, "side effect: update "); + fprintf (dump_file, "Inferred range: update "); m_update->add (node); } @@ -1317,8 +1317,8 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, basic_block bb; basic_block prev_bb = start_bb; - // Track any side effects seen - int_range_max side_effect (TREE_TYPE (name)); + // Track any inferred ranges seen. + int_range_max infer (TREE_TYPE (name)); // Range on entry to the DEF block should not be queried. gcc_checking_assert (start_bb != def_bb); @@ -1332,8 +1332,8 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, bb; prev_bb = bb, bb = get_immediate_dominator (CDI_DOMINATORS, bb)) { - // Accumulate any block exit side effects. - m_exit.maybe_adjust_range (side_effect, name, bb); + // Accumulate any block exit inferred ranges. + m_exit.maybe_adjust_range (infer, name, bb); // This block has an outgoing range. if (m_gori.has_edge_range_p (name, bb)) @@ -1399,7 +1399,7 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, if (m_gori.outgoing_edge_range_p (er, e, name, *this)) { r.intersect (er); - // If this is a normal edge, apply any side effects. + // If this is a normal edge, apply any inferred ranges. if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0) m_exit.maybe_adjust_range (r, name, bb); @@ -1415,7 +1415,7 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, // Apply non-null if appropriate. if (!has_abnormal_call_or_eh_pred_edge_p (start_bb)) - r.intersect (side_effect); + r.intersect (infer); if (DEBUG_RANGE_CACHE) { @@ -1430,17 +1430,17 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, // any operands on stmt S to nonnull. void -ranger_cache::apply_side_effects (gimple *s) +ranger_cache::apply_inferred_ranges (gimple *s) { int_range_max r; bool update = true; basic_block bb = gimple_bb (s); - stmt_side_effects se(s); - if (se.num () == 0) + gimple_infer_range infer(s); + if (infer.num () == 0) return; - // Do not update the on-netry cache for block ending stmts. + // Do not update the on-entry cache for block ending stmts. if (stmt_ends_bb_p (s)) { edge_iterator ei; @@ -1452,15 +1452,15 @@ ranger_cache::apply_side_effects (gimple *s) update = false; } - for (unsigned x = 0; x < se.num (); x++) + for (unsigned x = 0; x < infer.num (); x++) { - tree name = se.name (x); - m_exit.add_range (name, bb, se.range (x)); + tree name = infer.name (x); + m_exit.add_range (name, bb, infer.range (x)); if (update) { if (!m_on_entry.get_bb_range (r, name, bb)) exit_range (r, name, bb, RFD_READ_ONLY); - if (r.intersect (se.range (x))) + if (r.intersect (infer.range (x))) m_on_entry.set_bb_range (name, bb, r); } } diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index 555fe32..d56e56c 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_SSA_RANGE_CACHE_H #include "gimple-range-gori.h" -#include "gimple-range-side-effect.h" +#include "gimple-range-infer.h" // This class manages a vector of pointers to ssa_block ranges. It // provides the basis for the "range on entry" cache for all @@ -87,9 +87,9 @@ public: void propagate_updated_value (tree name, basic_block bb); - void apply_side_effects (gimple *s); + void apply_inferred_ranges (gimple *s); gori_compute m_gori; - side_effect_manager m_exit; + infer_range_manager m_exit; void dump_bb (FILE *f, basic_block bb); virtual void dump (FILE *f) override; diff --git a/gcc/gimple-range-side-effect.cc b/gcc/gimple-range-infer.cc index 2c8c77d..545d4f2 100644 --- a/gcc/gimple-range-side-effect.cc +++ b/gcc/gimple-range-infer.cc @@ -1,4 +1,4 @@ -/* Gimple range side effect implementation. +/* Gimple range inference implementation. Copyright (C) 2022 Free Software Foundation, Inc. Contributed by Andrew MacLeod <amacleod@redhat.com>. @@ -37,7 +37,7 @@ along with GCC; see the file COPYING3. If not see // Adapted from infer_nonnull_range_by_dereference and check_loadstore // to process nonnull ssa_name OP in S. DATA contains a pointer to a -// stmt side effects instance. +// stmt range inference instance. static bool non_null_loadstore (gimple *, tree op, tree, void *data) @@ -49,16 +49,16 @@ non_null_loadstore (gimple *, tree op, tree, void *data) if (!targetm.addr_space.zero_address_valid (as)) { tree ssa = TREE_OPERAND (op, 0); - ((stmt_side_effects *)data)->add_nonzero (ssa); + ((gimple_infer_range *)data)->add_nonzero (ssa); } } return false; } -// Add NAME and RANGE to the the side effect summary. +// Add NAME and RANGE to the the range inference summary. void -stmt_side_effects::add_range (tree name, irange &range) +gimple_infer_range::add_range (tree name, irange &range) { m_names[num_args] = name; m_ranges[num_args] = range; @@ -66,10 +66,10 @@ stmt_side_effects::add_range (tree name, irange &range) num_args++; } -// Add a nonzero range for NAME to the side effect summary. +// Add a nonzero range for NAME to the range inference summary. void -stmt_side_effects::add_nonzero (tree name) +gimple_infer_range::add_nonzero (tree name) { if (!gimple_range_ssa_p (name)) return; @@ -78,10 +78,10 @@ stmt_side_effects::add_nonzero (tree name) add_range (name, nz); } -// Process S for side effects and fill in the summary list. -// This is the routine where new side effects should be added. +// Process S for range inference and fill in the summary list. +// This is the routine where new inferred ranges should be added. -stmt_side_effects::stmt_side_effects (gimple *s) +gimple_infer_range::gimple_infer_range (gimple *s) { num_args = 0; @@ -120,7 +120,7 @@ stmt_side_effects::stmt_side_effects (gimple *s) // ------------------------------------------------------------------------- -// This class is an element in list of side effect ranges. +// This class is an element in the list of infered ranges. class exit_range { @@ -134,7 +134,7 @@ public: // Otherwise return NULL. exit_range * -side_effect_manager::exit_range_head::find_ptr (tree ssa) +infer_range_manager::exit_range_head::find_ptr (tree ssa) { // Return NULL if SSA is not in this list. if (!m_names || !bitmap_bit_p (m_names, SSA_NAME_VERSION (ssa))) @@ -147,11 +147,11 @@ side_effect_manager::exit_range_head::find_ptr (tree ssa) return NULL; } -// Construct a side effects manager. DO_SEARCH indicates whether an immediate +// Construct a range infer manager. DO_SEARCH indicates whether an immediate // use scan should be made the first time a name is processed. This is for // on-demand clients who may not visit every statement and may miss uses. -side_effect_manager::side_effect_manager (bool do_search) +infer_range_manager::infer_range_manager (bool do_search) { bitmap_obstack_initialize (&m_bitmaps); m_on_exit.create (0); @@ -168,9 +168,9 @@ side_effect_manager::side_effect_manager (bool do_search) m_nonzero.safe_grow_cleared (num_ssa_names + 1); } -// Destruct a side effects manager. +// Destruct a range infer manager. -side_effect_manager::~side_effect_manager () +infer_range_manager::~infer_range_manager () { m_nonzero.release (); obstack_free (&m_list_obstack, NULL); @@ -182,7 +182,7 @@ side_effect_manager::~side_effect_manager () // the cache, creating it if necessary. const irange& -side_effect_manager::get_nonzero (tree name) +infer_range_manager::get_nonzero (tree name) { unsigned v = SSA_NAME_VERSION (name); if (v >= m_nonzero.length ()) @@ -195,10 +195,10 @@ side_effect_manager::get_nonzero (tree name) return *(m_nonzero[v]); } -// Return TRUE if NAME has a side effect range in block BB. +// Return TRUE if NAME has a range inference in block BB. bool -side_effect_manager::has_range_p (tree name, basic_block bb) +infer_range_manager::has_range_p (tree name, basic_block bb) { // Check if this is an immediate use search model. if (m_seen && !bitmap_bit_p (m_seen, SSA_NAME_VERSION (name))) @@ -213,11 +213,11 @@ side_effect_manager::has_range_p (tree name, basic_block bb) return true; } -// Return TRUE if NAME has a side effect range in block BB, and adjust range R +// Return TRUE if NAME has a range inference in block BB, and adjust range R // to include it. bool -side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) +infer_range_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) { if (!has_range_p (name, bb)) return false; @@ -227,10 +227,10 @@ side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) return r.intersect (*(ptr->range)); } -// Add range R as a side effect for NAME in block BB. +// Add range R as an inferred range for NAME in block BB. void -side_effect_manager::add_range (tree name, basic_block bb, const irange &r) +infer_range_manager::add_range (tree name, basic_block bb, const irange &r) { if (bb->index >= (int)m_on_exit.length ()) m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); @@ -272,18 +272,18 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r) m_on_exit[bb->index].head = ptr; } -// Add a non-zero side effect for NAME in block BB. +// Add a non-zero inferred range for NAME in block BB. void -side_effect_manager::add_nonzero (tree name, basic_block bb) +infer_range_manager::add_nonzero (tree name, basic_block bb) { add_range (name, bb, get_nonzero (name)); } -// Follow immediate use chains and find all side effects for NAME. +// Follow immediate use chains and find all inferred ranges for NAME. void -side_effect_manager::register_all_uses (tree name) +infer_range_manager::register_all_uses (tree name) { gcc_checking_assert (m_seen); @@ -296,15 +296,15 @@ side_effect_manager::register_all_uses (tree name) use_operand_p use_p; imm_use_iterator iter; - // Loop over each immediate use and see if it has a side effect. + // Loop over each immediate use and see if it has an inferred range. FOR_EACH_IMM_USE_FAST (use_p, iter, name) { gimple *s = USE_STMT (use_p); - stmt_side_effects se (s); - for (unsigned x = 0; x < se.num (); x++) + gimple_infer_range infer (s); + for (unsigned x = 0; x < infer.num (); x++) { - if (name == se.name (x)) - add_range (name, gimple_bb (s), se.range (x)); + if (name == infer.name (x)) + add_range (name, gimple_bb (s), infer.range (x)); } } } diff --git a/gcc/gimple-range-side-effect.h b/gcc/gimple-range-infer.h index 848d94b..412958f 100644 --- a/gcc/gimple-range-side-effect.h +++ b/gcc/gimple-range-infer.h @@ -1,4 +1,4 @@ -/* Header file for gimple range side effects. +/* Header file for gimple range inference. Copyright (C) 2022 Free Software Foundation, Inc. Contributed by Andrew MacLeod <amacleod@redhat.com>. @@ -21,15 +21,17 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_GIMPLE_RANGE_SIDE_H #define GCC_GIMPLE_RANGE_SIDE_H -// This class manages an on-demand summary of side effects for a statement. -// It can be instantiated as required and provides a list of side effects. +// Inferred ranges are ranges which are applied to use operands as a by product +// of executing an operation. -// New side effects should added in the constructor of this class. +// This class manages an on-demand summary of inferred ranges for a statement. +// It can be instantiated as required and provides a list of inferred ranges. +// New inferred ranges should be added in the constructor of this class. -class stmt_side_effects +class gimple_infer_range { public: - stmt_side_effects (gimple *s); + gimple_infer_range (gimple *s); inline unsigned num () const { return num_args; } inline tree name (unsigned index) const { gcc_checking_assert (index < num_args); return m_names[index]; } @@ -45,17 +47,17 @@ private: inline void bump_index () { if (num_args < size_limit - 1) num_args++; } }; -// This class manages a list of side effect ranges for each basic block. -// As side effects are seen, they can be registered to a block and later -// queried. WHen constructed with a TRUE flag, immediate uses chains are +// This class manages a list of inferred ranges for each basic block. +// As inferences are made, they can be registered to a block and later +// queried. When constructed with a TRUE flag, immediate uses chains are // followed the first time a name is referenced and block populated if -// thre are any side effects. +// there are any inferred ranges. -class side_effect_manager +class infer_range_manager { public: - side_effect_manager (bool do_search); - ~side_effect_manager (); + infer_range_manager (bool do_search); + ~infer_range_manager (); void add_range (tree name, basic_block bb, const irange &r); void add_nonzero (tree name, basic_block bb); bool has_range_p (tree name, basic_block bb); diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index f5e9e77..53f4865 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -118,7 +118,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) // If name is defined in this block, try to get an range from S. if (def_stmt && gimple_bb (def_stmt) == bb) { - // Declared in ths block, if it has a global set, check for an + // Declared in this block, if it has a global set, check for an // override from a block walk, otherwise calculate it. if (m_cache.get_global_range (r, expr)) m_cache.block_range (r, bb, expr, false); @@ -446,12 +446,11 @@ gimple_ranger::fold_stmt (gimple_stmt_iterator *gsi, tree (*valueize) (tree)) return ret; } -// Called during dominator walks to register any side effects that take effect -// from this point forward. Current release is only for tracking non-null -// within a block. +// Called during dominator walks to register any inferred ranges that take +// effect from this point forward. void -gimple_ranger::register_side_effects (gimple *s) +gimple_ranger::register_inferred_ranges (gimple *s) { // First, export the LHS if it is a new global range. tree lhs = gimple_get_lhs (s); @@ -475,7 +474,7 @@ gimple_ranger::register_side_effects (gimple *s) fputc ('\n', dump_file); } } - m_cache.apply_side_effects (s); + m_cache.apply_inferred_ranges (s); } // This routine will export whatever global ranges are known to GCC diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 13d4c77..c67280d 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -60,7 +60,7 @@ public: void dump_bb (FILE *f, basic_block bb); auto_edge_flag non_executable_edge_flag; bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree)); - void register_side_effects (gimple *s); + void register_inferred_ranges (gimple *s); protected: bool fold_range_internal (irange &r, gimple *s, tree name); void prefill_name (irange &r, tree name); diff --git a/gcc/gimple-ssa-sprintf.cc b/gcc/gimple-ssa-sprintf.cc index 8202129..6bd2730 100644 --- a/gcc/gimple-ssa-sprintf.cc +++ b/gcc/gimple-ssa-sprintf.cc @@ -2232,8 +2232,9 @@ format_character (const directive &dir, tree arg, pointer_query &ptr_qry) } /* If TYPE is an array or struct or union, increment *FLDOFF by the starting - offset of the member that *OFF point into and set *FLDSIZE to its size - in bytes and decrement *OFF by the same. Otherwise do nothing. */ + offset of the member that *OFF points into if one can be determined and + set *FLDSIZE to its size in bytes and decrement *OFF by the same. + Otherwise do nothing. */ static void set_aggregate_size_and_offset (tree type, HOST_WIDE_INT *fldoff, @@ -2249,9 +2250,9 @@ set_aggregate_size_and_offset (tree type, HOST_WIDE_INT *fldoff, if (array_elt_at_offset (type, *off, &index, &arrsize)) { *fldoff += index; - *off -= index; *fldsize = arrsize; } + /* Otherwise leave *FLDOFF et al. unchanged. */ } else if (RECORD_OR_UNION_TYPE_P (type)) { @@ -2269,11 +2270,12 @@ set_aggregate_size_and_offset (tree type, HOST_WIDE_INT *fldoff, *fldoff += index; *off -= index; } + /* Otherwise leave *FLDOFF et al. unchanged. */ } } -/* For an expression X of pointer type, recursively try to find the same - origin (object or pointer) as Y it references and return such a Y. +/* For an expression X of pointer type, recursively try to find its origin + (either object DECL or pointer such as PARM_DECL) Y and return such a Y. When X refers to an array element or struct member, set *FLDOFF to the offset of the element or member from the beginning of the "most derived" object and *FLDSIZE to its size. When nonnull, set *OFF to @@ -2284,9 +2286,6 @@ static tree get_origin_and_offset_r (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *fldsize, HOST_WIDE_INT *off) { - if (!x) - return NULL_TREE; - HOST_WIDE_INT sizebuf = -1; if (!fldsize) fldsize = &sizebuf; @@ -2308,23 +2307,33 @@ get_origin_and_offset_r (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *fldsize, case ARRAY_REF: { - tree offset = TREE_OPERAND (x, 1); - HOST_WIDE_INT idx = (tree_fits_uhwi_p (offset) - ? tree_to_uhwi (offset) : HOST_WIDE_INT_MAX); + tree sub = TREE_OPERAND (x, 1); + unsigned HOST_WIDE_INT idx = + tree_fits_uhwi_p (sub) ? tree_to_uhwi (sub) : HOST_WIDE_INT_MAX; - tree eltype = TREE_TYPE (x); - if (TREE_CODE (eltype) == INTEGER_TYPE) + tree elsz = array_ref_element_size (x); + unsigned HOST_WIDE_INT elbytes = + tree_fits_shwi_p (elsz) ? tree_to_shwi (elsz) : HOST_WIDE_INT_MAX; + + unsigned HOST_WIDE_INT byteoff = idx * elbytes; + + if (byteoff < HOST_WIDE_INT_MAX + && elbytes < HOST_WIDE_INT_MAX + && byteoff / elbytes == idx) { + /* For in-bounds constant offsets into constant-sized arrays + bump up *OFF, and for what's likely arrays or structs of + arrays, also *FLDOFF, as necessary. */ if (off) - *off = idx; + *off += byteoff; + if (elbytes > 1) + *fldoff += byteoff; } - else if (idx < HOST_WIDE_INT_MAX) - *fldoff += idx * int_size_in_bytes (eltype); else - *fldoff = idx; + *fldoff = HOST_WIDE_INT_MAX; x = TREE_OPERAND (x, 0); - return get_origin_and_offset_r (x, fldoff, fldsize, nullptr); + return get_origin_and_offset_r (x, fldoff, fldsize, off); } case MEM_REF: @@ -2350,8 +2359,14 @@ get_origin_and_offset_r (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *fldsize, case COMPONENT_REF: { + tree foff = component_ref_field_offset (x); tree fld = TREE_OPERAND (x, 1); - *fldoff += int_byte_position (fld); + if (!tree_fits_shwi_p (foff) + || !tree_fits_shwi_p (DECL_FIELD_BIT_OFFSET (fld))) + return x; + *fldoff += (tree_to_shwi (foff) + + (tree_to_shwi (DECL_FIELD_BIT_OFFSET (fld)) + / BITS_PER_UNIT)); get_origin_and_offset_r (fld, fldoff, fldsize, off); x = TREE_OPERAND (x, 0); @@ -2411,30 +2426,25 @@ get_origin_and_offset_r (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *fldsize, return x; } -/* Nonrecursive version of the above. */ +/* Nonrecursive version of the above. + The function never returns null unless X is null to begin with. */ static tree get_origin_and_offset (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *off, HOST_WIDE_INT *fldsize = nullptr) { + if (!x) + return NULL_TREE; + HOST_WIDE_INT sizebuf; if (!fldsize) fldsize = &sizebuf; + /* Invalidate *FLDSIZE. */ *fldsize = -1; + *fldoff = *off = 0; - *fldoff = *off = *fldsize = 0; - tree orig = get_origin_and_offset_r (x, fldoff, fldsize, off); - if (!orig) - return NULL_TREE; - - if (!*fldoff && *off == *fldsize) - { - *fldoff = *off; - *off = 0; - } - - return orig; + return get_origin_and_offset_r (x, fldoff, fldsize, off); } /* If ARG refers to the same (sub)object or array element as described @@ -2454,7 +2464,8 @@ alias_offset (tree arg, HOST_WIDE_INT *arg_size, return HOST_WIDE_INT_MIN; /* The two arguments may refer to the same object. If they both refer - to a struct member, see if the members are one and the same. */ + to a struct member, see if the members are one and the same. If so, + return the offset into the member. */ HOST_WIDE_INT arg_off = 0, arg_fld = 0; tree arg_orig = get_origin_and_offset (arg, &arg_fld, &arg_off, arg_size); diff --git a/gcc/gimple-ssa-warn-restrict.cc b/gcc/gimple-ssa-warn-restrict.cc index b678e80..734cdd7 100644 --- a/gcc/gimple-ssa-warn-restrict.cc +++ b/gcc/gimple-ssa-warn-restrict.cc @@ -525,7 +525,6 @@ builtin_memref::set_base_and_offset (tree expr) { tree memrefoff = fold_convert (ptrdiff_type_node, TREE_OPERAND (base, 1)); extend_offset_range (memrefoff); - base = TREE_OPERAND (base, 0); if (refoff != HOST_WIDE_INT_MIN && TREE_CODE (expr) == COMPONENT_REF) @@ -538,14 +537,19 @@ builtin_memref::set_base_and_offset (tree expr) REFOFF is set to s[1].b - (char*)s. */ offset_int off = tree_to_shwi (memrefoff); refoff += off; - } - - if (!integer_zerop (memrefoff)) - /* A non-zero offset into an array of struct with flexible array - members implies that the array is empty because there is no - way to initialize such a member when it belongs to an array. - This must be some sort of a bug. */ - refsize = 0; + + if (!integer_zerop (memrefoff) + && !COMPLETE_TYPE_P (TREE_TYPE (expr)) + && multiple_of_p (sizetype, memrefoff, + TYPE_SIZE_UNIT (TREE_TYPE (base)), true)) + /* A non-zero offset into an array of struct with flexible array + members implies that the array is empty because there is no + way to initialize such a member when it belongs to an array. + This must be some sort of a bug. */ + refsize = 0; + } + + base = TREE_OPERAND (base, 0); } if (TREE_CODE (ref) == COMPONENT_REF) diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 98f5544..cd17966 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -12319,17 +12319,34 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) tree expr = *expr_p; gimple *g; gimple_seq body = NULL; + bool nowait = false; + bool has_depend = false; if (OMP_TASK_BODY (expr) == NULL_TREE) - for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_MUTEXINOUTSET) + { + for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + has_depend = true; + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_MUTEXINOUTSET) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<mutexinoutset%> kind in %<depend%> clause on a " + "%<taskwait%> construct"); + break; + } + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NOWAIT) + nowait = true; + if (nowait && !has_depend) { - error_at (OMP_CLAUSE_LOCATION (c), - "%<mutexinoutset%> kind in %<depend%> clause on a " - "%<taskwait%> construct"); - break; + error_at (EXPR_LOCATION (expr), + "%<taskwait%> construct with %<nowait%> clause but no " + "%<depend%> clauses"); + *expr_p = NULL_TREE; + return; } + } gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, omp_find_clause (OMP_TASK_CLAUSES (expr), diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index 152fe72..a94041c 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -4190,9 +4190,9 @@ public: m_initialize_when_cloning = true; } - virtual void duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, - edge_clone_summary *src_data, - edge_clone_summary *dst_data); + void duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, + edge_clone_summary *src_data, + edge_clone_summary *dst_data) final override; }; /* Edge duplication hook. */ diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h index e1f1d1b..941fea6 100644 --- a/gcc/ipa-fnsummary.h +++ b/gcc/ipa-fnsummary.h @@ -236,14 +236,15 @@ public: /* Remove ipa_fn_summary for all callees of NODE. */ void remove_callees (cgraph_node *node); - virtual void insert (cgraph_node *, ipa_fn_summary *); - virtual void remove (cgraph_node *node, ipa_fn_summary *) + void insert (cgraph_node *, ipa_fn_summary *) final override; + void remove (cgraph_node *node, ipa_fn_summary *) final override { remove_callees (node); } - virtual void duplicate (cgraph_node *src, cgraph_node *dst, - ipa_fn_summary *src_data, ipa_fn_summary *dst_data); + void duplicate (cgraph_node *src, cgraph_node *dst, + ipa_fn_summary *src_data, ipa_fn_summary *dst_data) + final override; }; extern GTY(()) fast_function_summary <ipa_fn_summary *, va_gc> @@ -259,9 +260,9 @@ public: disable_insertion_hook (); } - virtual void duplicate (cgraph_node *, cgraph_node *, - ipa_size_summary *src_data, - ipa_size_summary *dst_data) + void duplicate (cgraph_node *, cgraph_node *, + ipa_size_summary *src_data, + ipa_size_summary *dst_data) final override { *dst_data = *src_data; } @@ -311,9 +312,9 @@ public: fast_call_summary <ipa_call_summary *, va_heap> (symtab) {} /* Hook that is called by summary when an edge is duplicated. */ - virtual void duplicate (cgraph_edge *src, cgraph_edge *dst, - ipa_call_summary *src_data, - ipa_call_summary *dst_data); + void duplicate (cgraph_edge *src, cgraph_edge *dst, + ipa_call_summary *src_data, + ipa_call_summary *dst_data) final override; }; /* Estimated execution times, code sizes and other information about the diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc index 556816a..c053f8b 100644 --- a/gcc/ipa-modref.cc +++ b/gcc/ipa-modref.cc @@ -119,10 +119,10 @@ public: fnspec_summaries_t (symbol_table *symtab) : call_summary <fnspec_summary *> (symtab) {} /* Hook that is called by summary when an edge is duplicated. */ - virtual void duplicate (cgraph_edge *, - cgraph_edge *, - fnspec_summary *src, - fnspec_summary *dst) + void duplicate (cgraph_edge *, + cgraph_edge *, + fnspec_summary *src, + fnspec_summary *dst) final override { dst->fnspec = xstrdup (src->fnspec); } @@ -194,10 +194,10 @@ public: escape_summaries_t (symbol_table *symtab) : call_summary <escape_summary *> (symtab) {} /* Hook that is called by summary when an edge is duplicated. */ - virtual void duplicate (cgraph_edge *, - cgraph_edge *, - escape_summary *src, - escape_summary *dst) + void duplicate (cgraph_edge *, + cgraph_edge *, + escape_summary *src, + escape_summary *dst) final override { dst->esc = src->esc.copy (); } @@ -217,11 +217,11 @@ class GTY((user)) modref_summaries public: modref_summaries (symbol_table *symtab) : fast_function_summary <modref_summary *, va_gc> (symtab) {} - virtual void insert (cgraph_node *, modref_summary *state); - virtual void duplicate (cgraph_node *src_node, - cgraph_node *dst_node, - modref_summary *src_data, - modref_summary *dst_data); + void insert (cgraph_node *, modref_summary *state) final override; + void duplicate (cgraph_node *src_node, + cgraph_node *dst_node, + modref_summary *src_data, + modref_summary *dst_data) final override; static modref_summaries *create_ggc (symbol_table *symtab) { return new (ggc_alloc_no_dtor<modref_summaries> ()) @@ -241,11 +241,11 @@ public: modref_summaries_lto (symbol_table *symtab) : fast_function_summary <modref_summary_lto *, va_gc> (symtab), propagated (false) {} - virtual void insert (cgraph_node *, modref_summary_lto *state); - virtual void duplicate (cgraph_node *src_node, - cgraph_node *dst_node, - modref_summary_lto *src_data, - modref_summary_lto *dst_data); + void insert (cgraph_node *, modref_summary_lto *state) final override; + void duplicate (cgraph_node *src_node, + cgraph_node *dst_node, + modref_summary_lto *src_data, + modref_summary_lto *dst_data) final override; static modref_summaries_lto *create_ggc (symbol_table *symtab) { return new (ggc_alloc_no_dtor<modref_summaries_lto> ()) diff --git a/gcc/ipa-param-manipulation.cc b/gcc/ipa-param-manipulation.cc index 38328c3..23a8cb8 100644 --- a/gcc/ipa-param-manipulation.cc +++ b/gcc/ipa-param-manipulation.cc @@ -114,10 +114,10 @@ class ipa_edge_modification_sum /* Hook that is called by summary when an edge is duplicated. */ - virtual void duplicate (cgraph_edge *, - cgraph_edge *, - ipa_edge_modification_info *old_info, - ipa_edge_modification_info *new_info) + void duplicate (cgraph_edge *, + cgraph_edge *, + ipa_edge_modification_info *old_info, + ipa_edge_modification_info *new_info) final override { new_info->index_map.safe_splice (old_info->index_map); new_info->pass_through_map.safe_splice (old_info->pass_through_map); diff --git a/gcc/ipa-profile.cc b/gcc/ipa-profile.cc index b74d77f..8763b38 100644 --- a/gcc/ipa-profile.cc +++ b/gcc/ipa-profile.cc @@ -198,9 +198,9 @@ public: {} /* Duplicate info when an edge is cloned. */ - virtual void duplicate (cgraph_edge *, cgraph_edge *, - speculative_call_summary *old_sum, - speculative_call_summary *new_sum); + void duplicate (cgraph_edge *, cgraph_edge *, + speculative_call_summary *old_sum, + speculative_call_summary *new_sum) final override; }; static ipa_profile_call_summaries *call_sums = NULL; diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index c6c745f..afd9222 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -4187,14 +4187,13 @@ propagate_controlled_uses (struct cgraph_edge *cs) { int d = ipa_get_controlled_uses (old_root_info, i); int c = rdesc->refcount; + tree cst = ipa_get_jf_constant (jf); rdesc->refcount = combine_controlled_uses_counters (c, d); if (rdesc->refcount != IPA_UNDESCRIBED_USE - && ipa_get_param_load_dereferenced (old_root_info, i)) + && ipa_get_param_load_dereferenced (old_root_info, i) + && TREE_CODE (cst) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (cst, 0)) == VAR_DECL) { - tree cst = ipa_get_jf_constant (jf); - gcc_checking_assert (TREE_CODE (cst) == ADDR_EXPR - && (TREE_CODE (TREE_OPERAND (cst, 0)) - == VAR_DECL)); symtab_node *n = symtab_node::get (TREE_OPERAND (cst, 0)); new_root->create_reference (n, IPA_REF_LOAD, NULL); if (dump_file) @@ -4204,7 +4203,6 @@ propagate_controlled_uses (struct cgraph_edge *cs) } if (rdesc->refcount == 0) { - tree cst = ipa_get_jf_constant (jf); gcc_checking_assert (TREE_CODE (cst) == ADDR_EXPR && ((TREE_CODE (TREE_OPERAND (cst, 0)) == FUNCTION_DECL) diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index b22dfb5..8811e0e 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -1004,10 +1004,10 @@ public: } /* Hook that is called by summary when a node is duplicated. */ - virtual void duplicate (cgraph_node *node, - cgraph_node *node2, - ipa_node_params *data, - ipa_node_params *data2); + void duplicate (cgraph_node *node, + cgraph_node *node2, + ipa_node_params *data, + ipa_node_params *data2) final override; }; /* Summary to manange ipa_edge_args structures. */ @@ -1024,12 +1024,12 @@ class GTY((user)) ipa_edge_args_sum_t : public call_summary <ipa_edge_args *> } /* Hook that is called by summary when an edge is removed. */ - virtual void remove (cgraph_edge *cs, ipa_edge_args *args); + void remove (cgraph_edge *cs, ipa_edge_args *args) final override; /* Hook that is called by summary when an edge is duplicated. */ - virtual void duplicate (cgraph_edge *src, - cgraph_edge *dst, - ipa_edge_args *old_args, - ipa_edge_args *new_args); + void duplicate (cgraph_edge *src, + cgraph_edge *dst, + ipa_edge_args *old_args, + ipa_edge_args *new_args) final override; }; /* Function summary where the parameter infos are actually stored. */ @@ -1055,10 +1055,10 @@ public: return summary; } /* Hook that is called by summary when a node is duplicated. */ - virtual void duplicate (cgraph_node *node, - cgraph_node *node2, - ipcp_transformation *data, - ipcp_transformation *data2); + void duplicate (cgraph_node *node, + cgraph_node *node2, + ipcp_transformation *data, + ipcp_transformation *data2) final override; }; /* Function summary where the IPA CP transformations are actually stored. */ diff --git a/gcc/ipa-pure-const.cc b/gcc/ipa-pure-const.cc index 2b4950a..6f8006a 100644 --- a/gcc/ipa-pure-const.cc +++ b/gcc/ipa-pure-const.cc @@ -137,10 +137,10 @@ public: funct_state_summary_t (symbol_table *symtab): fast_function_summary <funct_state_d *, va_heap> (symtab) {} - virtual void insert (cgraph_node *, funct_state_d *state); - virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node, - funct_state_d *src_data, - funct_state_d *dst_data); + void insert (cgraph_node *, funct_state_d *state) final override; + void duplicate (cgraph_node *src_node, cgraph_node *dst_node, + funct_state_d *src_data, + funct_state_d *dst_data) final override; }; static funct_state_summary_t *funct_state_summaries = NULL; diff --git a/gcc/ipa-reference.cc b/gcc/ipa-reference.cc index 67e0c85..40b0209e 100644 --- a/gcc/ipa-reference.cc +++ b/gcc/ipa-reference.cc @@ -133,11 +133,11 @@ public: ipa_ref_opt_summary_t (symbol_table *symtab): fast_function_summary <ipa_reference_optimization_summary_d *, va_heap> (symtab) {} - virtual void remove (cgraph_node *src_node, - ipa_reference_optimization_summary_d *data); - virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node, - ipa_reference_optimization_summary_d *src_data, - ipa_reference_optimization_summary_d *dst_data); + void remove (cgraph_node *src_node, + ipa_reference_optimization_summary_d *data) final override; + void duplicate (cgraph_node *src_node, cgraph_node *dst_node, + ipa_reference_optimization_summary_d *src_data, + ipa_reference_optimization_summary_d *dst_data) final override; }; static ipa_ref_opt_summary_t *ipa_ref_opt_sum_summaries = NULL; diff --git a/gcc/ipa-sra.cc b/gcc/ipa-sra.cc index 261a720..96b020f 100644 --- a/gcc/ipa-sra.cc +++ b/gcc/ipa-sra.cc @@ -376,10 +376,10 @@ public: ipa_sra_function_summaries (symbol_table *table, bool ggc): function_summary<isra_func_summary *> (table, ggc) { } - virtual void duplicate (cgraph_node *, cgraph_node *, - isra_func_summary *old_sum, - isra_func_summary *new_sum); - virtual void insert (cgraph_node *, isra_func_summary *); + void duplicate (cgraph_node *, cgraph_node *, + isra_func_summary *old_sum, + isra_func_summary *new_sum) final override; + void insert (cgraph_node *, isra_func_summary *) final override; }; /* Hook that is called by summary when a node is duplicated. */ @@ -458,9 +458,9 @@ public: call_summary<isra_call_summary *> (table) { } /* Duplicate info when an edge is cloned. */ - virtual void duplicate (cgraph_edge *, cgraph_edge *, - isra_call_summary *old_sum, - isra_call_summary *new_sum); + void duplicate (cgraph_edge *, cgraph_edge *, + isra_call_summary *old_sum, + isra_call_summary *new_sum) final override; }; static ipa_sra_call_summaries *call_sums; diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog index 495901d..0c424cd 100644 --- a/gcc/jit/ChangeLog +++ b/gcc/jit/ChangeLog @@ -1,3 +1,8 @@ +2022-05-23 David Malcolm <dmalcolm@redhat.com> + + * jit-recording.h: Add "final" and "override" to all vfunc + implementations that were missing them, as appropriate. + 2022-05-20 David Malcolm <dmalcolm@redhat.com> * jit-playback.h: Replace uses of "FINAL" and "OVERRIDE" with diff --git a/gcc/match.pd b/gcc/match.pd index c2fed9b..88c6c41 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -285,14 +285,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) || !COMPLEX_FLOAT_TYPE_P (type))) (negate @0))) -/* Transform { 0 or 1 } * { 0 or 1 } into { 0 or 1 } & { 0 or 1 } */ -(simplify - (mult SSA_NAME@1 SSA_NAME@2) - (if (INTEGRAL_TYPE_P (type) - && get_nonzero_bits (@1) == 1 - && get_nonzero_bits (@2) == 1) - (bit_and @1 @2))) - /* Transform x * { 0 or 1, 0 or 1, ... } into x & { 0 or -1, 0 or -1, ...}, unless the target has native support for the former but not the latter. */ (simplify @@ -1787,6 +1779,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (bit_not (bit_not @0)) @0) +(match zero_one_valued_p + @0 + (if (INTEGRAL_TYPE_P (type) && tree_nonzero_bits (@0) == 1))) +(match zero_one_valued_p + truth_valued_p@0) + +/* Transform { 0 or 1 } * { 0 or 1 } into { 0 or 1 } & { 0 or 1 }. */ +(simplify + (mult zero_one_valued_p@0 zero_one_valued_p@1) + (if (INTEGRAL_TYPE_P (type)) + (bit_and @0 @1))) + +/* Transform X & -Y into X * Y when Y is { 0 or 1 }. */ +(simplify + (bit_and:c (convert? (negate zero_one_valued_p@0)) @1) + (if (INTEGRAL_TYPE_P (type) + && INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TREE_CODE (TREE_TYPE (@0)) != BOOLEAN_TYPE + && !TYPE_UNSIGNED (TREE_TYPE (@0))) + (mult (convert @0) @1))) + /* Convert ~ (-A) to A - 1. */ (simplify (bit_not (convert? (negate @0))) @@ -3281,44 +3294,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (cmp @0 (minmax:c @0 @1)) { constant_boolean_node (cmp == GE_EXPR || cmp == LE_EXPR, type); } )) -/* Undo fancy way of writing max/min or other ?: expressions, - like a - ((a - b) & -(a < b)), in this case into (a < b) ? b : a. +/* Undo fancy ways of writing max/min or other ?: expressions, like + a - ((a - b) & -(a < b)) and a - (a - b) * (a < b) into (a < b) ? b : a. People normally use ?: and that is what we actually try to optimize. */ -(for cmp (simple_comparison) - (simplify - (minus @0 (bit_and:c (minus @0 @1) - (convert? (negate@4 (convert? (cmp@5 @2 @3)))))) - (if (INTEGRAL_TYPE_P (type) - && INTEGRAL_TYPE_P (TREE_TYPE (@4)) - && TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (@5)) - && (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type) - || !TYPE_UNSIGNED (TREE_TYPE (@4))) - && (GIMPLE || !TREE_SIDE_EFFECTS (@1))) - (cond (cmp @2 @3) @1 @0))) - (simplify - (plus:c @0 (bit_and:c (minus @1 @0) - (convert? (negate@4 (convert? (cmp@5 @2 @3)))))) - (if (INTEGRAL_TYPE_P (type) - && INTEGRAL_TYPE_P (TREE_TYPE (@4)) - && TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (@5)) - && (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type) - || !TYPE_UNSIGNED (TREE_TYPE (@4))) - && (GIMPLE || !TREE_SIDE_EFFECTS (@1))) - (cond (cmp @2 @3) @1 @0))) - /* Similarly with ^ instead of - though in that case with :c. */ - (simplify - (bit_xor:c @0 (bit_and:c (bit_xor:c @0 @1) - (convert? (negate@4 (convert? (cmp@5 @2 @3)))))) - (if (INTEGRAL_TYPE_P (type) - && INTEGRAL_TYPE_P (TREE_TYPE (@4)) - && TREE_CODE (TREE_TYPE (@4)) != BOOLEAN_TYPE - && INTEGRAL_TYPE_P (TREE_TYPE (@5)) - && (TYPE_PRECISION (TREE_TYPE (@4)) >= TYPE_PRECISION (type) - || !TYPE_UNSIGNED (TREE_TYPE (@4))) - && (GIMPLE || !TREE_SIDE_EFFECTS (@1))) - (cond (cmp @2 @3) @1 @0)))) +/* Transform A + (B-A)*cmp into cmp ? B : A. */ +(simplify + (plus:c @0 (mult:c (minus @1 @0) zero_one_valued_p@2)) + (if (INTEGRAL_TYPE_P (type) + && (GIMPLE || !TREE_SIDE_EFFECTS (@1))) + (cond (convert:boolean_type_node @2) @1 @0))) +/* Transform A - (A-B)*cmp into cmp ? B : A. */ +(simplify + (minus @0 (mult:c (minus @0 @1) zero_one_valued_p@2)) + (if (INTEGRAL_TYPE_P (type) + && (GIMPLE || !TREE_SIDE_EFFECTS (@1))) + (cond (convert:boolean_type_node @2) @1 @0))) +/* Transform A ^ (A^B)*cmp into cmp ? B : A. */ +(simplify + (bit_xor:c @0 (mult:c (bit_xor:c @0 @1) zero_one_valued_p@2)) + (if (INTEGRAL_TYPE_P (type) + && (GIMPLE || !TREE_SIDE_EFFECTS (@1))) + (cond (convert:boolean_type_node @2) @1 @0))) /* Simplifications of shift and rotates. */ @@ -7642,6 +7638,8 @@ and, (with { tree op0 = @0, op1 = @1, op2 = @2; + machine_mode result_mode = TYPE_MODE (type); + machine_mode op_mode = TYPE_MODE (TREE_TYPE (op0)); /* Build a vector of integers from the tree mask. */ vec_perm_builder builder; @@ -7703,7 +7701,7 @@ and, insert from a CONSTRUCTOR or constant and use a BIT_INSERT_EXPR in that case. But only if the vector mode is supported, otherwise this is invalid GIMPLE. */ - if (TYPE_MODE (type) != BLKmode + if (op_mode != BLKmode && (TREE_CODE (cop0) == VECTOR_CST || TREE_CODE (cop0) == CONSTRUCTOR || TREE_CODE (cop1) == VECTOR_CST @@ -7749,12 +7747,12 @@ and, 2-argument version. */ tree oldop2 = op2; if (sel.ninputs () == 2 - || can_vec_perm_const_p (TYPE_MODE (type), sel, false)) + || can_vec_perm_const_p (result_mode, op_mode, sel, false)) op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel); else { vec_perm_indices sel2 (builder, 2, nelts); - if (can_vec_perm_const_p (TYPE_MODE (type), sel2, false)) + if (can_vec_perm_const_p (result_mode, op_mode, sel2, false)) op2 = vec_perm_indices_to_tree (TREE_TYPE (op2), sel2); else /* Not directly supported with either encoding, diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index ba92c4e..007558c 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,9 @@ +2022-05-25 Jakub Jelinek <jakub@redhat.com> + + PR c/91134 + * objc-act.cc (objc_build_component_ref): Adjust build_component_ref + caller. + 2022-05-11 Martin Liska <mliska@suse.cz> PR target/105355 diff --git a/gcc/objc/objc-act.cc b/gcc/objc/objc-act.cc index 252274c..10591bb 100644 --- a/gcc/objc/objc-act.cc +++ b/gcc/objc/objc-act.cc @@ -2812,7 +2812,7 @@ objc_build_component_ref (tree datum, tree component) tf_warning_or_error); #else return build_component_ref (input_location, datum, component, - UNKNOWN_LOCATION); + UNKNOWN_LOCATION, UNKNOWN_LOCATION); #endif } diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index cfa6483..ee5213e 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -89,6 +89,9 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT_DEPEND, "GOMP_taskwait_depend", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT, + "GOMP_taskwait_depend_nowait", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_START, "GOMP_taskgroup_start", diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc index 5729a20..0821b8d 100644 --- a/gcc/omp-expand.cc +++ b/gcc/omp-expand.cc @@ -916,10 +916,12 @@ expand_taskwait_call (basic_block bb, gomp_task *entry_stmt) depend = OMP_CLAUSE_DECL (depend); + bool nowait = omp_find_clause (clauses, OMP_CLAUSE_NOWAIT) != NULL_TREE; gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); - tree t - = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT_DEPEND), - 1, depend); + enum built_in_function f = (nowait + ? BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT + : BUILT_IN_GOMP_TASKWAIT_DEPEND); + tree t = build_call_expr (builtin_decl_explicit (f), 1, depend); force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); diff --git a/gcc/optabs-query.cc b/gcc/optabs-query.cc index 68dc679..809482b 100644 --- a/gcc/optabs-query.cc +++ b/gcc/optabs-query.cc @@ -407,9 +407,9 @@ can_vec_perm_var_p (machine_mode mode) } /* Return true if the target directly supports VEC_PERM_EXPRs on vectors - of mode MODE using the selector SEL. ALLOW_VARIABLE_P is true if it - is acceptable to force the selector into a register and use a variable - permute (if the target supports that). + of mode OP_MODE and result vector of mode MODE using the selector SEL. + ALLOW_VARIABLE_P is true if it is acceptable to force the selector into a + register and use a variable permute (if the target supports that). Note that additional permutations representing whole-vector shifts may also be handled via the vec_shr or vec_shl optab, but only where the @@ -417,8 +417,8 @@ can_vec_perm_var_p (machine_mode mode) with here. */ bool -can_vec_perm_const_p (machine_mode mode, const vec_perm_indices &sel, - bool allow_variable_p) +can_vec_perm_const_p (machine_mode mode, machine_mode op_mode, + const vec_perm_indices &sel, bool allow_variable_p) { /* If the target doesn't implement a vector mode for the vector type, then no operations are supported. */ @@ -448,7 +448,7 @@ can_vec_perm_const_p (machine_mode mode, const vec_perm_indices &sel, if (targetm.vectorize.vec_perm_const != NULL) { - if (targetm.vectorize.vec_perm_const (mode, NULL_RTX, NULL_RTX, + if (targetm.vectorize.vec_perm_const (mode, op_mode, NULL_RTX, NULL_RTX, NULL_RTX, sel)) return true; @@ -534,7 +534,7 @@ can_mult_highpart_p (machine_mode mode, bool uns_p) + (i & ~1) + ((i & 1) ? nunits : 0)); vec_perm_indices indices (sel, 2, nunits); - if (can_vec_perm_const_p (mode, indices)) + if (can_vec_perm_const_p (mode, mode, indices)) return 2; } } @@ -550,7 +550,7 @@ can_mult_highpart_p (machine_mode mode, bool uns_p) for (unsigned int i = 0; i < 3; ++i) sel.quick_push (2 * i + (BYTES_BIG_ENDIAN ? 0 : 1)); vec_perm_indices indices (sel, 2, nunits); - if (can_vec_perm_const_p (mode, indices)) + if (can_vec_perm_const_p (mode, mode, indices)) return 3; } } diff --git a/gcc/optabs-query.h b/gcc/optabs-query.h index b9c9fd6..945d2a8 100644 --- a/gcc/optabs-query.h +++ b/gcc/optabs-query.h @@ -178,8 +178,8 @@ bool can_conditionally_move_p (machine_mode mode); opt_machine_mode qimode_for_vec_perm (machine_mode); bool selector_fits_mode_p (machine_mode, const vec_perm_indices &); bool can_vec_perm_var_p (machine_mode); -bool can_vec_perm_const_p (machine_mode, const vec_perm_indices &, - bool = true); +bool can_vec_perm_const_p (machine_mode, machine_mode, + const vec_perm_indices &, bool = true); /* Find a widening optab even if it doesn't widen as much as we want. */ #define find_widening_optab_handler(A, B, C) \ find_widening_optab_handler_and_mode (A, B, C, NULL) diff --git a/gcc/optabs.cc b/gcc/optabs.cc index 3d8fa3a..c0a6847 100644 --- a/gcc/optabs.cc +++ b/gcc/optabs.cc @@ -6250,7 +6250,10 @@ expand_vec_perm_const (machine_mode mode, rtx v0, rtx v1, if (single_arg_p) v1 = v0; - if (targetm.vectorize.vec_perm_const (mode, target, v0, v1, indices)) + gcc_checking_assert (GET_MODE (v0) == GET_MODE (v1)); + machine_mode op_mode = GET_MODE (v0); + if (targetm.vectorize.vec_perm_const (mode, op_mode, target, v0, v1, + indices)) return target; } @@ -6264,7 +6267,7 @@ expand_vec_perm_const (machine_mode mode, rtx v0, rtx v1, v0_qi = gen_lowpart (qimode, v0); v1_qi = gen_lowpart (qimode, v1); if (targetm.vectorize.vec_perm_const != NULL - && targetm.vectorize.vec_perm_const (qimode, target_qi, v0_qi, + && targetm.vectorize.vec_perm_const (qimode, qimode, target_qi, v0_qi, v1_qi, qimode_indices)) return gen_lowpart (mode, target_qi); } diff --git a/gcc/params.opt b/gcc/params.opt index b88e137..bcf1423 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -745,10 +745,6 @@ The maximum number of instructions to consider to unroll in a loop. Common Joined UInteger Var(param_max_unswitch_insns) Init(50) Param Optimization The maximum number of insns of an unswitched loop. --param=max-unswitch-level= -Common Joined UInteger Var(param_max_unswitch_level) Init(3) Param Optimization -The maximum number of unswitchings in a single loop. - -param=max-variable-expansions-in-unroller= Common Joined UInteger Var(param_max_variable_expansions) Init(1) Param Optimization If -fvariable-expansion-in-unroller is used, the maximum number of times that an individual variable will be expanded during loop unrolling. diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index 67c2550..ae56173 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -2448,9 +2448,13 @@ field_at_offset (tree type, tree start_after, HOST_WIDE_INT off, /* The offset of FLD within its immediately enclosing structure. */ HOST_WIDE_INT fldpos = next_pos < 0 ? int_byte_position (fld) : next_pos; + tree typesize = TYPE_SIZE_UNIT (fldtype); + if (typesize && TREE_CODE (typesize) != INTEGER_CST) + /* Bail if FLD is a variable length member. */ + return NULL_TREE; + /* If the size is not available the field is a flexible array member. Treat this case as success. */ - tree typesize = TYPE_SIZE_UNIT (fldtype); HOST_WIDE_INT fldsize = (tree_fits_uhwi_p (typesize) ? tree_to_uhwi (typesize) : off); @@ -2464,7 +2468,11 @@ field_at_offset (tree type, tree start_after, HOST_WIDE_INT off, { /* If OFF is equal to the offset of the next field continue to it and skip the array/struct business below. */ - next_pos = int_byte_position (next_fld); + tree pos = byte_position (next_fld); + if (!tree_fits_shwi_p (pos)) + /* Bail if NEXT_FLD is a variable length member. */ + return NULL_TREE; + next_pos = tree_to_shwi (pos); *nextoff = *fldoff + next_pos; if (*nextoff == off && TREE_CODE (type) != UNION_TYPE) continue; diff --git a/gcc/range-op.h b/gcc/range-op.h index 5fdda32..300974f 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -95,7 +95,7 @@ protected: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; - // Side effect of relation for generic fold_range clients. + // Effect of relation for generic fold_range clients. virtual bool op1_op2_relation_effect (irange &lhs_range, tree type, const irange &op1_range, const irange &op2_range, diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h index c54d308..45fa250 100644 --- a/gcc/symbol-summary.h +++ b/gcc/symbol-summary.h @@ -248,7 +248,7 @@ protected: private: /* Indication if we use ggc summary. */ - virtual bool is_ggc () + bool is_ggc () final override { return m_ggc; } @@ -439,7 +439,7 @@ public: void *data); private: - virtual bool is_ggc (); + bool is_ggc () final override; /* Summary is stored in the vector. */ vec <T *, V> *m_vector; @@ -744,7 +744,7 @@ protected: private: /* Indication if we use ggc summary. */ - virtual bool is_ggc () + bool is_ggc () final override { return m_ggc; } @@ -910,7 +910,7 @@ public: void *data); private: - virtual bool is_ggc (); + bool is_ggc () final override; /* Summary is stored in the vector. */ vec <T *, V> *m_vector; diff --git a/gcc/symtab-thunks.cc b/gcc/symtab-thunks.cc index 73f810d..b1d9c5d 100644 --- a/gcc/symtab-thunks.cc +++ b/gcc/symtab-thunks.cc @@ -71,10 +71,10 @@ public: function_summary<thunk_info *> (table, ggc) { } /* Hook that is called by summary when a node is duplicated. */ - virtual void duplicate (cgraph_node *node, - cgraph_node *node2, - thunk_info *data, - thunk_info *data2); + void duplicate (cgraph_node *node, + cgraph_node *node2, + thunk_info *data, + thunk_info *data2) final override; }; /* Duplication hook. */ diff --git a/gcc/target.def b/gcc/target.def index d85adf3..2a7fa68 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -1878,12 +1878,16 @@ access using @var{type} is known to be naturally aligned.", DEFHOOK (vec_perm_const, "This hook is used to test whether the target can permute up to two\n\ -vectors of mode @var{mode} using the permutation vector @code{sel}, and\n\ -also to emit such a permutation. In the former case @var{in0}, @var{in1}\n\ -and @var{out} are all null. In the latter case @var{in0} and @var{in1} are\n\ -the source vectors and @var{out} is the destination vector; all three are\n\ -operands of mode @var{mode}. @var{in1} is the same as @var{in0} if\n\ -@var{sel} describes a permutation on one vector instead of two.\n\ +vectors of mode @var{op_mode} using the permutation vector @code{sel},\n\ +producing a vector of mode @var{mode}. The hook is also used to emit such\n\ +a permutation.\n\ +\n\ +When the hook is being used to test whether the target supports a permutation,\n\ +@var{in0}, @var{in1}, and @var{out} are all null. When the hook is being used\n\ +to emit a permutation, @var{in0} and @var{in1} are the source vectors of mode\n\ +@var{op_mode} and @var{out} is the destination vector of mode @var{mode}.\n\ +@var{in1} is the same as @var{in0} if @var{sel} describes a permutation on one\n\ +vector instead of two.\n\ \n\ Return true if the operation is possible, emitting instructions for it\n\ if rtxes are provided.\n\ @@ -1894,7 +1898,7 @@ try the equivalent byte operation. If that also fails, it will try forcing\n\ the selector into a register and using the @var{vec_perm@var{mode}}\n\ instruction pattern. There is no need for the hook to handle these two\n\ implementation approaches itself.", - bool, (machine_mode mode, rtx output, rtx in0, rtx in1, + bool, (machine_mode mode, machine_mode op_mode, rtx output, rtx in0, rtx in1, const vec_perm_indices &sel), NULL) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ef7e0b4..677e064 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,275 @@ +2022-05-29 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/105732 + * c-c++-common/cpp/va-opt-10.c: New test. + +2022-05-28 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.dg/gomp/declare-target-2.f90: Add 'enter' clause test. + * gfortran.dg/gomp/declare-target-4.f90: Likewise. + +2022-05-28 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/declare-target-2.c: Add further tests for mixing of + link and to/enter clauses on separate directives. + +2022-05-28 Jason Merrill <jason@redhat.com> + + PR c++/105652 + * g++.dg/cpp2a/concepts-lambda20.C: New test. + +2022-05-27 Marek Polacek <polacek@redhat.com> + + PR c++/105725 + * g++.dg/warn/Wmismatched-tags-10.C: New test. + +2022-05-27 Marek Polacek <polacek@redhat.com> + + PR c/90658 + * c-c++-common/attr-cdtor-1.c: New test. + +2022-05-27 Tobias Burnus <tobias@codesourcery.com> + Chung-Lin Tang <cltang@codesourcery.com> + + * gfortran.dg/gomp/requires-4.f90: Update dg-error. + * gfortran.dg/gomp/requires-8.f90: Update dg-error. + +2022-05-27 Martin Jambor <mjambor@suse.cz> + + PR ipa/105639 + * gcc.dg/ipa/pr105639.c: New test. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/clauses-3.c: Add tests with enter clause instead + of to or modify some existing to clauses to enter. + * c-c++-common/gomp/declare-target-1.c: Likewise. + * c-c++-common/gomp/declare-target-2.c: Likewise. + * c-c++-common/gomp/declare-target-3.c: Likewise. + * g++.dg/gomp/attrs-9.C: Likewise. + * g++.dg/gomp/declare-target-1.C: Likewise. + +2022-05-27 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105726 + * g++.dg/warn/Warray-bounds-27.C: New testcase. + +2022-05-27 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/105729 + * g++.dg/ubsan/pr105729.C: New test. + +2022-05-27 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.dg/pr98865.c: New test case. + +2022-05-27 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.target/i386/pr91400-1.c: Update for improved code generation. + * gcc.target/i386/pr91400-2.c: Likewise. + * gcc.target/i386/testnot-1.c: New test case. + * gcc.target/i386/testnot-2.c: Likewise. + +2022-05-27 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * gcc.target/xtensa/bswap.c: Remove test. + * gcc.target/xtensa/bswap-O1.c: New. + * gcc.target/xtensa/bswap-O2.c: Ditto. + * gcc.target/xtensa/bswap-Os.c: Ditto. + +2022-05-26 Marek Polacek <polacek@redhat.com> + + PR c++/105569 + * g++.dg/warn/Waddress-9.C: New test. + +2022-05-26 Patrick Palka <ppalka@redhat.com> + + PR c++/96363 + * g++.dg/cpp2a/concepts-partial-spec12.C: New test. + * g++.dg/cpp2a/concepts-partial-spec12a.C: New test. + * g++.dg/cpp2a/concepts-partial-spec13.C: New test. + +2022-05-25 Marek Polacek <polacek@redhat.com> + + PR c++/96637 + * g++.dg/parse/error64.C: New test. + +2022-05-25 Jason Merrill <jason@redhat.com> + + PR c++/105655 + * g++.dg/cpp2a/class-deduction-alias13.C: New test. + +2022-05-25 Jason Merrill <jason@redhat.com> + + PR c++/105623 + * g++.dg/cpp1y/auto-fn62.C: New test. + +2022-05-25 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp1y/constexpr-local4.C: New test. + +2022-05-25 Marek Polacek <polacek@redhat.com> + + PR c++/100252 + * g++.dg/cpp1y/nsdmi-aggr14.C: New test. + * g++.dg/cpp1y/nsdmi-aggr15.C: New test. + * g++.dg/cpp1y/nsdmi-aggr16.C: New test. + * g++.dg/cpp1y/nsdmi-aggr17.C: New test. + * g++.dg/cpp1y/nsdmi-aggr18.C: New test. + * g++.dg/cpp1y/nsdmi-aggr19.C: New test. + +2022-05-25 Jakub Jelinek <jakub@redhat.com> + + PR c/91134 + * gcc.dg/pr91134.c: New test. + +2022-05-25 Richard Biener <rguenther@suse.de> + + * gcc.dg/loop-unswitch-10.c: Fix misspelled defaut: + * gcc.dg/loop-unswitch-11.c: Likewise. + * gcc.dg/loop-unswitch-14.c: Likewise. + +2022-05-25 Jakub Jelinek <jakub@redhat.com> + + PR sanitizer/105714 + * gcc.dg/asan/pr105714.c: New test. + +2022-05-25 Martin Liska <mliska@suse.cz> + Richard Biener <rguenther@suse.de> + + * gcc.dg/loop-unswitch-7.c: New test. + * gcc.dg/loop-unswitch-8.c: New test. + * gcc.dg/loop-unswitch-9.c: New test. + * gcc.dg/loop-unswitch-10.c: New test. + * gcc.dg/loop-unswitch-11.c: New test. + * gcc.dg/loop-unswitch-12.c: New test. + * gcc.dg/loop-unswitch-13.c: New test. + * gcc.dg/loop-unswitch-14.c: New test. + * gcc.dg/loop-unswitch-15.c: New test. + * gcc.dg/loop-unswitch-16.c: New test. + * gcc.dg/loop-unswitch-17.c: New test. + * gcc.dg/torture/20220518-1.c: New test. + * gcc.dg/torture/20220518-2.c: New test. + * gcc.dg/torture/20220525-1.c: New test. + * gcc.dg/alias-10.c: Adjust. + * gcc.dg/tree-ssa/loop-6.c: Likewise. + * gcc.dg/loop-unswitch-1.c: Likewise. + +2022-05-25 Szabolcs Nagy <szabolcs.nagy@arm.com> + + PR target/104689 + * gcc.target/aarch64/pr104689.c: New test. + +2022-05-24 Martin Sebor <msebor@redhat.com> + Richard Biener <rguenther@suse.de> + + PR middle-end/105604 + * gcc.dg/Wrestrict-24.c: New test. + * gcc.dg/Wrestrict-25.c: New test. + * gcc.dg/Wrestrict-26.c: New test. + +2022-05-24 Joel Brobecker <brobecker@adacore.com> + + * gcc.misc-tests/outputs.exp: Make the -gsplit-dwarf test + a compile-and-link test rather than a compile-only test. + +2022-05-24 Jason Merrill <jason@redhat.com> + + PR c++/105622 + * g++.dg/cpp2a/no_unique_address14.C: New test. + +2022-05-24 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.target/i386/neg-zext-1.c: New test case for -m32. + * gcc.target/i386/neg-zext-2.c: New test case for -m64. + +2022-05-24 Roger Sayle <roger@nextmovesoftware.com> + + PR tree-optimization/105668 + * gcc.target/i386/pr105668.c: New test case. + +2022-05-24 Patrick Palka <ppalka@redhat.com> + + * g++.dg/cpp0x/constexpr-52830a.C: New test. + +2022-05-24 ShiYulong <shiyulong@iscas.ac.cn> + + * gcc.target/riscv/cmo-zicbom-1.c: New test. + * gcc.target/riscv/cmo-zicbom-2.c: New test. + * gcc.target/riscv/cmo-zicbop-1.c: New test. + * gcc.target/riscv/cmo-zicbop-2.c: New test. + * gcc.target/riscv/cmo-zicboz-1.c: New test. + * gcc.target/riscv/cmo-zicboz-2.c: New test. + +2022-05-24 Richard Biener <rguenther@suse.de> + + PR middle-end/105711 + * gcc.target/i386/pr105711.c: New testcase. + +2022-05-24 Tobias Burnus <tobias@codesourcery.com> + + PR c/105378 + * gfortran.dg/gomp/taskwait-depend-nowait-1.f90: New. + +2022-05-24 Vineet Gupta <vineetg@rivosinc.com> + + * gcc.target/riscv/pr105666.c: New test. + +2022-05-24 Jakub Jelinek <jakub@redhat.com> + + PR c/105378 + * c-c++-common/gomp/taskwait-depend-nowait-1.c: New test. + +2022-05-24 Richard Biener <rguenther@suse.de> + + PR tree-optimization/100221 + * gcc.dg/tree-ssa/ssa-dse-44.c: New testcase. + * gcc.dg/tree-ssa/ssa-dse-45.c: Likewise. + +2022-05-24 Kewen Lin <linkw@linux.ibm.com> + + PR testsuite/105706 + * gcc.target/powerpc/pr78604.c: Adjust. + +2022-05-24 Kewen Lin <linkw@linux.ibm.com> + + PR target/105627 + * gcc.target/powerpc/pr105627.c: New test. + +2022-05-23 H.J. Lu <hjl.tools@gmail.com> + + PR target/104441 + * gcc.target/i386/pr104441-1a.c (load8bit_4x4_avx2): Initialize + src23. + +2022-05-23 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/plugin/analyzer_gil_plugin.c: Replace uses of "FINAL" and + "OVERRIDE" with "final" and "override". + +2022-05-23 Mayshao <mayshao-oc@zhaoxin.com> + + * gcc.target/i386/funcspec-56.inc: Test -arch=lujiauzi and -tune=lujiazui. + * g++.target/i386/mv32.C: Ditto. + +2022-05-23 Dimitar Dimitrov <dimitar@dinux.eu> + + * gcc.dg/mallign.c: Skip check if sizeof(word)==1. + +2022-05-23 Richard Biener <rguenther@suse.de> + + * gcc.dg/gimplefe-27.c: Adjust. + * gcc.dg/gimplefe-45.c: Likewise. + * gcc.dg/pr101145-2.c: Likewise. + * gcc.dg/pr98211.c: Likewise. + * gcc.dg/torture/pr89595.c: Likewise. + * gcc.dg/tree-ssa/divide-7.c: Likewise. + * gcc.dg/tree-ssa/ssa-lim-12.c: Likewise. + +2022-05-23 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/spill_to_mask-1.c: New test. + 2022-05-21 Dimitar Dimitrov <dimitar@dinux.eu> * gcc.dg/tree-ssa/gen-vect-11.c: For PRU target, skip the diff --git a/gcc/testsuite/c-c++-common/attr-cdtor-1.c b/gcc/testsuite/c-c++-common/attr-cdtor-1.c new file mode 100644 index 0000000..ea61336 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-cdtor-1.c @@ -0,0 +1,6 @@ +/* PR c/90658 */ +/* { dg-do compile } */ + +void f (); +void g1 () __attribute__ ((constructor(f))); /* { dg-error "priorities must be integers" } */ +void g2 () __attribute__ ((destructor(f))); /* { dg-error "priorities must be integers" } */ diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-10.c b/gcc/testsuite/c-c++-common/cpp/va-opt-10.c new file mode 100644 index 0000000..f810b42 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-10.c @@ -0,0 +1,18 @@ +/* PR preprocessor/105732 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99" { target c } } */ +/* { dg-options "-std=c++20" { target c++ } } */ + +#define m1(p1, p2, p3) p3 +#define m2(p1, ...) 1##__VA_OPT__(foo) +#define m3(...) m1(1, 2, m2) +#define m4(p1, ...) 1 __VA_OPT__() +#define m5(...) m1(1, 2, m4) +#if m3(,)(,) +#else +#error +#endif +#if m5(,)(,) +#else +#error +#endif diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-3.c b/gcc/testsuite/c-c++-common/gomp/clauses-3.c index 7e07a81..5618a91 100644 --- a/gcc/testsuite/c-c++-common/gomp/clauses-3.c +++ b/gcc/testsuite/c-c++-common/gomp/clauses-3.c @@ -3,6 +3,8 @@ struct S { int *s; char u; struct T v; long x; }; void bar (int *); #pragma omp declare target to (bar) +void baz (int *); +#pragma omp declare target enter (baz) int main () @@ -18,6 +20,6 @@ main () #pragma omp target map (s.s[0]) map (s.v.b[:3]) ; #pragma omp target map (s.s[0]) map (s.v.b[:3]) - bar (s.s); + baz (s.s); return 0; } diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-1.c b/gcc/testsuite/c-c++-common/gomp/declare-target-1.c index a1f1ea7..79ad556 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-target-1.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-1.c @@ -10,4 +10,4 @@ long c; #pragma omp end declare target #pragma omp declare target (bar, a) -#pragma omp declare target to (b) link (d) to (foo) +#pragma omp declare target to (b) link (d) enter (foo) diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-2.c b/gcc/testsuite/c-c++-common/gomp/declare-target-2.c index c7a325c..97602dc 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-target-2.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-2.c @@ -7,9 +7,25 @@ extern int a; #pragma omp end declare target int b; #pragma omp declare target to (b) link (b) /* { dg-error "appears more than once on the same .declare target. directive" } */ +#pragma omp declare target enter (b) link (b) /* { dg-error "appears more than once on the same .declare target. directive" } */ int c; #pragma omp declare target (c) -#pragma omp declare target link (c) /* { dg-error "specified both in declare target" } */ +#pragma omp declare target link (c) /* { dg-error "specified both in declare target 'link' and 'to' or 'enter' clauses" } */ +int c2; +#pragma omp declare target to (c2) +#pragma omp declare target link (c2) /* { dg-error "specified both in declare target 'link' and 'to' or 'enter' clauses" } */ +int c3; +#pragma omp declare target enter (c3) +#pragma omp declare target link (c3) /* { dg-error "specified both in declare target 'link' and 'to' or 'enter' clauses" } */ +int c4; +#pragma omp declare target link (c4) +#pragma omp declare target (c4) /* { dg-error "specified both in declare target 'link' and 'enter' clauses" } */ +int c5; +#pragma omp declare target link (c5) +#pragma omp declare target to (c5) /* { dg-error "specified both in declare target 'link' and 'to' clauses" } */ +int c6; +#pragma omp declare target link (c6) +#pragma omp declare target enter (c6) /* { dg-error "specified both in declare target 'link' and 'enter' clauses" } */ int foo (void); #pragma omp declare target link (foo) /* { dg-error "is not a variable in clause" } */ struct S; @@ -32,9 +48,13 @@ int m; #pragma omp declare target to (k) #pragma omp declare target (k) #pragma omp declare target to (k, m) link (l) +#pragma omp declare target enter (k, m) link (l) #pragma omp declare target link (l) int n, o, s, t; #pragma omp declare target to (n) to (n) /* { dg-error "appears more than once on the same .declare target. directive" } */ +#pragma omp declare target enter (n) enter (n) /* { dg-error "appears more than once on the same .declare target. directive" } */ +#pragma omp declare target enter (n) to (n) /* { dg-error "appears more than once on the same .declare target. directive" } */ +#pragma omp declare target to (n) enter (n) /* { dg-error "appears more than once on the same .declare target. directive" } */ #pragma omp declare target link (o, o) /* { dg-error "appears more than once on the same .declare target. directive" } */ #pragma omp declare target (s, t, s) /* { dg-error "appears more than once on the same .declare target. directive" } */ int p, q, r; diff --git a/gcc/testsuite/c-c++-common/gomp/declare-target-3.c b/gcc/testsuite/c-c++-common/gomp/declare-target-3.c index bf72fda..e76e7a3 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-target-3.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-target-3.c @@ -15,10 +15,13 @@ extern int f[]; #pragma omp declare target to (f) /* { dg-error "'f' does not have a mappable type in 'to' clause" } */ extern int g[]; #pragma omp declare target to (g) /* { dg-error "'g' does not have a mappable type in 'to' clause" } */ +extern int g2[]; +#pragma omp declare target enter (g2) /* { dg-error "'g2' does not have a mappable type in 'enter' clause" } */ int g[3]; extern int h[]; int h[3]; #pragma omp declare target to (h) +#pragma omp declare target enter (h) int i[] = { 1, 2, 3 }; int j[] = { 1, 2, 3 }; diff --git a/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c b/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c new file mode 100644 index 0000000..54df023 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c @@ -0,0 +1,17 @@ +void +foo (int *p) +{ + #pragma omp taskwait depend(iterator(i = 0:16) , in : p[i]) nowait depend(out : p[32]) +} + +void +bar (int *p) +{ + #pragma omp taskwait depend(mutexinoutset : p[0]) nowait /* { dg-error "'mutexinoutset' kind in 'depend' clause on a 'taskwait' construct" } */ +} + +void +baz (void) +{ + #pragma omp taskwait nowait /* { dg-error "'taskwait' construct with 'nowait' clause but no 'depend' clauses" } */ +} diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-52830a.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-52830a.C new file mode 100644 index 0000000..224f2cd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-52830a.C @@ -0,0 +1,39 @@ +// PR c++/52830 +// { dg-do compile { target c++11 } } +// { dg-additional-options "-fchecking" } +// A version of constexpr-52830.C that uses an intermediate template template +// parameter. + +template<bool b> struct eif { typedef void type; }; +template<> struct eif<false> {}; + +template<class A, class B> struct same +{ + static constexpr bool value = false; +}; +template<class A> +struct same<A, A> +{ + static constexpr bool value = true; +}; + + +struct foo { + template<class T, template<class, class> class SAME = same> + void func(T && a, + typename eif<SAME<decltype(a), int&&>::value>::type * = 0); +}; + +template<class T, template<class, class> class SAME> +void +foo:: +func(T && a, + typename eif<SAME<decltype(a), int&&>::value>::type * ) +{ +} + +void do_stuff() +{ + foo f; + f.func(12); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn62.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn62.C new file mode 100644 index 0000000..9c2bff1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn62.C @@ -0,0 +1,14 @@ +// PR c++/105623 +// { dg-do compile { target c++14 } } + +template <class T> +auto g(T fn) { } + +template<typename> +struct base { + static auto value() { } +}; + +struct S : base<void> { + static void f() { g(value); } +}; diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-local4.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-local4.C new file mode 100644 index 0000000..bef6248 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-local4.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++14 } } + +struct A +{ + int i; + constexpr A(int i): i(i) {}; +}; + +const A a = 42; + +constexpr int f() +{ + const int j = a.i; // { dg-message "'a'" } + return j; +} + +static_assert (f() == 42,""); // { dg-error "non-constant" } diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C new file mode 100644 index 0000000..28b908a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr14.C @@ -0,0 +1,131 @@ +// PR c++/100252 +// { dg-do run { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + int x; + int y = x; +}; + +struct B { + int x = 0; + int y = A{x}.y; +}; + +constexpr B csb1 = { }; +SA(csb1.x == 0 && csb1.y == csb1.x); +constexpr B csb2 = { 1 }; +SA(csb2.x == 1 && csb2.y == csb2.x); +constexpr B csb3 = { 1, 2 }; +SA(csb3.x == 1 && csb3.y == 2); + +B sb1 = { }; +B sb2 = { 1 }; +B sb3 = { 1, 2}; + +struct C { + int x = 0; + int y = (true, A{x}.y) + (A{x}.y, 0); +}; + +constexpr C csc1 = { }; +SA(csc1.x == 0 && csc1.y == csc1.x); +constexpr C csc2 = { 1 }; +SA(csc2.x == 1 && csc2.y == csc2.x); +constexpr C csc3 = { 1, 2 }; +SA(csc3.x == 1 && csc3.y == 2); + +C sc1 = { }; +C sc2 = { 1 }; +C sc3 = { 1, 2}; + +struct D { + int x = 0; + int y = (A{x}.y); +}; + +constexpr D csd1 = { }; +SA(csd1.x == 0 && csd1.y == csd1.x); +constexpr D csd2 = { 1 }; +SA(csd2.x == 1 && csd2.y == csd2.x); +constexpr D csd3 = { 1, 2 }; +SA(csd3.x == 1 && csd3.y == 2); + +D sd1 = { }; +D sd2 = { 1 }; +D sd3 = { 1, 2}; + +struct E { + int x = 0; + int y = x ? A{x}.y : A{x}.y; +}; + +constexpr E cse1 = { }; +SA(cse1.x == 0 && cse1.y == cse1.x); +constexpr E cse2 = { 1 }; +SA(cse2.x == 1 && cse2.y == cse2.x); +constexpr E cse3 = { 1, 2 }; +SA(cse3.x == 1 && cse3.y == 2); + +E se1 = { }; +E se2 = { 1 }; +E se3 = { 1, 2}; + +int +main () +{ + if (sb1.x != 0 || sb1.x != sb1.y) + __builtin_abort(); + if (sb2.x != 1 || sb2.x != sb2.y) + __builtin_abort(); + if (sb3.x != 1 || sb3.y != 2) + __builtin_abort(); + + if (sc1.x != 0 || sc1.x != sc1.y) + __builtin_abort(); + if (sc2.x != 1 || sc2.x != sc2.y) + __builtin_abort(); + if (sc3.x != 1 || sc3.y != 2) + __builtin_abort(); + + B b1 = { }; + B b2 = { 1 }; + B b3 = { 1, 2}; + if (b1.x != 0 || b1.x != b1.y) + __builtin_abort(); + if (b2.x != 1 || b2.x != b2.y) + __builtin_abort(); + if (b3.x != 1 || b3.y != 2) + __builtin_abort(); + + C c1 = { }; + C c2 = { 1 }; + C c3 = { 1, 2}; + if (c1.x != 0 || c1.x != c1.y) + __builtin_abort(); + if (c2.x != 1 || c2.x != c2.y) + __builtin_abort(); + if (c3.x != 1 || c3.y != 2) + __builtin_abort(); + + D d1 = { }; + D d2 = { 1 }; + D d3 = { 1, 2}; + if (d1.x != 0 || d1.x != d1.y) + __builtin_abort(); + if (d2.x != 1 || d2.x != d2.y) + __builtin_abort(); + if (d3.x != 1 || d3.y != 2) + __builtin_abort(); + + E e1 = { }; + E e2 = { 1 }; + E e3 = { 1, 2}; + if (e1.x != 0 || e1.x != e1.y) + __builtin_abort(); + if (e2.x != 1 || e2.x != e2.y) + __builtin_abort(); + if (e3.x != 1 || e3.y != 2) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C new file mode 100644 index 0000000..d091d69 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr15.C @@ -0,0 +1,80 @@ +// PR c++/100252 +// { dg-do run { target c++14 } } + +struct A { + int x; + int y = x; +}; + +struct B { + int x = 0; + int y = A{x}.y; +}; + +static void +test_b (B b1 = B{}, B b2 = B{1}, B b3 = B{1, 2}) +{ + if (b1.x != 0 || b1.y != b1.x) + __builtin_abort(); + if (b2.x != 1 || b2.y != b2.x) + __builtin_abort(); + if (b3.x != 1 || b3.y != 2) + __builtin_abort(); +} + +struct C { + int x = 0; + int y = (true, A{x}.y) + (A{x}.y, 0); +}; + +static void +test_c (C c1 = C{}, C c2 = C{1}, C c3 = C{1, 2}) +{ + if (c1.x != 0 || c1.y != c1.x) + __builtin_abort(); + if (c2.x != 1 || c2.y != c2.x) + __builtin_abort(); + if (c3.x != 1 || c3.y != 2) + __builtin_abort(); +} + +struct D { + int x = 0; + int y = (A{x}.y); +}; + +static void +test_d (D d1 = D{}, D d2 = D{1}, D d3 = D{1, 2}) +{ + if (d1.x != 0 || d1.y != d1.x) + __builtin_abort(); + if (d2.x != 1 || d2.y != d2.x) + __builtin_abort(); + if (d3.x != 1 || d3.y != 2) + __builtin_abort(); +} + +struct E { + int x = 0; + int y = x ? A{x}.y : A{x}.y; +}; + +static void +test_e (E e1 = E{}, E e2 = E{1}, E e3 = E{1, 2}) +{ + if (e1.x != 0 || e1.y != e1.x) + __builtin_abort(); + if (e2.x != 1 || e2.y != e2.x) + __builtin_abort(); + if (e3.x != 1 || e3.y != 2) + __builtin_abort(); +} + +int +main () +{ + test_b (); + test_c (); + test_d (); + test_e (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C new file mode 100644 index 0000000..dc6492c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr16.C @@ -0,0 +1,58 @@ +// PR c++/100252 +// { dg-do compile { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + const A* p = this; +}; + +struct B { + A a = A{}; +}; + +constexpr B b; +SA(b.a.p == &b.a); +B b1 = { }; + +struct C { + A a = (true, A{}); +}; + +constexpr C c; +SA(c.a.p == &c.a); +C c1 = { }; + +struct D { + A a = (A{}); +}; + +constexpr D d; +SA(d.a.p == &d.a); +D d1 = { }; + +static constexpr A global_a; + +struct E { + A a = true ? A{} : A{}; + A b = true ? global_a : (false ? A{} : A{}); + A c = true ? (false ? A{} : A{}) : global_a; + A d = true ? (false ? A{} : A{}) : (false ? A{} : A{}); +}; + +// FIXME: When fixing this, also fix nsdmi-aggr17.C. +constexpr E e; // { dg-bogus "" "PR105550" { xfail *-*-* } } +SA (e.a.p == &e.a); // { dg-bogus "" "PR105550" { xfail *-*-* } } + +E e1 = { }; + +struct F { + bool b = (A{}, true); +}; + +constexpr F f; + +void +g (B b2 = B{}, C c2 = C{}, D d2 = D{}, E e2 = E{}) +{ +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C new file mode 100644 index 0000000..fc27a2c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr17.C @@ -0,0 +1,138 @@ +// PR c++/100252 +// { dg-do run { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + int x; + int y = x; + const A* p = this; +}; + +struct B { + int x = 42; + A a = A{x}; +}; + +constexpr B b; +SA(b.a.p == &b.a); +SA(b.x == 42); +B b2 = { }; +B b3 = { 42 }; + +struct C { + int x = 42; + B b = B{x}; +}; + +constexpr C c; +C c2; +C c3; + +struct D { + int x = 42; + A a = (true, A{x}); +}; + +constexpr D d; +SA(d.a.p == &d.a); +SA(d.x == 42); +D d2 = { }; +D d3 = { 42 }; + +struct E { + int x = 42; + A a = (A{x}); +}; + +constexpr E e; +SA(e.a.p == &e.a); +SA(e.x == 42); +E e2 = { }; +E e3 = { 42 }; + +struct F { + int x = 42; + A a = true ? A{x} : A{x}; +}; + +// FIXME: Doesn't work due to PR105550. +//constexpr F f; +//SA (f.a.p == &f.a); +SA (e.x == 42); +F f2 = { }; +F f3 = { 42 }; + +static void +test_b (B b4 = B{}, B b5 = B{ 42 }) +{ + if (b2.x != 42 || b2.a.x != 42 || b2.a.y != b2.a.x) + __builtin_abort (); + if (b3.x != 42 || b3.a.x != 42 || b3.a.y != b3.a.x) + __builtin_abort (); + if (b4.x != 42 || b4.a.x != 42 || b4.a.y != b4.a.x) + __builtin_abort (); + if (b5.x != 42 || b5.a.x != 42 || b5.a.y != b5.a.x) + __builtin_abort (); +} + +static void +test_c (C c4 = C{}, C c5 = C{ 42 }) +{ + if (c2.b.x != 42 || c2.b.a.x != 42 || c2.b.a.y != c2.b.a.x) + __builtin_abort (); + if (c3.b.x != 42 || c3.b.a.x != 42 || c3.b.a.y != c3.b.a.x) + __builtin_abort (); + if (c4.b.x != 42 || c4.b.a.x != 42 || c4.b.a.y != c4.b.a.x) + __builtin_abort (); + if (c5.b.x != 42 || c5.b.a.x != 42 || c5.b.a.y != c5.b.a.x) + __builtin_abort (); +} + +static void +test_d (D d4 = D{}, D d5 = D{ 42 }) +{ + if (d2.x != 42 || d2.a.x != 42 || d2.a.y != d2.a.x) + __builtin_abort (); + if (d3.x != 42 || d3.a.x != 42 || d3.a.y != d3.a.x) + __builtin_abort (); + if (d4.x != 42 || d4.a.x != 42 || d4.a.y != d4.a.x) + __builtin_abort (); + if (d5.x != 42 || d5.a.x != 42 || d5.a.y != d5.a.x) + __builtin_abort (); +} + +static void +test_e (E e4 = E{}, E e5 = E{ 42 }) +{ + if (e2.x != 42 || e2.a.x != 42 || e2.a.y != e2.a.x) + __builtin_abort (); + if (e3.x != 42 || e3.a.x != 42 || e3.a.y != e3.a.x) + __builtin_abort (); + if (e4.x != 42 || e4.a.x != 42 || e4.a.y != e4.a.x) + __builtin_abort (); + if (e5.x != 42 || e5.a.x != 42 || e5.a.y != e5.a.x) + __builtin_abort (); +} + +static void +test_f (F f4 = F{}, F f5 = F{ 42 }) +{ + if (f2.x != 42 || f2.a.x != 42 || f2.a.y != f2.a.x) + __builtin_abort (); + if (f3.x != 42 || f3.a.x != 42 || f3.a.y != f3.a.x) + __builtin_abort (); + if (f4.x != 42 || f4.a.x != 42 || f4.a.y != f4.a.x) + __builtin_abort (); + if (f5.x != 42 || f5.a.x != 42 || f5.a.y != f5.a.x) + __builtin_abort (); +} +int +main () +{ + test_b (); + test_c (); + test_d (); + test_e (); + test_f (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C new file mode 100644 index 0000000..567b8ee --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr18.C @@ -0,0 +1,56 @@ +// PR c++/100252 +// { dg-do compile { target c++14 } } + +struct B { }; + +struct A { + int x; + int y = x; + constexpr operator B() { return B{}; } +}; + +struct C { + int x = 42; + B b = A{x}; +}; + +C c1 = {}; +C c2 = { 42 }; +constexpr C c3 = {}; +constexpr C c4 = { 42 }; + +struct D { + int x = 42; + B b = (true, A{x}); +}; + +D d1 = {}; +D d2 = { 42 }; +constexpr D d3 = {}; +constexpr D d4 = { 42 }; + +struct E { + int x = 42; + B b = (A{x}); +}; + +E e1 = {}; +E e2 = { 42 }; +constexpr E e3 = {}; +constexpr E e4 = { 42 }; + +struct F { + int x = 42; + B b = (A{x}); +}; + +F f1 = {}; +F f2 = { 42 }; +constexpr F f3 = {}; +constexpr F f4 = { 42 }; + +void +g (C c5 = C{}, C c6 = C{ 42 }, D d5 = D{}, D d6 = D{ 42 }, + E e5 = E{}, E e6 = E{ 42 }, F f5 = F{}, F f6 = F{ 42 }) +{ +} diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C new file mode 100644 index 0000000..f4892e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr19.C @@ -0,0 +1,28 @@ +// PR c++/100252 +// { dg-do compile { target c++14 } } + +#define SA(X) static_assert ((X),#X) + +struct A { + const A* p = this; +}; + +struct B { + A a = (A{}, A{}); +}; + +constexpr B b; +SA(b.a.p == &b.a); + +struct C { + int x; + int y = x; +}; + +struct D { + int x = 0; + int y = (C{x}.y, C{x}.y); +}; + +constexpr D d = { }; +D d2 = {}; diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias13.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias13.C new file mode 100644 index 0000000..0a90a83 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias13.C @@ -0,0 +1,24 @@ +// PR c++/105655 +// { dg-do compile { target c++20 } } + +template <class T> +struct A +{ + template <class L, class R> + struct B + { + B(const L & left, const R & right) + {} + }; + + template <class L, class R> + B(const L &, const R &) -> B<L, R>; +}; + +template <class L, class R> +using C = A<int>::B<L, R>; + +int main() +{ + C x{0, 0}; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda20.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda20.C new file mode 100644 index 0000000..40e5973 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda20.C @@ -0,0 +1,17 @@ +// PR c++/105652 +// { dg-do compile { target c++20 } } +// { dg-additional-options -g } + +template<int> +struct I {}; + +template<class T> +concept C = []<int N>(I<N>) { return true; } (I<0>{}); + +template<class T> +struct S { }; + +template<C T> +struct S<T> { constexpr static bool value = true; }; + +static_assert(S<int>::value); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C new file mode 100644 index 0000000..9bb6e2d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12.C @@ -0,0 +1,10 @@ +// PR c++/96363 +// { dg-do compile { target c++20 } } + +template<class T> class TPL; + +template<class T> requires true class TPL<T>; // #1 +template<class T> requires false class TPL<T>; // #2 error here + +template<class T> requires true class TPL<T*>; // #1 +template<class T> requires false class TPL<T*>; // #2 error here diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12a.C new file mode 100644 index 0000000..6d23a28 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec12a.C @@ -0,0 +1,14 @@ +// PR c++/96363 +// { dg-do compile { target c++20 } } +// A version of concepts-partial-spec12.C where the primary template is +// constrained. + +template<class T> concept C = true; + +template<C T> class TPL; + +template<C T> requires true class TPL<T>; // #1 +template<C T> requires false class TPL<T>; // #2 error here + +template<C T> requires true class TPL<T*>; // #1 +template<C T> requires false class TPL<T*>; // #2 error here diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec13.C b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec13.C new file mode 100644 index 0000000..b5ec2c9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-partial-spec13.C @@ -0,0 +1,16 @@ +// PR c++/99501 +// { dg-do compile { target c++20 } } + +template<auto> struct X; + +template<auto V> requires requires{V.a;} struct X<V>; +template<auto V> requires requires{V.b;} struct X<V>; + +template<auto V> requires requires{V.a;} struct X<V> { static const bool v = false; }; +template<auto V> requires requires{V.b;} struct X<V> { static const bool v = true; }; + +struct A { int a; }; +static_assert(!X<A{}>::v); + +struct B { int b; }; +static_assert(X<B{}>::v); diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C b/gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C new file mode 100644 index 0000000..d3fcd4a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address14.C @@ -0,0 +1,19 @@ +// PR c++/105622 +// { dg-do compile { target c++20 } } + +struct empty { + empty() = default; + constexpr empty(int) { } +}; + +struct container { + empty __begin_ = {}; + [[no_unique_address]] empty __size_ = 0; +}; + +constexpr bool test() { + container s; + return true; +} +static_assert(test()); + diff --git a/gcc/testsuite/g++.dg/gomp/attrs-9.C b/gcc/testsuite/g++.dg/gomp/attrs-9.C index 08cd2b1..19a3b0a 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-9.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-9.C @@ -6,8 +6,8 @@ int a; [[omp::directive (declare target (a))]]; int t; [[omp::sequence (omp::directive (threadprivate (t)))]]; -int b, c; -[[omp::directive (declare target, to (b), link (c))]]; +int b, c, e; +[[omp::directive (declare target, to (b), link (c), enter (e))]]; [[omp::directive (declare target)]]; [[omp::directive (declare target)]]; int d; diff --git a/gcc/testsuite/g++.dg/gomp/declare-target-1.C b/gcc/testsuite/g++.dg/gomp/declare-target-1.C index 9cc32f4..7b270cd 100644 --- a/gcc/testsuite/g++.dg/gomp/declare-target-1.C +++ b/gcc/testsuite/g++.dg/gomp/declare-target-1.C @@ -16,6 +16,7 @@ void f5 (T); #pragma omp declare target (f3) #pragma omp declare target to (f4) // { dg-error "overloaded function name .f4. in clause .to." } #pragma omp declare target to (f5<int>) // { dg-error "template .f5<int>. in clause .to." } +#pragma omp declare target enter (f5<short>) // { dg-error "template .f5<short int>. in clause .enter." } template <int N> void f6 (int) { @@ -35,3 +36,7 @@ int v; #pragma omp declare target (N::M::f7) #pragma omp declare target to (::N::f8) #pragma omp declare target to (::f9) to (::v) +#pragma omp declare target to (::f9, ::v) +#pragma omp declare target enter (::N::f8) +#pragma omp declare target enter (::f9) enter (::v) +#pragma omp declare target enter (::f9, ::v) diff --git a/gcc/testsuite/g++.dg/parse/error64.C b/gcc/testsuite/g++.dg/parse/error64.C new file mode 100644 index 0000000..87848a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/error64.C @@ -0,0 +1,4 @@ +// PR c++/96637 +// { dg-do compile } + +void foo(int[] alignas[1] alignas(1)){} // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/ubsan/pr105729.C b/gcc/testsuite/g++.dg/ubsan/pr105729.C new file mode 100644 index 0000000..fb67663 --- /dev/null +++ b/gcc/testsuite/g++.dg/ubsan/pr105729.C @@ -0,0 +1,29 @@ +// PR sanitizer/105729 +// { dg-do run } +// { dg-options "-fsanitize=null -fno-sanitize-recover=null" } + +int +foo (int x) +{ + throw 0; +} + +struct S {}; +struct T { + S *data; + T () : data (0) {} + const S &bar (int x) const { return data[foo (x)]; } +}; + +int +main () +{ + T t; + try + { + t.bar (-1); + } + catch (...) + { + } +} diff --git a/gcc/testsuite/g++.dg/warn/Waddress-9.C b/gcc/testsuite/g++.dg/warn/Waddress-9.C new file mode 100644 index 0000000..d3e4697 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Waddress-9.C @@ -0,0 +1,31 @@ +// PR c++/105569 +// { dg-do compile { target c++11 } } +// { dg-options -Waddress } + +class A {}; + +class B : public virtual A {}; + +class C : public A {}; + +int main() { + B* object = new B(); + B &ref = *object; + + bool b = nullptr == dynamic_cast<A*>(&ref); // { dg-warning "the address of 'ref' will never be NULL" } + bool b4 = nullptr == static_cast<A*>(&ref); // { dg-warning "the address of 'ref' will never be NULL" } + if (dynamic_cast<A*>(&ref)) // { dg-warning "the address of 'ref' will never be NULL" } + { + } + if (static_cast<A*>(&ref)) // { dg-warning "the address of 'ref' will never be NULL" } + { + } + + auto ptr = dynamic_cast<A*>(&ref); + bool b2 = ptr == nullptr; + + C* cobject = new C(); + C &cref = *cobject; + + bool b3 = nullptr == dynamic_cast<A*>(&cref); +} diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-27.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-27.C new file mode 100644 index 0000000..06ce089 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-27.C @@ -0,0 +1,16 @@ +// PR105726 +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-options "-O2 -Warray-bounds" } + +#include <array> +#include <cstring> + +struct X { + char pad[4]; + std::array<char, 1> mField; +}; + +void encode(char* aBuffer, const X& aMessage) { + strncpy(aBuffer, aMessage.mField.data(), 1); // { dg-bogus "bounds" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-tags-10.C b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-10.C new file mode 100644 index 0000000..d7e1074 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-tags-10.C @@ -0,0 +1,10 @@ +// PR c++/105725 +// { dg-do compile { target c++14 } } +// { dg-options "-Wall -Wmismatched-tags" } + +template <bool> struct enable_if; +template <bool Cond> using enable_if_t = typename enable_if<Cond>::type; +template <typename> bool is_class_v; +template <class, class> bool B; +template <class T> +bool B<T, enable_if_t<is_class_v<class T::foo>>>; diff --git a/gcc/testsuite/gcc.dg/Wrestrict-24.c b/gcc/testsuite/gcc.dg/Wrestrict-24.c new file mode 100644 index 0000000..d224d80 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wrestrict-24.c @@ -0,0 +1,35 @@ +/* PR tree-optimization/105604 - ICE: in tree_to_shwi with vla in struct + and sprintf + { dg-do compile } + { dg-options "-O2 -Wall -Wrestrict" } */ + +extern int sprintf (char*, const char*, ...); + +extern void* sink (void*, ...); + +struct { + long users; + long size; + char *data; +} * main_trans; + +void *main___trans_tmp_1; + +int users = 0; + +void test (void) +{ + struct { + long users; + long size; + char *data; + int links[users]; + char buf[]; + } *trans = sink (0); + + trans->data = trans->buf; + main___trans_tmp_1 = trans; + main_trans = main___trans_tmp_1; + sprintf (main_trans->data, "test"); + sink (main_trans->data); +} diff --git a/gcc/testsuite/gcc.dg/Wrestrict-25.c b/gcc/testsuite/gcc.dg/Wrestrict-25.c new file mode 100644 index 0000000..a15f56d --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wrestrict-25.c @@ -0,0 +1,165 @@ +/* PR tree-optimization/105604 - ICE: in tree_to_shwi with vla in struct + and sprintf + { dg-do compile } + { dg-options "-O2 -Wall -Wrestrict" } */ + +extern int sprintf (char*, const char*, ...); + +void* sink (void*); + + +void sprintf_S_a8_an_bn (int n, int i, int j) +{ + struct { + char a8[8], an[n], bn[n]; + } *p = sink (0); + + { + char *d = p->a8 + i; + char *s = p->a8; + sprintf (d, "%s", s); // { dg-warning "argument 3 may overlap" } + sink (p); + } + + { + char *d = p->a8; + char *s = p->a8 + j; + sprintf (d, "%s", s); // { dg-warning "argument 3 may overlap" } + sink (p); + } + + { + char *d = p->a8 + i; + char *s = p->a8 + j; + sprintf (d, "%s", s); // { dg-warning "argument 3 may overlap" } + sink (p); + } + + { + char *d = p->a8 + i; + char *s = p->an; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->a8; + char *s = p->an + j; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->a8 + i; + char *s = p->an + j; + sprintf (d, "%s", s); + sink (p); + } + + { + /* The IL makes it impossible to rule out an overlap between + p->a8 + i and p->bn + i so the "may overlap" warning triggers. */ + char *d = p->a8 + i; + char *s = p->bn; + sprintf (d, "%s", s); // { dg-bogus "-Wrestrict" "pr??????" { xfail *-*-* } } + sink (p); + } + + { + char *d = p->a8; + char *s = p->bn + j; + sprintf (d, "%s", s); // { dg-bogus "-Wrestrict" "pr??????" { xfail *-*-* } } + sink (p); + } + + { + char *d = p->a8 + i; + char *s = p->bn + j; + sprintf (d, "%s", s); // { dg-bogus "-Wrestrict" "pr??????" { xfail *-*-* } } + sink (p); + } + + { + char *d = p->an + i; + char *s = p->bn; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->an; + char *s = p->bn + j; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->an + i; + char *s = p->bn + j; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->an + i; + char *s = p->a8; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->an; + char *s = p->a8 + j; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->an + i; + char *s = p->a8 + j; + sprintf (d, "%s", s); + sink (p); + } + + { + char *d = p->bn + i; + char *s = p->a8; + sprintf (d, "%s", s); // { dg-bogus "-Wrestrict" "pr??????" { xfail *-*-* } } + sink (p); + } + + { + char *d = p->bn; + char *s = p->a8 + j; + sprintf (d, "%s", s); // { dg-bogus "-Wrestrict" "pr??????" { xfail *-*-* } } + sink (p); + } + + { + char *d = p->bn + i; + char *s = p->a8 + j; + sprintf (d, "%s", s); // { dg-bogus "-Wrestrict" "pr??????" { xfail *-*-* } } + sink (p); + } + + { + char *d = p->bn + i; + char *s = p->bn; + sprintf (d, "%s", s); // { dg-warning "may overlap" } + sink (p); + } + + { + char *d = p->bn; + char *s = p->bn + j; + sprintf (d, "%s", s); // { dg-warning "may overlap" } + sink (p); + } + + { + char *d = p->bn + i; + char *s = p->bn + j; + sprintf (d, "%s", s); // { dg-warning "may overlap" } + sink (p); + } +} diff --git a/gcc/testsuite/gcc.dg/Wrestrict-26.c b/gcc/testsuite/gcc.dg/Wrestrict-26.c new file mode 100644 index 0000000..a10c426 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wrestrict-26.c @@ -0,0 +1,114 @@ +/* Verify that sprintf calls with arrays or struct of arrays don't + cause -Wrestrict false positives. + { dg-do compile } + { dg-options "-O2 -Wall -Wrestrict -ftrack-macro-expansion=0" } */ + +#define sprintf(d, f, ...) (sprintf (d, f, __VA_ARGS__), sink (d)) + +extern void sink (void*, ...); +extern int (sprintf) (char*, const char*, ...); + +extern char ca[][2][8]; + +void test_array_of_arrays (void) +{ + sprintf (ca[0][0], "%s", ca[0][0]); // { dg-warning "-Wrestrict" } + sprintf (ca[0][0], "%s", ca[0][1]); + sprintf (ca[0][0], "%s", ca[1][0]); + sprintf (ca[0][0], "%s", ca[1][1]); + + sprintf (ca[0][1], "%s", ca[0][0]); + sprintf (ca[0][1], "%s", ca[0][1]); // { dg-warning "-Wrestrict" } + sprintf (ca[0][1], "%s", ca[1][0]); + sprintf (ca[0][1], "%s", ca[1][1]); + + sprintf (ca[1][0], "%s", ca[0][0]); + sprintf (ca[1][0], "%s", ca[0][1]); + sprintf (ca[1][0], "%s", ca[1][0]); // { dg-warning "-Wrestrict" } + sprintf (ca[1][0], "%s", ca[1][1]); + + sprintf (ca[1][1], "%s", ca[0][0]); + sprintf (ca[1][1], "%s", ca[0][1]); + sprintf (ca[1][1], "%s", ca[1][0]); + sprintf (ca[1][1], "%s", ca[1][1]); // { dg-warning "-Wrestrict" } +} + + +struct A +{ + char a[2][2][8]; + char b[2][2][8]; + char c[2][2][8]; +}; + +extern struct A aa[][2]; + +void test_array_of_structs (void) +{ + // Verify that calls with the same elements of the same array trigger + // warnings as expected. + sprintf (aa[0][0].a[0][0], "%s", aa[0][0].a[0][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][0].a[0][1], "%s", aa[0][0].a[0][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][0].a[1][0], "%s", aa[0][0].a[1][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][0].a[1][1], "%s", aa[0][0].a[1][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][1].a[0][0], "%s", aa[0][1].a[0][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][1].a[0][1], "%s", aa[0][1].a[0][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][1].a[1][0], "%s", aa[0][1].a[1][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[0][1].a[1][1], "%s", aa[0][1].a[1][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][0].a[0][0], "%s", aa[1][0].a[0][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][0].a[0][1], "%s", aa[1][0].a[0][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][0].a[1][0], "%s", aa[1][0].a[1][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][0].a[1][1], "%s", aa[1][0].a[1][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][1].a[0][0], "%s", aa[1][1].a[0][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][1].a[0][1], "%s", aa[1][1].a[0][1]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][1].a[1][0], "%s", aa[1][1].a[1][0]); // { dg-warning "-Wrestrict" } + sprintf (aa[1][1].a[1][1], "%s", aa[1][1].a[1][1]); // { dg-warning "-Wrestrict" } + +#define NOWARN() + + // Exhaustively verify that calls with different elements of the same + // array don't cause false positives. +#undef NOWARN +#define NOWARN(D, S) \ + sprintf (D[0][0], "%s", S[0][0]); \ + sprintf (D[0][0], "%s", S[0][1]); \ + sprintf (D[0][0], "%s", S[1][0]); \ + sprintf (D[0][0], "%s", S[1][1]); \ + sprintf (D[0][1], "%s", S[0][0]); \ + sprintf (D[0][1], "%s", S[0][1]); \ + sprintf (D[0][1], "%s", S[1][0]); \ + sprintf (D[0][1], "%s", S[1][1]); \ + sprintf (D[1][0], "%s", S[0][0]); \ + sprintf (D[1][0], "%s", S[0][1]); \ + sprintf (D[1][0], "%s", S[1][0]); \ + sprintf (D[1][0], "%s", S[1][1]); \ + sprintf (D[1][1], "%s", S[0][0]); \ + sprintf (D[1][1], "%s", S[0][1]); \ + sprintf (D[1][1], "%s", S[1][0]); \ + sprintf (D[1][1], "%s", S[1][1]) + + NOWARN (aa[0][0].a, aa[0][1].a); + NOWARN (aa[0][0].a, aa[1][0].a); + NOWARN (aa[0][0].a, aa[1][1].a); + + NOWARN (aa[0][1].a, aa[0][0].a); + NOWARN (aa[0][1].a, aa[1][0].a); + NOWARN (aa[0][1].a, aa[1][1].a); + + NOWARN (aa[1][0].a, aa[0][0].a); + NOWARN (aa[1][0].a, aa[0][1].a); + NOWARN (aa[1][0].a, aa[1][1].a); + +#define NOWARN_MEM(M1, M2) \ + NOWARN (aa[0][0].M1, aa[0][0].M2); \ + NOWARN (aa[0][0].M1, aa[0][1].M2); \ + NOWARN (aa[0][0].M1, aa[1][0].M2); \ + NOWARN (aa[0][0].M1, aa[1][1].M2) + + NOWARN_MEM (a, b); + NOWARN_MEM (a, c); + NOWARN_MEM (b, a); + NOWARN_MEM (b, c); + NOWARN_MEM (c, a); + NOWARN_MEM (c, b); +} diff --git a/gcc/testsuite/gcc.dg/alias-10.c b/gcc/testsuite/gcc.dg/alias-10.c index 95d8b19..8472d30 100644 --- a/gcc/testsuite/gcc.dg/alias-10.c +++ b/gcc/testsuite/gcc.dg/alias-10.c @@ -28,4 +28,4 @@ void foo (bitmap head, bitmap_element *elt) } -/* { dg-final { scan-tree-dump-times "Unswitching" 1 "unswitch"} } */ +/* { dg-final { scan-tree-dump-times "unswitching" 1 "unswitch"} } */ diff --git a/gcc/testsuite/gcc.dg/asan/pr105714.c b/gcc/testsuite/gcc.dg/asan/pr105714.c new file mode 100644 index 0000000..d378b8a --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/pr105714.c @@ -0,0 +1,33 @@ +/* PR sanitizer/105714 */ +/* { dg-do run } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-Os" } } */ +/* { dg-shouldfail "asan" } */ + +struct A { int x; }; +struct A b[2]; +struct A *c = b, *d = b; +int e; + +int +foo () +{ + for (e = 0; e < 1; e++) + { + int i[1]; + i; + } + for (int h = 0; h < 3; h++) + *c = *d; + *c = *(b + 3); + return c->x; +} + +int +main () +{ + foo (); + return 0; +} + +/* { dg-output "ERROR: AddressSanitizer: global-buffer-overflow on address.*(\n|\r\n|\r)" } */ +/* { dg-output "READ of size.*" } */ diff --git a/gcc/testsuite/gcc.dg/ipa/pr105639.c b/gcc/testsuite/gcc.dg/ipa/pr105639.c new file mode 100644 index 0000000..5534fe9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr105639.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O -w" } */ + +void typedef (*cb) (void); + +static void +bar (cb *fp) +{ + (*fp) (); +} + +void +foo (void) +{ + bar (foo); +} diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-1.c b/gcc/testsuite/gcc.dg/loop-unswitch-1.c index f9d628d..196cb64 100644 --- a/gcc/testsuite/gcc.dg/loop-unswitch-1.c +++ b/gcc/testsuite/gcc.dg/loop-unswitch-1.c @@ -33,4 +33,4 @@ parse_tag: ; } /* Test that we actually unswitched something. */ -/* { dg-final { scan-tree-dump "Unswitching loop" "unswitch" } } */ +/* { dg-final { scan-tree-dump "unswitching loop" "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-10.c b/gcc/testsuite/gcc.dg/loop-unswitch-10.c new file mode 100644 index 0000000..395167e --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-10.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +int +__attribute__((noipa)) +foo(double *a, double *b, double *c, double *d, double *r, int size, int order) +{ + for (int i = 0; i < size; i++) + { + double tmp, tmp2; + + switch(order) + { + case 0: + tmp = -8 * a[i]; + tmp2 = 2 * b[i]; + break; + case 1: + tmp = 3 * a[i] - 2 * b[i]; + tmp2 = 5 * b[i] - 2 * c[i]; + break; + case 2: + tmp = 9 * a[i] + 2 * b[i] + c[i]; + tmp2 = 4 * b[i] + 2 * c[i] + 8 * d[i]; + break; + case 3: + tmp = 3 * a[i] + 2 * b[i] - c[i]; + tmp2 = b[i] - 2 * c[i] + 8 * d[i]; + break; + default: + __builtin_unreachable (); + } + + double x = 3 * tmp + d[i] + tmp; + double y = 3.4f * tmp + d[i] + tmp2; + r[i] = x + y; + } + + return 0; +} + +#define N 16 * 1024 +double aa[N], bb[N], cc[N], dd[N], rr[N]; + +int main() +{ + for (int i = 0; i < 100 * 1000; i++) + foo (aa, bb, cc, dd, rr, N, i % 4); +} + + +/* Test that we actually unswitched something. */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 0" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 1" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 2" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 3" 1 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-11.c b/gcc/testsuite/gcc.dg/loop-unswitch-11.c new file mode 100644 index 0000000..422a942 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-11.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +int +foo(double *a, double *b, double *c, double *d, double *r, int size, int order) +{ + for (int i = 0; i < size; i++) + { + double tmp, tmp2; + + switch(order) + { + case 5 ... 6: + case 9: + tmp = -8 * a[i]; + tmp2 = 2 * b[i]; + break; + case 11: + tmp = 3 * a[i] - 2 * b[i]; + tmp2 = 5 * b[i] - 2 * c[i]; + break; + case 22: + tmp = 9 * a[i] + 2 * b[i] + c[i]; + tmp2 = 4 * b[i] + 2 * c[i] + 8 * d[i]; + break; + case 33: + tmp = 3 * a[i] + 2 * b[i] - c[i]; + tmp2 = b[i] - 2 * c[i] + 8 * d[i]; + break; + default: + __builtin_unreachable (); + } + + double x = 3 * tmp + d[i] + tmp; + double y = 3.4f * tmp + d[i] + tmp2; + r[i] = x + y; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* \\+ 4294967291.*order.* == 9" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 1" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 2" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 3" 1 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-12.c b/gcc/testsuite/gcc.dg/loop-unswitch-12.c new file mode 100644 index 0000000..052c456 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-12.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +int +foo(double *a, double *b, double *c, double *d, double *r, int size, int order) +{ + for (int i = 0; i < size; i++) + { + double tmp; + + if (order == 1) + tmp = -8 * a[i]; + else + tmp = -4 * b[i]; + + double x = 3 * tmp + d[i] + tmp; + + if (order == 1) + x += 2; + + double y = 3.4f * tmp + d[i]; + r[i] = x + y; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "unswitching loop . on .if. with condition: order.* == 1" 1 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-13.c b/gcc/testsuite/gcc.dg/loop-unswitch-13.c new file mode 100644 index 0000000..d09c4aa --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-13.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fno-thread-jumps -fdump-tree-unswitch-optimized" } */ + +int +foo(double *a, double *b, double *c, double *d, double *r, int size, unsigned order) +{ + for (int i = 0; i < size; i++) + { + double tmp; + + switch (order) + { + case 0 ... 4: + tmp = -8 * a[i]; + break; + default: + tmp = -4 * b[i]; + break; + } + + double x = 3 * tmp + d[i] + tmp; + + /* This and the case 0 ... 4 condition should only be unswitched once + since they are mutually excluded. */ + if (order >= 5) + x += 2; + + double y = 3.4f * tmp + d[i]; + r[i] = x + y; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "unswitching loop . on .\[^\n\r\]*. with condition" 1 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-14.c b/gcc/testsuite/gcc.dg/loop-unswitch-14.c new file mode 100644 index 0000000..d9d3168 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-14.c @@ -0,0 +1,60 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized --param=max-unswitch-insns=1000" } */ + +int +__attribute__((noipa)) +foo(double *a, double *b, double *c, double *d, double *r, int size, int order) +{ + for (int i = 0; i < size; i++) + { + double tmp, tmp2; + + if (order <= 0) + tmp = 123; + + switch(order) + { + case 0: + tmp += -8 * a[i]; + tmp2 = 2 * b[i]; + break; + case 1: + tmp = 3 * a[i] - 2 * b[i]; + tmp2 = 5 * b[i] - 2 * c[i]; + break; + case 2: + tmp = 9 * a[i] + 2 * b[i] + c[i]; + tmp2 = 4 * b[i] + 2 * c[i] + 8 * d[i]; + break; + case 3: + tmp = 3 * a[i] + 2 * b[i] - c[i]; + tmp2 = b[i] - 2 * c[i] + 8 * d[i]; + break; + default: + __builtin_unreachable (); + } + + double x = 3 * tmp + d[i] + tmp; + double y = 3.4f * tmp + d[i] + tmp2; + r[i] = x + y; + } + + return 0; +} + +#define N 16 * 1024 +double aa[N], bb[N], cc[N], dd[N], rr[N]; + +int main() +{ + for (int i = 0; i < 100 * 1000; i++) + foo (aa, bb, cc, dd, rr, N, i % 4); +} + + +/* Test that we actually unswitched something. */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* <= 0" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 0" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 1" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 2" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .switch. with condition: order.* == 3" 1 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-15.c b/gcc/testsuite/gcc.dg/loop-unswitch-15.c new file mode 100644 index 0000000..87139bb --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-15.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +void bar(); +void baz(); +void foo (int a, int b, int n) +{ + for (int i = 0; i < n; ++i) + if (a < b) + bar (); + else + baz (); +} + +/* { dg-final { scan-tree-dump "unswitching loop . on .if. with condition:" "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-16.c b/gcc/testsuite/gcc.dg/loop-unswitch-16.c new file mode 100644 index 0000000..4b0b400 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-16.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized --param max-unswitch-insns=100" } */ + +void bar (int); +void foo (int a, int b, int c, int n) +{ + for (int i = 0; i < n; ++i) + { + if (a > 5) + bar (1); + if (b < 10) + bar (2); + if (c != 5) + bar (3); + } +} + +/* Verify we can unswitch all permutations of the predicates. */ +/* { dg-final { scan-tree-dump-times "unswitching loop . on .if. with condition" 7 "unswitch" } } */ +/* { dg-final { scan-tree-dump "unswitching loop . on .if. with condition: a" "unswitch" } } */ +/* { dg-final { scan-tree-dump "unswitching loop . on .if. with condition: b" "unswitch" } } */ +/* { dg-final { scan-tree-dump "unswitching loop . on .if. with condition: c" "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-17.c b/gcc/testsuite/gcc.dg/loop-unswitch-17.c new file mode 100644 index 0000000..8655e09 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-17.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +int foo (int a) +{ + do + { + if (a == 1) + return 0; + switch (a) + { + case 1: + return 5; + case 2: + return 7; + case 3: + return 11; + default:; + } + } + while (1); +} + +/* { dg-final { scan-tree-dump-times "unswitching loop" 3 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-7.c b/gcc/testsuite/gcc.dg/loop-unswitch-7.c new file mode 100644 index 0000000..db2f930 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-7.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fno-thread-jumps -fdump-tree-unswitch-optimized" } */ + +int +foo(double *a, double *b, double *c, double *d, double *r, int size, float order) +{ + for (int i = 0; i < size; i++) + { + double tmp; + + if (order == 1.f) + tmp = -8 * a[i]; + else + tmp = -4 * b[i]; + + double x = 3 * tmp + d[i] + tmp; + + if (order == 1.f) + x += 2; + + double y = 3.4f * tmp + d[i]; + r[i] = x + y; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "unswitching loop . on .if. with condition: order.* == 1.0e" 1 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-8.c b/gcc/testsuite/gcc.dg/loop-unswitch-8.c new file mode 100644 index 0000000..32796e9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-8.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +int +foo(double *a, double *b, double *c, double *d, double *r, int size, int order) +{ + for (int i = 0; i < size; i++) + { + double tmp; + + if (order < 3) + tmp = -8 * a[i]; + else + tmp = -4 * b[i]; + + double x = 3 * tmp + d[i] + tmp; + + if (5 > order) + x += 2; + + if (order == 12345) + x *= 5; + + double y = 3.4f * tmp + d[i]; + r[i] = x + y; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "unswitching loop . on .if. with condition: order" 3 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/loop-unswitch-9.c b/gcc/testsuite/gcc.dg/loop-unswitch-9.c new file mode 100644 index 0000000..5e50b07 --- /dev/null +++ b/gcc/testsuite/gcc.dg/loop-unswitch-9.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -funswitch-loops -fdump-tree-unswitch-optimized" } */ + +int +foo(double *a, double *b, double *c, double *d, double *r, int size, int order) +{ + for (int i = 0; i < size; i++) + { + double tmp; + + if (order == 1) + tmp = -8 * a[i]; + else + { + if (order == 2) + tmp = -4 * b[i]; + else + tmp = a[i]; + } + + r[i] = 3.4f * tmp + d[i]; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "unswitching loop . on .if. with condition: order" 2 "unswitch" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c index 12d1c8d..b5ae128 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c @@ -47,13 +47,13 @@ class gil_state_machine : public state_machine public: gil_state_machine (logger *logger); - bool inherited_state_p () const FINAL OVERRIDE { return false; } + bool inherited_state_p () const final override { return false; } bool on_stmt (sm_context *sm_ctxt, const supernode *node, - const gimple *stmt) const FINAL OVERRIDE; + const gimple *stmt) const final override; - bool can_purge_p (state_t s) const FINAL OVERRIDE; + bool can_purge_p (state_t s) const final override; void check_for_pyobject_usage_without_gil (sm_context *sm_ctxt, const supernode *node, @@ -82,12 +82,12 @@ class gil_diagnostic : public pending_diagnostic { public: /* There isn't a warning ID for us to use. */ - int get_controlling_option () const FINAL OVERRIDE + int get_controlling_option () const final override { return 0; } - location_t fixup_location (location_t loc) const FINAL OVERRIDE + location_t fixup_location (location_t loc) const final override { /* Ideally we'd check for specific macros here, and only resolve certain macros. */ @@ -98,7 +98,7 @@ public: } label_text describe_state_change (const evdesc::state_change &change) - FINAL OVERRIDE + final override { if (change.is_global_p () && change.m_new_state == m_sm.m_released_gil) @@ -125,25 +125,25 @@ class double_save_thread : public gil_diagnostic : gil_diagnostic (sm), m_call (call) {} - const char *get_kind () const FINAL OVERRIDE + const char *get_kind () const final override { return "double_save_thread"; } - bool subclass_equal_p (const pending_diagnostic &base_other) const OVERRIDE + bool subclass_equal_p (const pending_diagnostic &base_other) const override { const double_save_thread &sub_other = (const double_save_thread &)base_other; return m_call == sub_other.m_call; } - bool emit (rich_location *rich_loc) FINAL OVERRIDE + bool emit (rich_location *rich_loc) final override { return warning_at (rich_loc, get_controlling_option (), "nested usage of %qs", "Py_BEGIN_ALLOW_THREADS"); } - label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE + label_text describe_final_event (const evdesc::final_event &ev) final override { return ev.formatted_print ("nested usage of %qs here", "Py_BEGIN_ALLOW_THREADS"); @@ -162,12 +162,12 @@ class fncall_without_gil : public gil_diagnostic m_arg_idx (arg_idx) {} - const char *get_kind () const FINAL OVERRIDE + const char *get_kind () const final override { return "fncall_without_gil"; } - bool subclass_equal_p (const pending_diagnostic &base_other) const OVERRIDE + bool subclass_equal_p (const pending_diagnostic &base_other) const override { const fncall_without_gil &sub_other = (const fncall_without_gil &)base_other; @@ -176,7 +176,7 @@ class fncall_without_gil : public gil_diagnostic && m_arg_idx == sub_other.m_arg_idx); } - bool emit (rich_location *rich_loc) FINAL OVERRIDE + bool emit (rich_location *rich_loc) final override { auto_diagnostic_group d; if (m_callee_fndecl) @@ -191,7 +191,7 @@ class fncall_without_gil : public gil_diagnostic m_arg_idx + 1, m_callee_fndecl); } - label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE + label_text describe_final_event (const evdesc::final_event &ev) final override { if (m_callee_fndecl) return ev.formatted_print ("use of PyObject as argument %i of %qE here" @@ -216,25 +216,25 @@ class pyobject_usage_without_gil : public gil_diagnostic : gil_diagnostic (sm), m_expr (expr) {} - const char *get_kind () const FINAL OVERRIDE + const char *get_kind () const final override { return "pyobject_usage_without_gil"; } - bool subclass_equal_p (const pending_diagnostic &base_other) const OVERRIDE + bool subclass_equal_p (const pending_diagnostic &base_other) const override { return same_tree_p (m_expr, ((const pyobject_usage_without_gil&)base_other).m_expr); } - bool emit (rich_location *rich_loc) FINAL OVERRIDE + bool emit (rich_location *rich_loc) final override { auto_diagnostic_group d; return warning_at (rich_loc, get_controlling_option (), "use of PyObject %qE without the GIL", m_expr); } - label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE + label_text describe_final_event (const evdesc::final_event &ev) final override { return ev.formatted_print ("PyObject %qE used here without the GIL", m_expr); diff --git a/gcc/testsuite/gcc.dg/pr91134.c b/gcc/testsuite/gcc.dg/pr91134.c new file mode 100644 index 0000000..8844f42 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr91134.c @@ -0,0 +1,32 @@ +/* PR c/91134 */ +/* { dg-options "-fdiagnostics-show-caret" } */ + +struct X { int member; } x; +struct Y { struct X **x; } y; + +int +foo (void) +{ + struct X *pointer = &x; + struct Y *yp = &y; + struct X **pointerpointer = &pointer; + int i = *pointerpointer->member; /* { dg-error "'pointerpointer' is a pointer to pointer; did you mean to dereference it before applying '->' to it\\\?" } */ +/* { dg-begin-multiline-output "" } + int i = *pointerpointer->member; + ^~ + (* ) + { dg-end-multiline-output "" } */ + int j = pointer.member; /* { dg-error "'pointer' is a pointer; did you mean to use '->'\\\?" } */ +/* { dg-begin-multiline-output "" } + int j = pointer.member; + ^ + -> + { dg-end-multiline-output "" } */ + int k = yp->x->member; /* { dg-error "'yp->x' is a pointer to pointer; did you mean to dereference it before applying '->' to it\\\?" } */ +/* { dg-begin-multiline-output "" } + int k = yp->x->member; + ^~ + (* ) + { dg-end-multiline-output "" } */ + return i + j + k; +} diff --git a/gcc/testsuite/gcc.dg/pr98865.c b/gcc/testsuite/gcc.dg/pr98865.c new file mode 100644 index 0000000..95f7270 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr98865.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(int x, int y) +{ + return -(x&1) & y; +} + +int bar(int x, int y) +{ + return (x&1) * y; +} + +/* { dg-final { scan-tree-dump-times " \\* " 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/torture/20220518-1.c b/gcc/testsuite/gcc.dg/torture/20220518-1.c new file mode 100644 index 0000000..1822aee --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20220518-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-funswitch-loops" } */ + +enum { + MOD_WVG_MASK_TEX_USE_INT, + MOD_WVG_MASK_TEX_USE_RED, + MOD_WVG_MASK_TEX_USE_BLUE, + MOD_WVG_MASK_TEX_USE_SAT, + MOD_WVG_MASK_TEX_USE_VAL, + MOD_WVG_MASK_TEX_USE_ALPHA +} foo_num; +float *foo_org_w; +int *foo_new_w; +float foo_fact; +int foo_tex_use_channel, foo_i, foo_texres_0; +void foo() +{ + for (; foo_num;) + switch (foo_tex_use_channel) { + case MOD_WVG_MASK_TEX_USE_INT: + foo_org_w[foo_i] = foo_new_w[foo_i] * foo_texres_0; + break; + case MOD_WVG_MASK_TEX_USE_RED: + foo_org_w[foo_i] = 0; + case MOD_WVG_MASK_TEX_USE_BLUE: + foo_org_w[foo_i] = foo_fact + foo_org_w[foo_i]; + break; + case MOD_WVG_MASK_TEX_USE_SAT: + foo_org_w[foo_i] = foo_fact; + break; + case MOD_WVG_MASK_TEX_USE_VAL: + foo_org_w[foo_i] = 0; + case MOD_WVG_MASK_TEX_USE_ALPHA: + foo_org_w[foo_i] = foo_fact + foo_org_w[foo_i]; + break; + default: + foo_org_w[foo_i] = foo_new_w[foo_i] * foo_texres_0; + } +} diff --git a/gcc/testsuite/gcc.dg/torture/20220518-2.c b/gcc/testsuite/gcc.dg/torture/20220518-2.c new file mode 100644 index 0000000..af70d7f --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20220518-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-funswitch-loops" } */ + +int Get_Spline_Val_sp_0, Get_Spline_Val_k; +double Get_Spline_Val_p, Get_Spline_Val_se_0_0_0; +double *Get_Spline_Val_v; +void Get_Spline_Val() { + int i; + for (;;) + if (i > Get_Spline_Val_sp_0) + Get_Spline_Val_k = Get_Spline_Val_se_0_0_0; + else if (Get_Spline_Val_sp_0 == 1) + Get_Spline_Val_v[Get_Spline_Val_k] = Get_Spline_Val_p; +} diff --git a/gcc/testsuite/gcc.dg/torture/20220525-1.c b/gcc/testsuite/gcc.dg/torture/20220525-1.c new file mode 100644 index 0000000..55dad31 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20220525-1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-funswitch-loops" } */ + +int LIST_1, mb_pred_b_d4x4spatial_dec_picture_l0_rFrame, + mb_pred_b_d4x4spatial_dec_picture_l1_rFrame; +typedef struct { + char ref_idx[2]; +} PicMotionParams; +PicMotionParams mb_pred_b_d4x4spatial_dec_picture_mv_info; +int get_colocated_info_4x4___trans_tmp_1, get_colocated_info_4x4_list1_0; +int get_colocated_info_4x4() +{ + int moving = + get_colocated_info_4x4_list1_0 && get_colocated_info_4x4___trans_tmp_1; + return moving; +} +void mb_pred_b_d4x4spatial_dec_picture() +{ + char k; + for (;;) + { + k = 0; + for (; k < 4; k++) + if (mb_pred_b_d4x4spatial_dec_picture_l0_rFrame + || mb_pred_b_d4x4spatial_dec_picture_l1_rFrame == 0) + { + int is_not_moving = get_colocated_info_4x4(); + if (mb_pred_b_d4x4spatial_dec_picture_l1_rFrame) + if (is_not_moving) + mb_pred_b_d4x4spatial_dec_picture_mv_info.ref_idx[LIST_1] = 1; + } + } +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-6.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-6.c index 6044760..f9eb5c6 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loop-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-6.c @@ -19,7 +19,7 @@ void xxx(void) /* Loop should be unswitched. */ -/* { dg-final { scan-tree-dump-times "Unswitching loop" 1 "unswitch" } } */ +/* { dg-final { scan-tree-dump-times "unswitching loop" 1 "unswitch" } } */ /* In effect there should be exactly three conditional jumps in the final program. */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-44.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-44.c new file mode 100644 index 0000000..aaec41d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-44.c @@ -0,0 +1,19 @@ +/* { dg-do link } */ +/* { dg-options "-O -fdump-tree-dse1-details" } */ + +extern void foo(void); +int a, b; +static int c; +int main() +{ + if (c) + foo (); + int *g = &c; + int **h = &g; + int ***h1 = &h; + if (a) + while (b) + b = 0; +} + +/* { dg-final { scan-tree-dump "Deleted dead store: g = &c;" "dse1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-45.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-45.c new file mode 100644 index 0000000..fd92d7b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-45.c @@ -0,0 +1,24 @@ +/* { dg-do link } */ +/* { dg-options "-O" } */ + +extern void foo(void); +int a, b; +static int c; +static void f() { + while (a) + for (; b; b--) + ; +} +void i() { + if (c) + foo(); + int *g = &c; + { + int **h[1] = {&g}; + f(); + } +} +int main() { + i(); + return 0; +} diff --git a/gcc/testsuite/gcc.misc-tests/outputs.exp b/gcc/testsuite/gcc.misc-tests/outputs.exp index bc1fbe4..afae735 100644 --- a/gcc/testsuite/gcc.misc-tests/outputs.exp +++ b/gcc/testsuite/gcc.misc-tests/outputs.exp @@ -36,8 +36,8 @@ gcc_parallel_test_enable 0 # having to deal with .dSYM directories, as long as -gsplit-dwarf is # not supported on platforms that use .dSYM directories. set gsplit_dwarf "-g -gsplit-dwarf" -if ![check_no_compiler_messages gsplitdwarf object { - void foo (void) { } +if ![check_no_compiler_messages gsplitdwarf executable { + int main (void) { return 0; } } "$gsplit_dwarf"] { set gsplit_dwarf "" } diff --git a/gcc/testsuite/gcc.target/aarch64/pr104689.c b/gcc/testsuite/gcc.target/aarch64/pr104689.c new file mode 100644 index 0000000..3b7adbd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr104689.c @@ -0,0 +1,149 @@ +/* PR target/104689. Unwind across pac-ret frames with unusual dwarf. */ +/* { dg-do run } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-fexceptions -O2" } */ + +#include <unwind.h> +#include <stdlib.h> +#include <stdio.h> + +#define die() \ + do { \ + printf ("%s:%d: reached unexpectedly.\n", __FILE__, __LINE__); \ + fflush (stdout); \ + abort (); \ + } while (0) + + +/* Code to invoke unwinding with a logging callback. */ + +static struct _Unwind_Exception exc; + +static _Unwind_Reason_Code +force_unwind_stop (int version, _Unwind_Action actions, + _Unwind_Exception_Class exc_class, + struct _Unwind_Exception *exc_obj, + struct _Unwind_Context *context, + void *stop_parameter) +{ + printf ("%s: CFA: %p PC: %p actions: %d\n", + __func__, + (void *)_Unwind_GetCFA (context), + (void *)_Unwind_GetIP (context), + (int)actions); + if (actions & _UA_END_OF_STACK) + die (); + return _URC_NO_REASON; +} + +static void force_unwind (void) +{ +#ifndef __USING_SJLJ_EXCEPTIONS__ + _Unwind_ForcedUnwind (&exc, force_unwind_stop, 0); +#else + _Unwind_SjLj_ForcedUnwind (&exc, force_unwind_stop, 0); +#endif +} + + +/* Define functions with unusual pac-ret dwarf via top level asm. */ + +#define STR(x) #x +#define DW_CFA_val_expression 0x16 +#define RA_SIGN_STATE 34 +#define DW_OP_lit0 0x30 +#define DW_OP_lit1 0x31 + +#define cfi_escape(a1, a2, a3, a4) \ + ".cfi_escape " STR(a1) ", " STR(a2) ", " STR(a3) ", " STR(a4) + +/* Bytes: 0x16 0x22 0x01 0x30 */ +#define SET_RA_STATE_0 \ + cfi_escape (DW_CFA_val_expression, RA_SIGN_STATE, 1, DW_OP_lit0) + +/* Bytes: 0x16 0x22 0x01 0x31 */ +#define SET_RA_STATE_1 \ + cfi_escape (DW_CFA_val_expression, RA_SIGN_STATE, 1, DW_OP_lit1) + +/* These function call their argument. */ +void unusual_pac_ret (void *); +void unusual_no_pac_ret (void *); + +asm("" +".global unusual_pac_ret\n" +".type unusual_pac_ret, %function\n" +"unusual_pac_ret:\n" +" .cfi_startproc\n" +" " SET_RA_STATE_0 "\n" +" hint 25 // paciasp\n" +" " SET_RA_STATE_1 "\n" +" stp x29, x30, [sp, -16]!\n" +" .cfi_def_cfa_offset 16\n" +" .cfi_offset 29, -16\n" +" .cfi_offset 30, -8\n" +" mov x29, sp\n" +" blr x0\n" +" ldp x29, x30, [sp], 16\n" +" .cfi_restore 30\n" +" .cfi_restore 29\n" +" .cfi_def_cfa_offset 0\n" +" hint 29 // autiasp\n" +" " SET_RA_STATE_0 "\n" +" ret\n" +" .cfi_endproc\n"); + +asm("" +".global unusual_no_pac_ret\n" +".type unusual_no_pac_ret, %function\n" +"unusual_no_pac_ret:\n" +" .cfi_startproc\n" +" " SET_RA_STATE_0 "\n" +" stp x29, x30, [sp, -16]!\n" +" .cfi_def_cfa_offset 16\n" +" .cfi_offset 29, -16\n" +" .cfi_offset 30, -8\n" +" mov x29, sp\n" +" blr x0\n" +" ldp x29, x30, [sp], 16\n" +" .cfi_restore 30\n" +" .cfi_restore 29\n" +" .cfi_def_cfa_offset 0\n" +" ret\n" +" .cfi_endproc\n"); + + +/* Functions to create a call chain with mixed pac-ret dwarf. */ + +__attribute__((target("branch-protection=pac-ret"))) +static void f2_pac_ret (void) +{ + force_unwind (); + die (); +} + +__attribute__((target("branch-protection=none"))) +static void f1_no_pac_ret (void) +{ + unusual_pac_ret (f2_pac_ret); + die (); +} + +__attribute__((noinline, target("branch-protection=pac-ret"))) +static void f0_pac_ret (void) +{ + unusual_no_pac_ret (f1_no_pac_ret); + die (); +} + +static void cleanup_handler (void *p) +{ + printf ("%s: Success.\n", __func__); + exit (0); +} + +int main () +{ + char dummy __attribute__((cleanup (cleanup_handler))); + f0_pac_ret (); + die (); +} diff --git a/gcc/testsuite/gcc.target/i386/neg-zext-1.c b/gcc/testsuite/gcc.target/i386/neg-zext-1.c new file mode 100644 index 0000000..ec91fb1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/neg-zext-1.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2" } */ + +long long foo(unsigned int x) { return -(long long)x; } + +/* { dg-final { scan-assembler "sbb" } } */ +/* { dg-final { scan-assembler-not "adc" } } */ diff --git a/gcc/testsuite/gcc.target/i386/neg-zext-2.c b/gcc/testsuite/gcc.target/i386/neg-zext-2.c new file mode 100644 index 0000000..a6ed077 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/neg-zext-2.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +__int128 fool(unsigned long x) { return -(__int128)x; } + +/* { dg-final { scan-assembler "sbb" } } */ +/* { dg-final { scan-assembler-not "adc" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr104441-1a.c b/gcc/testsuite/gcc.target/i386/pr104441-1a.c index 83734f7..0931029 100644 --- a/gcc/testsuite/gcc.target/i386/pr104441-1a.c +++ b/gcc/testsuite/gcc.target/i386/pr104441-1a.c @@ -8,7 +8,7 @@ __attribute__((always_inline, target("avx2"))) static __m256i load8bit_4x4_avx2(const uint8_t *const src, const uint32_t stride) { - __m128i src01, src23; + __m128i src01, src23 = _mm_setzero_si128(); src01 = _mm_cvtsi32_si128(*(int32_t*)(src + 0 * stride)); src23 = _mm_insert_epi32(src23, *(int32_t *)(src + 3 * stride), 1); return _mm256_setr_m128i(src01, src23); diff --git a/gcc/testsuite/gcc.target/i386/pr105668.c b/gcc/testsuite/gcc.target/i386/pr105668.c new file mode 100644 index 0000000..359c2b6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr105668.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O -ftracer -fno-tree-fre" } */ + +typedef __int128 __attribute__((__vector_size__ (16))) V; + +int i; + +V +foo (_Complex float f) +{ + (void) __builtin_atanhf (i); + V v = i != (V) { }; + i ^= f && 8; + v %= 5; + return v; +} diff --git a/gcc/testsuite/gcc.target/i386/pr105711.c b/gcc/testsuite/gcc.target/i386/pr105711.c new file mode 100644 index 0000000..6d07e08 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr105711.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 --param=sccvn-max-alias-queries-per-access=0" } */ + +int *p, a, b; + +void +foo (_Complex char c) +{ + c /= 3040; + a %= __builtin_memcmp (1 + &c, p, 1); + b = c + __imag__ c; +} diff --git a/gcc/testsuite/gcc.target/i386/pr91400-1.c b/gcc/testsuite/gcc.target/i386/pr91400-1.c index 6124058..751dc6c 100644 --- a/gcc/testsuite/gcc.target/i386/pr91400-1.c +++ b/gcc/testsuite/gcc.target/i386/pr91400-1.c @@ -1,8 +1,8 @@ /* PR target/91400 */ /* { dg-do compile } */ /* { dg-options "-O2" } */ -/* { dg-final { scan-assembler-times "andl" 1 } } */ -/* { dg-final { scan-assembler-times "cmpl" 1 } } */ +/* { dg-final { scan-assembler-times "notl" 1 } } */ +/* { dg-final { scan-assembler-times "testb" 1 } } */ /* { dg-final { scan-assembler-times "sete" 1 } } */ /* { dg-final { scan-assembler-not "cmove" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr91400-2.c b/gcc/testsuite/gcc.target/i386/pr91400-2.c index 1af5a2f..914acd7 100644 --- a/gcc/testsuite/gcc.target/i386/pr91400-2.c +++ b/gcc/testsuite/gcc.target/i386/pr91400-2.c @@ -1,8 +1,8 @@ /* PR target/91400 */ /* { dg-do compile } */ /* { dg-options "-O2" } */ -/* { dg-final { scan-assembler-times "andl" 1 } } */ -/* { dg-final { scan-assembler-times "cmpl" 1 } } */ +/* { dg-final { scan-assembler-times "notl" 1 } } */ +/* { dg-final { scan-assembler-times "testb" 1 } } */ /* { dg-final { scan-assembler-times "sete" 1 } } */ /* { dg-final { scan-assembler-not "cmove" } } */ diff --git a/gcc/testsuite/gcc.target/i386/testnot-1.c b/gcc/testsuite/gcc.target/i386/testnot-1.c new file mode 100644 index 0000000..9ebcb5c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/testnot-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int foo(int x) +{ + return (x & 1234) == 1234; +} + +int foos(short x) +{ + return (x & 1234) == 1234; +} + +int fooc(char x) +{ + return (x & 123) == 123; +} + +int fool(long long x) +{ + return (x & 1234) == 1234; +} + +/* { dg-final { scan-assembler-not "cmp" } } */ diff --git a/gcc/testsuite/gcc.target/i386/testnot-2.c b/gcc/testsuite/gcc.target/i386/testnot-2.c new file mode 100644 index 0000000..52fdaf3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/testnot-2.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +int foo(int x, int y) +{ + return (x & y) == y; +} + +int foos(short x, short y) +{ + return (x & y) == y; +} + +int fooc(char x, char y) +{ + return (x & y) == y; +} + +int fool(long long x, long long y) +{ + return (x & y) == y; +} + +/* { dg-final { scan-assembler-not "cmp" } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr105627.c b/gcc/testsuite/gcc.target/powerpc/pr105627.c new file mode 100644 index 0000000..bafb31f --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr105627.c @@ -0,0 +1,26 @@ +/* Specify -w to disable some warnings, such as: -Wpsabi. */ +/* { dg-options "-Og -fcompare-debug -mdejagnu-cpu=power8 -w" } */ + +typedef unsigned char __attribute__ ((__vector_size__ (8))) U; +typedef unsigned char __attribute__ ((__vector_size__ (64))) V; + +U u; +char c; +V v; + +V +foo (void) +{ + V w = c + & __builtin_shufflevector (u, (V){0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 5}, + 24, 24, 41, 45, 53, 60, 22, 35, 45, 12, 61, + 9, 52, 15, 44, 46, 5, 5, 1, 0, 4, 9, 0, 8, 5, + 7, 2, 5, 9, 2, 7, 7, 5, 6, 0, 2, 6, 1, 7, 7, + 0, 4, 0, 1, 7, 2, 5, 3, 2, 3, 5, 6, 6, 6, 0, + 6, 1, 9, 0, 5, 4, 3, 5, 4); + w = w + v; + return w; +} + diff --git a/gcc/testsuite/gcc.target/powerpc/pr78604.c b/gcc/testsuite/gcc.target/powerpc/pr78604.c index 35bfdb3..7a371af 100644 --- a/gcc/testsuite/gcc.target/powerpc/pr78604.c +++ b/gcc/testsuite/gcc.target/powerpc/pr78604.c @@ -109,4 +109,6 @@ uns_gte (UNS_TYPE val1, UNS_TYPE val2) /* { dg-final { scan-assembler-times {\mvcmpgtsd\M} 4 } } */ /* { dg-final { scan-assembler-times {\mvcmpgtud\M} 4 } } */ /* { dg-final { scan-assembler-not {\mvcmpequd\M} } } */ -/* { dg-final { scan-tree-dump-times "vect_model_simple_cost" 8 "vect" } } */ +/* For each function, one is for the comparison statement and the other + is for the condition statement which consumes the compared result. */ +/* { dg-final { scan-tree-dump-times "vect_model_simple_cost" 16 "vect" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/cmo-zicbom-1.c b/gcc/testsuite/gcc.target/riscv/cmo-zicbom-1.c new file mode 100644 index 0000000..e2ba218 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cmo-zicbom-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicbom -mabi=lp64" } */ + +int foo1() +{ + return __builtin_riscv_zicbom_cbo_clean(); +} + +int foo2() +{ + return __builtin_riscv_zicbom_cbo_flush(); +} + +int foo3() +{ + return __builtin_riscv_zicbom_cbo_inval(); +} + +/* { dg-final { scan-assembler-times "cbo.clean" 1 } } */ +/* { dg-final { scan-assembler-times "cbo.flush" 1 } } */ +/* { dg-final { scan-assembler-times "cbo.inval" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/cmo-zicbom-2.c b/gcc/testsuite/gcc.target/riscv/cmo-zicbom-2.c new file mode 100644 index 0000000..a605e8b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cmo-zicbom-2.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zicbom -mabi=ilp32" } */ + +int foo1() +{ + return __builtin_riscv_zicbom_cbo_clean(); +} + +int foo2() +{ + return __builtin_riscv_zicbom_cbo_flush(); +} + +int foo3() +{ + return __builtin_riscv_zicbom_cbo_inval(); +} + +/* { dg-final { scan-assembler-times "cbo.clean" 1 } } */ +/* { dg-final { scan-assembler-times "cbo.flush" 1 } } */ +/* { dg-final { scan-assembler-times "cbo.inval" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/cmo-zicbop-1.c b/gcc/testsuite/gcc.target/riscv/cmo-zicbop-1.c new file mode 100644 index 0000000..c5d78c1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cmo-zicbop-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile target { { rv64-*-*}}} */ +/* { dg-options "-march=rv64gc_zicbop -mabi=lp64" } */ + +void foo (char *p) +{ + __builtin_prefetch (p, 0, 0); + __builtin_prefetch (p, 0, 1); + __builtin_prefetch (p, 0, 2); + __builtin_prefetch (p, 0, 3); + __builtin_prefetch (p, 1, 0); + __builtin_prefetch (p, 1, 1); + __builtin_prefetch (p, 1, 2); + __builtin_prefetch (p, 1, 3); +} + +int foo1() +{ + return __builtin_riscv_zicbop_cbo_prefetchi(1); +} + +/* { dg-final { scan-assembler-times "prefetch.i" 1 } } */ +/* { dg-final { scan-assembler-times "prefetch.r" 4 } } */ +/* { dg-final { scan-assembler-times "prefetch.w" 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/cmo-zicbop-2.c b/gcc/testsuite/gcc.target/riscv/cmo-zicbop-2.c new file mode 100644 index 0000000..6576365 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cmo-zicbop-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile target { { rv32-*-*}}} */ +/* { dg-options "-march=rv32gc_zicbop -mabi=ilp32" } */ + +void foo (char *p) +{ + __builtin_prefetch (p, 0, 0); + __builtin_prefetch (p, 0, 1); + __builtin_prefetch (p, 0, 2); + __builtin_prefetch (p, 0, 3); + __builtin_prefetch (p, 1, 0); + __builtin_prefetch (p, 1, 1); + __builtin_prefetch (p, 1, 2); + __builtin_prefetch (p, 1, 3); +} + +int foo1() +{ + return __builtin_riscv_zicbop_cbo_prefetchi(1); +} + +/* { dg-final { scan-assembler-times "prefetch.i" 1 } } */ +/* { dg-final { scan-assembler-times "prefetch.r" 4 } } */ +/* { dg-final { scan-assembler-times "prefetch.w" 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/cmo-zicboz-1.c b/gcc/testsuite/gcc.target/riscv/cmo-zicboz-1.c new file mode 100644 index 0000000..96c1674 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cmo-zicboz-1.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicboz -mabi=lp64" } */ + +int foo1() +{ + return __builtin_riscv_zicboz_cbo_zero(); +} + +/* { dg-final { scan-assembler-times "cbo.zero" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/cmo-zicboz-2.c b/gcc/testsuite/gcc.target/riscv/cmo-zicboz-2.c new file mode 100644 index 0000000..9d99839 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/cmo-zicboz-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zicboz -mabi=ilp32" } */ + +int foo1() +{ + return __builtin_riscv_zicboz_cbo_zero(); +} + +/* { dg-final { scan-assembler-times "cbo.zero" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fmax.c b/gcc/testsuite/gcc.target/riscv/fmax.c index c71d35c..e1b7fa8 100644 --- a/gcc/testsuite/gcc.target/riscv/fmax.c +++ b/gcc/testsuite/gcc.target/riscv/fmax.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */ double diff --git a/gcc/testsuite/gcc.target/riscv/fmaxf.c b/gcc/testsuite/gcc.target/riscv/fmaxf.c index f998016..8da0513 100644 --- a/gcc/testsuite/gcc.target/riscv/fmaxf.c +++ b/gcc/testsuite/gcc.target/riscv/fmaxf.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */ float diff --git a/gcc/testsuite/gcc.target/riscv/fmin.c b/gcc/testsuite/gcc.target/riscv/fmin.c index 9634abd..01993d4 100644 --- a/gcc/testsuite/gcc.target/riscv/fmin.c +++ b/gcc/testsuite/gcc.target/riscv/fmin.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */ double diff --git a/gcc/testsuite/gcc.target/riscv/fminf.c b/gcc/testsuite/gcc.target/riscv/fminf.c index 9a3687b..32ce363 100644 --- a/gcc/testsuite/gcc.target/riscv/fminf.c +++ b/gcc/testsuite/gcc.target/riscv/fminf.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-fno-finite-math-only -fsigned-zeros -fno-signaling-nans -dp" } */ float diff --git a/gcc/testsuite/gcc.target/riscv/pr105666.c b/gcc/testsuite/gcc.target/riscv/pr105666.c new file mode 100644 index 0000000..dd996ee --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr105666.c @@ -0,0 +1,56 @@ +/* Shamelessly plugged off gcc/testsuite/gcc.c-torture/execute/pr28982a.c. + + The idea is to induce high register pressure for both int/fp registers + so that they spill. By default FMV instructions would be used to stash + int reg to a fp reg (and vice-versa) but that could be costlier than + spilling to stack. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ +/* { dg-options "-march=rv64g -ffast-math" } */ + +#define NITER 4 +#define NVARS 20 +#define MULTI(X) \ + X( 0), X( 1), X( 2), X( 3), X( 4), X( 5), X( 6), X( 7), X( 8), X( 9), \ + X(10), X(11), X(12), X(13), X(14), X(15), X(16), X(17), X(18), X(19) + +#define DECLAREI(INDEX) inc##INDEX = incs[INDEX] +#define DECLAREF(INDEX) *ptr##INDEX = ptrs[INDEX], result##INDEX = 5 +#define LOOP(INDEX) result##INDEX += result##INDEX * (*ptr##INDEX), ptr##INDEX += inc##INDEX +#define COPYOUT(INDEX) results[INDEX] = result##INDEX + +double *ptrs[NVARS]; +double results[NVARS]; +int incs[NVARS]; + +void __attribute__((noinline)) +foo (int n) +{ + int MULTI (DECLAREI); + double MULTI (DECLAREF); + while (n--) + MULTI (LOOP); + MULTI (COPYOUT); +} + +double input[NITER * NVARS]; + +int +main (void) +{ + int i; + + for (i = 0; i < NVARS; i++) + ptrs[i] = input + i, incs[i] = i; + for (i = 0; i < NITER * NVARS; i++) + input[i] = i; + foo (NITER); + for (i = 0; i < NVARS; i++) + if (results[i] != i * NITER * (NITER + 1) / 2) + return 1; + return 0; +} + +/* { dg-final { scan-assembler-not "\tfmv\\.d\\.x\t" } } */ +/* { dg-final { scan-assembler-not "\tfmv\\.x\\.d\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/smax-ieee.c b/gcc/testsuite/gcc.target/riscv/smax-ieee.c index 3a98aeb..2dbccef 100644 --- a/gcc/testsuite/gcc.target/riscv/smax-ieee.c +++ b/gcc/testsuite/gcc.target/riscv/smax-ieee.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */ double diff --git a/gcc/testsuite/gcc.target/riscv/smax.c b/gcc/testsuite/gcc.target/riscv/smax.c index d806c63..1092cc4 100644 --- a/gcc/testsuite/gcc.target/riscv/smax.c +++ b/gcc/testsuite/gcc.target/riscv/smax.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */ double diff --git a/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c b/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c index 6cf23d7..31b9bfa 100644 --- a/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c +++ b/gcc/testsuite/gcc.target/riscv/smaxf-ieee.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */ float diff --git a/gcc/testsuite/gcc.target/riscv/smaxf.c b/gcc/testsuite/gcc.target/riscv/smaxf.c index d6a7a7f..aa1f22b 100644 --- a/gcc/testsuite/gcc.target/riscv/smaxf.c +++ b/gcc/testsuite/gcc.target/riscv/smaxf.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */ float diff --git a/gcc/testsuite/gcc.target/riscv/smin-ieee.c b/gcc/testsuite/gcc.target/riscv/smin-ieee.c index c0a148c..ea36c2d 100644 --- a/gcc/testsuite/gcc.target/riscv/smin-ieee.c +++ b/gcc/testsuite/gcc.target/riscv/smin-ieee.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */ double diff --git a/gcc/testsuite/gcc.target/riscv/smin.c b/gcc/testsuite/gcc.target/riscv/smin.c index e325e9a..d07a0fd 100644 --- a/gcc/testsuite/gcc.target/riscv/smin.c +++ b/gcc/testsuite/gcc.target/riscv/smin.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */ double diff --git a/gcc/testsuite/gcc.target/riscv/sminf-ieee.c b/gcc/testsuite/gcc.target/riscv/sminf-ieee.c index 353e7a1..427617a 100644 --- a/gcc/testsuite/gcc.target/riscv/sminf-ieee.c +++ b/gcc/testsuite/gcc.target/riscv/sminf-ieee.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fsigned-zeros -dp" } */ float diff --git a/gcc/testsuite/gcc.target/riscv/sminf.c b/gcc/testsuite/gcc.target/riscv/sminf.c index f0ba7b4..7df223e 100644 --- a/gcc/testsuite/gcc.target/riscv/sminf.c +++ b/gcc/testsuite/gcc.target/riscv/sminf.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target hard_float } */ /* { dg-options "-ffinite-math-only -fno-signed-zeros -dp" } */ float diff --git a/gcc/testsuite/gcc.target/xtensa/bswap-O1.c b/gcc/testsuite/gcc.target/xtensa/bswap-O1.c new file mode 100644 index 0000000..a0c885b --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/bswap-O1.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +unsigned int test_0(unsigned int a) +{ + return (a & 0x000000FF) << 24 | + (a & 0x0000FF00) << 8 | + (a & 0x00FF0000) >> 8 | + (a & 0xFF000000) >> 24; +} + +unsigned int test_1(unsigned int a) +{ + union + { + unsigned int i; + unsigned char a[4]; + } u, v; + u.i = a; + v.a[0] = u.a[3]; + v.a[1] = u.a[2]; + v.a[2] = u.a[1]; + v.a[3] = u.a[0]; + return v.i; +} + +unsigned int test_2(unsigned int a) +{ + return __builtin_bswap32(a); +} + +unsigned long long test_3(unsigned long long a) +{ + return __builtin_bswap64(a); +} + +/* { dg-final { scan-assembler-times "call" 2 } } */ diff --git a/gcc/testsuite/gcc.target/xtensa/bswap-O2.c b/gcc/testsuite/gcc.target/xtensa/bswap-O2.c new file mode 100644 index 0000000..4cf95b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/bswap-O2.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +unsigned int test_0(unsigned int a) +{ + return (a & 0x000000FF) << 24 | + (a & 0x0000FF00) << 8 | + (a & 0x00FF0000) >> 8 | + (a & 0xFF000000) >> 24; +} + +unsigned int test_1(unsigned int a) +{ + union + { + unsigned int i; + unsigned char a[4]; + } u, v; + u.i = a; + v.a[0] = u.a[3]; + v.a[1] = u.a[2]; + v.a[2] = u.a[1]; + v.a[3] = u.a[0]; + return v.i; +} + +unsigned int test_2(unsigned int a) +{ + return __builtin_bswap32(a); +} + +unsigned long long test_3(unsigned long long a) +{ + return __builtin_bswap64(a); +} + +/* { dg-final { scan-assembler-times "ssai" 4 } } */ diff --git a/gcc/testsuite/gcc.target/xtensa/bswap-Os.c b/gcc/testsuite/gcc.target/xtensa/bswap-Os.c new file mode 100644 index 0000000..1e010fd --- /dev/null +++ b/gcc/testsuite/gcc.target/xtensa/bswap-Os.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-Os" } */ + +unsigned int test_0(unsigned int a) +{ + return (a & 0x000000FF) << 24 | + (a & 0x0000FF00) << 8 | + (a & 0x00FF0000) >> 8 | + (a & 0xFF000000) >> 24; +} + +unsigned int test_1(unsigned int a) +{ + union + { + unsigned int i; + unsigned char a[4]; + } u, v; + u.i = a; + v.a[0] = u.a[3]; + v.a[1] = u.a[2]; + v.a[2] = u.a[1]; + v.a[3] = u.a[0]; + return v.i; +} + +unsigned int test_2(unsigned int a) +{ + return __builtin_bswap32(a); +} + +unsigned long long test_3(unsigned long long a) +{ + return __builtin_bswap64(a); +} + +/* { dg-final { scan-assembler-times "call" 4 } } */ diff --git a/gcc/testsuite/gcc.target/xtensa/bswap.c b/gcc/testsuite/gcc.target/xtensa/bswap.c deleted file mode 100644 index 057a356..0000000 --- a/gcc/testsuite/gcc.target/xtensa/bswap.c +++ /dev/null @@ -1,14 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-O1" } */ - -unsigned long f32(unsigned long v) -{ - return __builtin_bswap32(v); -} - -unsigned long long f64(unsigned long long v) -{ - return __builtin_bswap64(v); -} - -/* { dg-final { scan-assembler-times "ssai" 2 } } */ diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d index de4c7ba..169b7b1 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d @@ -142,8 +142,8 @@ class B : public A, public I1, public I2 { public: using A::bar; - void foo(); - void bar(); + void foo() final override; + void bar() override; }; class Parent @@ -157,7 +157,7 @@ public: class Child final : public Parent { public: - void foo() /* const */; + void foo() override; }; class VisitorBase @@ -289,7 +289,7 @@ interface I2 : I1 class B : A, I1, I2 { alias bar = A.bar; - override void foo() {} + override final void foo() {} override void bar() {} } @@ -303,7 +303,7 @@ class Parent final class Child : Parent { extern(D) override void over() {} - override void foo() const {} + override void foo() {} } class VisitorBase diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d index 35c4ed7..1e2be90 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d @@ -160,7 +160,7 @@ class Child final : public Parent<T > { public: T childMember; - void parentVirtual(); + void parentVirtual() override; T childFinal(); }; diff --git a/gcc/testsuite/gdc.test/compilable/test22865.d b/gcc/testsuite/gdc.test/compilable/test22865.d new file mode 100644 index 0000000..0f40262 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22865.d @@ -0,0 +1,35 @@ +// https://issues.dlang.org/show_bug.cgi?id=22865 + +// Test that safety errors inside speculative scopes don't affect attribute inference + +void main() @safe +{ + foo(); +} + +__gshared int g; + +auto foo() +{ + alias x0 = typeof(g++); + alias x1 = typeof(cast(int*) 0); + + auto x2 = __traits(compiles, g++); + enum x3 = __traits(compiles, (cast(int*) 0)); + + debug + { + g++; + const x4 = cast(int*) 0; + asm { } + } +} + +// Test that safety violations still occur if the function is inside the __traits(compiles) + +static assert(!__traits(compiles, { + void f() @safe + { + g++; + } +})); diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d new file mode 100644 index 0000000..bf51363 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d @@ -0,0 +1,59 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/dip1000_deprecation.d(20): Deprecation: `@safe` function `main` calling `inferred` +fail_compilation/dip1000_deprecation.d(28): which would be `@system` because of: +fail_compilation/dip1000_deprecation.d(28): scope variable `x0` may not be returned +fail_compilation/dip1000_deprecation.d(22): Deprecation: `@safe` function `main` calling `inferredC` +fail_compilation/dip1000_deprecation.d(39): which calls `dip1000_deprecation.inferred` +fail_compilation/dip1000_deprecation.d(28): which would be `@system` because of: +fail_compilation/dip1000_deprecation.d(28): scope variable `x0` may not be returned +fail_compilation/dip1000_deprecation.d(54): Deprecation: escaping reference to stack allocated value returned by `S(null)` +fail_compilation/dip1000_deprecation.d(55): Deprecation: escaping reference to stack allocated value returned by `createS()` +fail_compilation/dip1000_deprecation.d(58): Deprecation: returning `s.incorrectReturnRef()` escapes a reference to local variable `s` +--- +*/ + +void main() @safe +{ + inferred(); + inferredB(); // no deprecation, trusted + inferredC(); // nested deprecation +} + +auto inferred() +{ + scope int* x0; + return x0; +} + +auto inferredB() @trusted +{ + scope int* x1; + return x1; +} + +auto inferredC() +{ + return inferred(); // no deprecation, inferredC is not explicit `@safe` +} + +@safe: + +struct S +{ + int* ptr; + int* incorrectReturnRef() scope return @trusted {return ptr;} +} + +S createS() { return S.init; } + +int* escape() +{ + return S().incorrectReturnRef(); + return createS().incorrectReturnRef(); + + S s; + return s.incorrectReturnRef(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip25.d b/gcc/testsuite/gdc.test/fail_compilation/dip25.d index 41bfe49..02f3140 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dip25.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dip25.d @@ -19,7 +19,7 @@ struct Data } ref int identity(return ref int x) @safe { return x; } -ref int fun(return int x) { return identity(x); } +ref int fun(return int x) @safe { return identity(x); } ref int fun2(ref int x) @safe { return identity(x); } void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d index dd28163..5c852a1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail12390.d(14): Error: `fun().i == 4` has no effect +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 --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22351.d b/gcc/testsuite/gdc.test/fail_compilation/fail22351.d new file mode 100644 index 0000000..405ab55 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22351.d @@ -0,0 +1,20 @@ +/* https://issues.dlang.org/show_bug.cgi?id=22351 +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/fail22351.d(18): Deprecation: overriding `extern(C++)` function `fail22351.C22351.func(int*)` with `const` qualified function `fail22351.Fail22351.func(const(int*))` is deprecated +fail_compilation/fail22351.d(18): Either remove `override`, or adjust the `const` qualifiers of the overriding function parameters +fail_compilation/fail22351.d(19): Error: function `extern (C++) void fail22351.Fail22351.func(const(int*)**)` does not override any function, did you mean to override `extern (C++) void fail22351.C22351.func(int*)`? +--- +*/ +extern(C++) class C22351 +{ + void func(int*) { } + void func(int***) { } +} + +extern(C++) final class Fail22351 : C22351 +{ + override void func(const int*) { } + override void func(const(int*)**) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23135.d b/gcc/testsuite/gdc.test/fail_compilation/fail23135.d new file mode 100644 index 0000000..d32c6ae --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23135.d @@ -0,0 +1,17 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23135 +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/fail23135.d(16): Deprecation: overriding `extern(C++)` function `fail23135.C23135.func()` with `const` qualified function `fail23135.Fail23135.func() const` is deprecated +fail_compilation/fail23135.d(16): Either remove `override`, or adjust the `const` qualifiers of the overriding function type +--- +*/ +extern(C++) class C23135 +{ + void func() { } +} + +extern(C++) final class Fail23135 : C23135 +{ + override void func() const { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d index 153e90b..3e7637f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d @@ -13,7 +13,7 @@ fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a referen fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a` fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a` fail_compilation/fail_scope.d(108): Deprecation: escaping reference to outer local variable `x` -fail_compilation/fail_scope.d(127): Error: returning `s.bar()` escapes a reference to local variable `s` +fail_compilation/fail_scope.d(127): Deprecation: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i` --- //fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix22108.d b/gcc/testsuite/gdc.test/fail_compilation/fix22108.d new file mode 100644 index 0000000..149beba --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fix22108.d @@ -0,0 +1,13 @@ +/* REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/fix22108.d(12): Error: scope variable `p` may not be returned +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=22108 + +@safe ref int test(ref scope return int* p) +{ + return *p; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix23138.d b/gcc/testsuite/gdc.test/fail_compilation/fix23138.d new file mode 100644 index 0000000..58766c8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fix23138.d @@ -0,0 +1,16 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fix23138.d(14): Error: function `fix23138.C2.foo` cannot override `@safe` method `fix23138.C1.foo` with a `@system` attribute +--- + */ + +class C1 { + void foo() @safe + {} +} + +class C2 : C1 +{ + override void foo() @system + {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15660.d b/gcc/testsuite/gdc.test/fail_compilation/test15660.d index be244d7..ae573b2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15660.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15660.d @@ -1,4 +1,4 @@ -/* REQUIRED_ARGS: -preview=dip1000 +/* REQUIRED_ARGS: -preview=fixImmutableConv TEST_OUTPUT: --- fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18484.d b/gcc/testsuite/gdc.test/fail_compilation/test18484.d index d604f38..e51647b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test18484.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test18484.d @@ -19,7 +19,7 @@ int* test1() @safe auto x = S(); return x.bar(); // error } -int* test2() +int* test2() @safe { return S().bar(); // error } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20881.d b/gcc/testsuite/gdc.test/fail_compilation/test20881.d index 7282635..d4c5f07 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20881.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test20881.d @@ -2,6 +2,7 @@ REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- +fail_compilation/test20881.d(20): Error: scope variable `this` may not be returned fail_compilation/test20881.d(27): Error: address of variable `s` assigned to `global` with longer lifetime fail_compilation/test20881.d(28): Error: address of variable `s` assigned to `global` with longer lifetime fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `global` with longer lifetime @@ -10,7 +11,6 @@ fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `gl @safe: // https://issues.dlang.org/show_bug.cgi?id=20881 - struct S { int* ptr; diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp new file mode 100644 index 0000000..ad70d0a --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp @@ -0,0 +1,46 @@ +#include <assert.h> + +class A22351 +{ +public: + virtual int f(); + virtual int g(int *); + virtual int h(); + virtual int h() const; +}; + +class B22351 : public A22351 +{ +public: + virtual int f() const; + virtual int g(const int *); + int h() const override; +}; + +B22351 *createB(); + +int main() +{ + // mutable A calls functions in A vtable + A22351 *a = createB(); + assert(a->f() == 1); + assert(a->g(0) == 3); + assert(a->h() == 5); + + // cast to B calls functions in B vtable + B22351 *b = (B22351 *)a; + assert(b->f() == 2); + assert(b->g(0) == 4); + assert(b->h() == 6); + + // cast to const calls B override function + const A22351 *ca = a; + assert(ca->h() == 6); + + // const B calls functions in B vtable + const B22351 *cb = createB(); + assert(cb->f() == 2); + assert(cb->h() == 6); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp new file mode 100644 index 0000000..d4193c9 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp @@ -0,0 +1,52 @@ +class Mutable +{ +public: + virtual ~Mutable(); + virtual void func(); +}; + +Mutable::~Mutable() +{ +} + +class DeriveMutable final : public Mutable +{ +public: + virtual ~DeriveMutable(); + void func() override; +}; + +DeriveMutable::~DeriveMutable() +{ +} + +class Const +{ +public: + virtual ~Const(); + virtual void func() const; +}; + +Const::~Const() +{ +} + +class DeriveConst final : public Const +{ +public: + virtual ~DeriveConst(); + void func() const override; +}; + +DeriveConst::~DeriveConst() +{ +} + +void test23135() +{ + DeriveMutable mut; + mut.func(); + + DeriveConst cst; + cst.func(); +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test22351.d b/gcc/testsuite/gdc.test/runnable_cxx/test22351.d new file mode 100644 index 0000000..1c930b6 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test22351.d @@ -0,0 +1,55 @@ +// https://issues.dlang.org/show_bug.cgi?id=22351 +// EXTRA_CPP_SOURCES: test22351.cpp +// REQUIRED_ARGS: -extern-std=c++11 +// CXXFLAGS: -std=c++11 +// DISABLED: win32 + +extern(C++) class A22351 +{ + int f() + { + return 1; + } + + int g(int*) + { + return 3; + } + + int h() + { + return 5; + } + + int h() const + { + return 7; + } +} + +extern(C++) class B22351 : A22351 +{ + alias f = A22351.f; + alias g = A22351.g; + alias h = A22351.h; + + int f() const + { + return 2; + } + + int g(const(int)*) + { + return 4; + } + + override int h() const + { + return 6; + } +} + +extern(C++) B22351 createB() +{ + return new B22351; +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test23135.d b/gcc/testsuite/gdc.test/runnable_cxx/test23135.d new file mode 100644 index 0000000..4a184bb --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/test23135.d @@ -0,0 +1,38 @@ +// https://issues.dlang.org/show_bug.cgi?id=23135 +// EXTRA_CPP_SOURCES: test23135.cpp +// REQUIRED_ARGS: -extern-std=c++11 +// CXXFLAGS: -std=c++11 +// DISABLED: win32 + +void main() +{ + test23135(); +} + +extern(C++): + +void test23135(); + +class Mutable +{ + ~this(); + void func() { } +} + +final class DeriveMutable : Mutable +{ + ~this(); + override void func() { } +} + +class Const +{ + ~this(); + void func() const { } +} + +final class DeriveConst : Const +{ + ~this(); + override void func() const { } +} diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90 index 2217eab..93075fb 100644 --- a/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90 @@ -1,9 +1,9 @@ ! { dg-do compile } module declare_target_2 - !$omp declare target to (a) link (a) ! { dg-error "TO clause and later in LINK" } + !$omp declare target to (a) link (a) ! { dg-error "mentioned multiple times in clauses of the same OMP DECLARE TARGET directive" } !$omp declare target (b) - !$omp declare target link (b) ! { dg-error "TO clause and later in LINK" } + !$omp declare target link (b) ! { dg-error "TO or ENTER clause and later in LINK" } !$omp declare target link (f) !$omp declare target to (f) ! { dg-error "LINK clause and later in TO" } !$omp declare target(c, c) ! { dg-error "mentioned multiple times in clauses of the same" } @@ -39,9 +39,9 @@ subroutine foo ! { dg-error "attribute conflicts" } !$omp declare target to (/c2/) !$omp declare target (/c2/) !$omp declare target to(/c2/) - !$omp declare target link(/c2/) ! { dg-error "TO clause and later in LINK" } + !$omp declare target link(/c2/) ! { dg-error "TO or ENTER clause and later in LINK" } !$omp declare target link(/c3/) - !$omp declare target (/c3/) ! { dg-error "LINK clause and later in TO" } + !$omp declare target (/c3/) ! { dg-error "LINK clause and later in ENTER" } !$omp declare target (/c4/, /c4/) ! { dg-error "mentioned multiple times in clauses of the same" } !$omp declare target to (/c4/) to(/c4/) ! { dg-error "mentioned multiple times in clauses of the same" } !$omp declare target link (/c5/) @@ -49,3 +49,13 @@ subroutine foo ! { dg-error "attribute conflicts" } !$omp declare target link(/c5/)link(/c5/) ! { dg-error "mentioned multiple times in clauses of the same" } !$omp declare target link(/c5/,/c5/) ! { dg-error "mentioned multiple times in clauses of the same" } end subroutine + +module declare_target_3 + !$omp declare target enter (a) link (a) ! { dg-error "mentioned multiple times in clauses of the same OMP DECLARE TARGET directive" } + !$omp declare target link(b) enter(b) ! { dg-error "mentioned multiple times in clauses of the same OMP DECLARE TARGET directive" } + !$omp declare target to (c) enter (c) ! { dg-error "mentioned multiple times in clauses of the same" } + !$omp declare target enter (d) to (d) ! { dg-error "mentioned multiple times in clauses of the same" } + !$omp declare target enter (e) enter (e) ! { dg-error "mentioned multiple times in clauses of the same" } + integer, save :: a, b, c, d, e +end + diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90 index 8947b88..4f5de4b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90 @@ -21,6 +21,10 @@ subroutine f5 !$omp declare target device_type (nohost) to (f5) end subroutine +subroutine f6 + !$omp declare target enter (f6) device_type (any) +end subroutine + module mymod ! device_type is ignored for variables in OpenMP 5.0 ! but TR8 and later apply those rules to variables as well @@ -69,13 +73,14 @@ module m2 public :: m, n, o, p, q, r, s, t, u, v, w, x end module m2 -! { dg-final { scan-tree-dump-times "omp declare target" 7 "original" } } -! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(" 7 "original" } } +! { dg-final { scan-tree-dump-times "omp declare target" 8 "original" } } +! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(" 8 "original" } } ! { dg-final { scan-tree-dump-not "__attribute__\\(\\(omp declare target \[^\n\r\]*\[\n\r\]void f1" "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(any\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r]void f2" 1 "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(any\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r\]void f3" 1 "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(host\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r\]void f4" 1 "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(nohost\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r\]void f5" 1 "original" } } +! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(any\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r]void f6" 1 "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(any\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r\]void s1" 1 "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(nohost\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r\]void s2" 1 "original" } } ! { dg-final { scan-tree-dump-times "__attribute__\\(\\(omp declare target \\(device_type\\(host\\)\\)\\)\\)\[\n\r]__attribute__\[^\n\r]+\[\n\r\]void s3" 1 "original" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-4.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-4.f90 index b17aceb..c870a28 100644 --- a/gcc/testsuite/gfortran.dg/gomp/requires-4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/requires-4.f90 @@ -9,7 +9,7 @@ end module m subroutine foo !$omp target !$omp end target -! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFSET but other program units do" "" { target *-*-* } 9 } +! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFLOAD but other program units do" "" { target *-*-* } 9 } ! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES UNIFIED_ADDRESS but other program units do" "" { target *-*-* } 9 } ! { dg-error "OpenMP device constructs/routines but does not set !.OMP REQUIRES UNIFIED_SHARED_MEMORY but other program units do" "" { target *-*-* } 9 } end diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-8.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-8.f90 index eadfcaf..e84d609 100644 --- a/gcc/testsuite/gfortran.dg/gomp/requires-8.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/requires-8.f90 @@ -13,7 +13,7 @@ contains end subroutine foo end module m -subroutine bar ! { dg-error "has OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFSET but other program units do" } +subroutine bar ! { dg-error "has OpenMP device constructs/routines but does not set !.OMP REQUIRES REVERSE_OFFLOAD but other program units do" } !use m !$omp requires unified_shared_memory !$omp declare target diff --git a/gcc/testsuite/gfortran.dg/gomp/taskwait-depend-nowait-1.f90 b/gcc/testsuite/gfortran.dg/gomp/taskwait-depend-nowait-1.f90 new file mode 100644 index 0000000..cd2f1d2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/taskwait-depend-nowait-1.f90 @@ -0,0 +1,14 @@ +subroutine foo (p) + integer :: p(*) + !$omp taskwait depend(iterator(i = 1:17) , in : p(i)) nowait depend(out : p(32)) +end + +subroutine bar (p) + implicit none + integer :: p(*) + !$omp taskwait depend(mutexinoutset : p(1)) nowait ! { dg-error "'mutexinoutset' kind in 'depend' clause on a 'taskwait' construct" } +end + +subroutine baz + !$omp taskwait nowait ! { dg-error "'taskwait' construct with 'nowait' clause but no 'depend' clauses" } +end diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 0a962dd..8de1b14 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -9028,11 +9028,16 @@ gimple_lv_add_condition_to_bb (basic_block first_head ATTRIBUTE_UNUSED, edge e0; /* Build new conditional expr */ + gsi = gsi_last_bb (cond_bb); + + cond_expr = force_gimple_operand_gsi_1 (&gsi, cond_expr, + is_gimple_condexpr_for_cond, + NULL_TREE, false, + GSI_CONTINUE_LINKING); new_cond_expr = gimple_build_cond_from_tree (cond_expr, NULL_TREE, NULL_TREE); /* Add new cond in cond_bb. */ - gsi = gsi_last_bb (cond_bb); gsi_insert_after (&gsi, new_cond_expr, GSI_NEW_STMT); /* Adjust edges appropriately to connect new head with first head diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 2383b57..ab5fa01 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -302,9 +302,9 @@ enum omp_clause_code { /* OpenMP clause: uniform (argument-list). */ OMP_CLAUSE_UNIFORM, - /* OpenMP clause: to (extended-list). - Only when it appears in declare target. */ - OMP_CLAUSE_TO_DECLARE, + /* OpenMP clause: enter (extended-list). + to is a deprecated alias when it appears in declare target. */ + OMP_CLAUSE_ENTER, /* OpenMP clause: link (variable-list). */ OMP_CLAUSE_LINK, diff --git a/gcc/tree-dfa.cc b/gcc/tree-dfa.cc index 21c82ce..e75e3d6 100644 --- a/gcc/tree-dfa.cc +++ b/gcc/tree-dfa.cc @@ -453,8 +453,8 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset, if (!next || TREE_CODE (stype) != RECORD_TYPE) { - tree fsize = DECL_SIZE_UNIT (field); - tree ssize = TYPE_SIZE_UNIT (stype); + tree fsize = DECL_SIZE (field); + tree ssize = TYPE_SIZE (stype); if (fsize == NULL || !poly_int_tree_p (fsize) || ssize == NULL @@ -465,7 +465,6 @@ get_ref_base_and_extent (tree exp, poly_int64_pod *poffset, poly_offset_int tem = (wi::to_poly_offset (ssize) - wi::to_poly_offset (fsize)); - tem <<= LOG2_BITS_PER_UNIT; tem -= woffset; maxsize += tem; } diff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc index 078ceab..9952809 100644 --- a/gcc/tree-nested.cc +++ b/gcc/tree-nested.cc @@ -1335,7 +1335,7 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_ENTER: case OMP_CLAUSE_LINK: case OMP_CLAUSE_USE_DEVICE_PTR: case OMP_CLAUSE_USE_DEVICE_ADDR: @@ -2120,7 +2120,7 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_SHARED: - case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_ENTER: case OMP_CLAUSE_LINK: case OMP_CLAUSE_USE_DEVICE_PTR: case OMP_CLAUSE_USE_DEVICE_ADDR: diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index 333ac23..6acd394 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -517,8 +517,11 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) case OMP_CLAUSE__SCANTEMP_: name = "_scantemp_"; goto print_remap; - case OMP_CLAUSE_TO_DECLARE: - name = "to"; + case OMP_CLAUSE_ENTER: + if (OMP_CLAUSE_ENTER_TO (clause)) + name = "to"; + else + name = "enter"; goto print_remap; case OMP_CLAUSE_LINK: name = "link"; diff --git a/gcc/tree-ssa-dse.cc b/gcc/tree-ssa-dse.cc index 881a2d0..ea50de7 100644 --- a/gcc/tree-ssa-dse.cc +++ b/gcc/tree-ssa-dse.cc @@ -898,6 +898,17 @@ dse_optimize_redundant_stores (gimple *stmt) } } +/* Return whether PHI contains ARG as an argument. */ + +static bool +contains_phi_arg (gphi *phi, tree arg) +{ + for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i) + if (gimple_phi_arg_def (phi, i) == arg) + return true; + return false; +} + /* A helper of dse_optimize_stmt. Given a GIMPLE_ASSIGN in STMT that writes to REF, classify it according to downstream uses and defs. Sets *BY_CLOBBER_P to true @@ -949,8 +960,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt, return DSE_STORE_LIVE; auto_vec<gimple *, 10> defs; - gimple *first_phi_def = NULL; - gimple *last_phi_def = NULL; + gphi *first_phi_def = NULL; + gphi *last_phi_def = NULL; FOR_EACH_IMM_USE_STMT (use_stmt, ui, defvar) { /* Limit stmt walking. */ @@ -973,8 +984,8 @@ dse_classify_store (ao_ref *ref, gimple *stmt, { defs.safe_push (use_stmt); if (!first_phi_def) - first_phi_def = use_stmt; - last_phi_def = use_stmt; + first_phi_def = as_a <gphi *> (use_stmt); + last_phi_def = as_a <gphi *> (use_stmt); } } /* If the statement is a use the store is not dead. */ @@ -1046,6 +1057,7 @@ dse_classify_store (ao_ref *ref, gimple *stmt, use_operand_p use_p; tree vdef = (gimple_code (def) == GIMPLE_PHI ? gimple_phi_result (def) : gimple_vdef (def)); + gphi *phi_def; /* If the path to check starts with a kill we do not need to process it further. ??? With byte tracking we need only kill the bytes currently @@ -1079,7 +1091,31 @@ dse_classify_store (ao_ref *ref, gimple *stmt, && bitmap_bit_p (visited, SSA_NAME_VERSION (PHI_RESULT (use_stmt)))))) - defs.unordered_remove (i); + { + defs.unordered_remove (i); + if (def == first_phi_def) + first_phi_def = NULL; + else if (def == last_phi_def) + last_phi_def = NULL; + } + /* If def is a PHI and one of its arguments is another PHI node still + in consideration we can defer processing it. */ + else if ((phi_def = dyn_cast <gphi *> (def)) + && ((last_phi_def + && phi_def != last_phi_def + && contains_phi_arg (phi_def, + gimple_phi_result (last_phi_def))) + || (first_phi_def + && phi_def != first_phi_def + && contains_phi_arg + (phi_def, gimple_phi_result (first_phi_def))))) + { + defs.unordered_remove (i); + if (phi_def == first_phi_def) + first_phi_def = NULL; + else if (phi_def == last_phi_def) + last_phi_def = NULL; + } else ++i; } diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index d698a48..c387e84 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -2953,7 +2953,8 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi) : (elts[0].second == 0 && elts[0].first == 0 ? 0 : refnelts) + i); vec_perm_indices indices (sel, orig[1] ? 2 : 1, refnelts); - if (!can_vec_perm_const_p (TYPE_MODE (perm_type), indices)) + machine_mode vmode = TYPE_MODE (perm_type); + if (!can_vec_perm_const_p (vmode, vmode, indices)) return false; mask_type = build_vector_type (build_nonstandard_integer_type (elem_size, 1), @@ -3002,7 +3003,8 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi) sel.quick_push (elts[i].first ? elts[i].second + nelts : i); vec_perm_indices indices (sel, 2, nelts); - if (!can_vec_perm_const_p (TYPE_MODE (type), indices)) + machine_mode vmode = TYPE_MODE (type); + if (!can_vec_perm_const_p (vmode, vmode, indices)) return false; mask_type = build_vector_type (build_nonstandard_integer_type (elem_size, 1), diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc index 2927f30..f32f1a7 100644 --- a/gcc/tree-ssa-loop-unswitch.cc +++ b/gcc/tree-ssa-loop-unswitch.cc @@ -38,6 +38,10 @@ along with GCC; see the file COPYING3. If not see #include "cfghooks.h" #include "tree-ssa-loop-manip.h" #include "tree-vectorizer.h" +#include "tree-pretty-print.h" +#include "gimple-range.h" +#include "dbgcnt.h" +#include "cfganal.h" /* This file implements the loop unswitching, i.e. transformation of loops like @@ -75,9 +79,137 @@ along with GCC; see the file COPYING3. If not see tree-ssa-loop-im.cc ensures that all the suitable conditions are in this shape. */ -static class loop *tree_unswitch_loop (class loop *, basic_block, tree); -static bool tree_unswitch_single_loop (class loop *, int); -static tree tree_may_unswitch_on (basic_block, class loop *); +/* Loop unswitching algorithm for innermost loops works in the following steps: + + 1) Number of instructions is estimated for each BB that belongs to a loop. + 2) Unswitching candidates are found for gcond and gswitch statements + (note that an unswitching predicate for a gswitch actually corresponds + to a non-default edge so it can contain multiple cases). + 3) The so called unswitch predicates are stored in a cache where the + gimple_uid of the last stmt in a basic-block is an index to the cache. + 4) We consider one by one the unswitching candidates and calculate BBs that + will be reachable in the unswitch version. + 5) A selected predicate is chosen and we simplify the CFG (dead edges) in + both versions of the loop. We utilize both Ranger for condition + simplification and also symbol equivalence. The folded if conditions + are replaced with true/false values, while for gswitch we mark the + corresponding edges with a pass-defined unreachable flag. + 6) Every time we unswitch a loop, we save unswitch_predicate to a vector + together with information if true or false edge was taken. Doing that + we have a so called PREDICATE_PATH that is utilized for simplification + of the cloned loop. + 7) The process is repeated until we reach a growth threshold or all + unswitching opportunities are taken. */ + +/* A tuple that holds a GENERIC condition and value range for an unswitching + predicate. */ + +struct unswitch_predicate +{ + /* CTOR for a switch edge predicate. */ + unswitch_predicate (tree cond, tree lhs_, int edge_index_, edge e, + const int_range_max& edge_range) + : condition (cond), lhs (lhs_), + true_range (edge_range), edge_index (edge_index_), switch_p (true) + { + gcc_assert (!(e->flags & (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE)) + && irange::supports_type_p (TREE_TYPE (lhs))); + false_range = true_range; + if (!false_range.varying_p () + && !false_range.undefined_p ()) + false_range.invert (); + num = predicates->length (); + predicates->safe_push (this); + } + + /* CTOR for a GIMPLE condition statement. */ + unswitch_predicate (gcond *stmt) + : switch_p (false) + { + if (EDGE_SUCC (gimple_bb (stmt), 0)->flags & EDGE_TRUE_VALUE) + edge_index = 0; + else + edge_index = 1; + lhs = gimple_cond_lhs (stmt); + tree rhs = gimple_cond_rhs (stmt); + enum tree_code code = gimple_cond_code (stmt); + condition = build2 (code, boolean_type_node, lhs, rhs); + if (irange::supports_type_p (TREE_TYPE (lhs))) + { + auto range_op = range_op_handler (code, TREE_TYPE (lhs)); + int_range<2> rhs_range (TREE_TYPE (rhs)); + if (CONSTANT_CLASS_P (rhs)) + rhs_range.set (rhs); + if (!range_op->op1_range (true_range, TREE_TYPE (lhs), + int_range<2> (boolean_true_node, + boolean_true_node), rhs_range) + || !range_op->op1_range (false_range, TREE_TYPE (lhs), + int_range<2> (boolean_false_node, + boolean_false_node), + rhs_range)) + { + true_range.set_varying (TREE_TYPE (lhs)); + false_range.set_varying (TREE_TYPE (lhs)); + } + } + num = predicates->length (); + predicates->safe_push (this); + } + + /* Copy ranges for purpose of usage in predicate path. */ + + inline void + copy_merged_ranges () + { + merged_true_range = true_range; + merged_false_range = false_range; + } + + /* GENERIC unswitching expression testing LHS against CONSTANT. */ + tree condition; + + /* LHS of the expression. */ + tree lhs; + + /* Initial ranges (when the expression is true/false) for the expression. */ + int_range_max true_range = {}, false_range = {}; + + /* Modified range that is part of a predicate path. */ + int_range_max merged_true_range = {}, merged_false_range = {}; + + /* Index of the edge the predicate belongs to in the successor vector. */ + int edge_index; + + /* Whether the predicate was created from a switch statement. */ + bool switch_p; + + /* The number of the predicate in the predicates vector below. */ + unsigned num; + + /* Vector of all used predicates, used for assigning a unique id that + can be used for bitmap operations. */ + static vec<unswitch_predicate *> *predicates; +}; + +vec<unswitch_predicate *> *unswitch_predicate::predicates; + +/* Ranger instance used in the pass. */ +static gimple_ranger *ranger = NULL; + +/* Cache storage for unswitch_predicate belonging to a basic block. */ +static vec<vec<unswitch_predicate *>> *bb_predicates; + +/* The type represents a predicate path leading to a basic block. */ +typedef vec<std::pair<unswitch_predicate *, bool>> predicate_vector; + +static class loop *tree_unswitch_loop (class loop *, edge, tree); +static bool tree_unswitch_single_loop (class loop *, dump_user_location_t, + predicate_vector &predicate_path, + unsigned loop_size, unsigned &budget, + int ignored_edge_flag, bitmap); +static void +find_unswitching_predicates_for_bb (basic_block bb, class loop *loop, + vec<unswitch_predicate *> &candidates); static bool tree_unswitch_outer_loop (class loop *); static edge find_loop_guard (class loop *, vec<gimple *>&); static bool empty_bb_without_guard_p (class loop *, basic_block, @@ -86,26 +218,154 @@ static bool used_outside_loop_p (class loop *, tree, vec<gimple *>&); static void hoist_guard (class loop *, edge); static bool check_exit_phi (class loop *); static tree get_vop_from_header (class loop *); +static void clean_up_after_unswitching (int); + +/* Return vector of predicates that belong to a basic block. */ + +static vec<unswitch_predicate *> & +get_predicates_for_bb (basic_block bb) +{ + gimple *last = last_stmt (bb); + return (*bb_predicates)[last == NULL ? 0 : gimple_uid (last)]; +} + +/* Save predicates that belong to a basic block. */ + +static void +set_predicates_for_bb (basic_block bb, vec<unswitch_predicate *> predicates) +{ + gimple_set_uid (last_stmt (bb), bb_predicates->length ()); + bb_predicates->safe_push (predicates); +} + +/* Initialize LOOP information reused during the unswitching pass. + Return total number of instructions in the loop. */ + +static unsigned +init_loop_unswitch_info (class loop *loop) +{ + unsigned total_insns = 0; + + /* Calculate instruction count. */ + basic_block *bbs = get_loop_body (loop); + for (unsigned i = 0; i < loop->num_nodes; i++) + { + unsigned insns = 0; + for (gimple_stmt_iterator gsi = gsi_start_bb (bbs[i]); !gsi_end_p (gsi); + gsi_next (&gsi)) + insns += estimate_num_insns (gsi_stmt (gsi), &eni_size_weights); + + bbs[i]->aux = (void *)(uintptr_t)insns; + total_insns += insns; + } + + /* Find all unswitching candidates. */ + for (unsigned i = 0; i != loop->num_nodes; i++) + { + /* Find a bb to unswitch on. */ + vec<unswitch_predicate *> candidates; + candidates.create (1); + find_unswitching_predicates_for_bb (bbs[i], loop, candidates); + if (!candidates.is_empty ()) + set_predicates_for_bb (bbs[i], candidates); + else + { + candidates.release (); + gimple *last = last_stmt (bbs[i]); + if (last != NULL) + gimple_set_uid (last, 0); + } + } + + free (bbs); + + return total_insns; +} /* Main entry point. Perform loop unswitching on all suitable loops. */ unsigned int -tree_ssa_unswitch_loops (void) +tree_ssa_unswitch_loops (function *fun) { - bool changed = false; + bool changed_unswitch = false; + bool changed_hoist = false; + auto_edge_flag ignored_edge_flag (fun); + + ranger = enable_ranger (fun); /* Go through all loops starting from innermost. */ - for (auto loop : loops_list (cfun, LI_FROM_INNERMOST)) + for (auto loop : loops_list (fun, LI_FROM_INNERMOST)) { if (!loop->inner) - /* Unswitch innermost loop. */ - changed |= tree_unswitch_single_loop (loop, 0); + { + /* Perform initial tests if unswitch is eligible. */ + dump_user_location_t loc = find_loop_location (loop); + + /* Do not unswitch in cold regions. */ + if (optimize_loop_for_size_p (loop)) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, loc, + "Not unswitching cold loops\n"); + continue; + } + + /* If the loop is not expected to iterate, there is no need + for unswitching. */ + HOST_WIDE_INT iterations = estimated_loop_iterations_int (loop); + if (iterations < 0) + iterations = likely_max_loop_iterations_int (loop); + if (iterations >= 0 && iterations <= 1) + { + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, loc, + "Not unswitching, loop is not expected" + " to iterate\n"); + continue; + } + + bb_predicates = new vec<vec<unswitch_predicate *>> (); + bb_predicates->safe_push (vec<unswitch_predicate *> ()); + unswitch_predicate::predicates = new vec<unswitch_predicate *> (); + + /* Unswitch innermost loop. */ + unsigned int loop_size = init_loop_unswitch_info (loop); + unsigned int budget = loop_size + param_max_unswitch_insns; + + predicate_vector predicate_path; + predicate_path.create (8); + auto_bitmap handled; + changed_unswitch + |= tree_unswitch_single_loop (loop, loc, predicate_path, + loop_size, budget, + ignored_edge_flag, handled); + predicate_path.release (); + + for (auto predlist : bb_predicates) + predlist.release (); + bb_predicates->release (); + delete bb_predicates; + bb_predicates = NULL; + + for (auto pred : unswitch_predicate::predicates) + delete pred; + unswitch_predicate::predicates->release (); + delete unswitch_predicate::predicates; + unswitch_predicate::predicates = NULL; + } else - changed |= tree_unswitch_outer_loop (loop); + changed_hoist |= tree_unswitch_outer_loop (loop); } - if (changed) + disable_ranger (fun); + clear_aux_for_blocks (); + + if (changed_unswitch) + clean_up_after_unswitching (ignored_edge_flag); + + if (changed_unswitch || changed_hoist) return TODO_cleanup_cfg; + return 0; } @@ -184,319 +444,588 @@ is_maybe_undefined (const tree name, gimple *stmt, class loop *loop) } /* Checks whether we can unswitch LOOP on condition at end of BB -- one of its - basic blocks (for what it means see comments below). */ + basic blocks (for what it means see comments below). + All candidates all filled to the provided vector CANDIDATES. */ -static tree -tree_may_unswitch_on (basic_block bb, class loop *loop) +static void +find_unswitching_predicates_for_bb (basic_block bb, class loop *loop, + vec<unswitch_predicate *> &candidates) { gimple *last, *def; - gcond *stmt; - tree cond, use; + tree use; basic_block def_bb; ssa_op_iter iter; /* BB must end in a simple conditional jump. */ last = last_stmt (bb); - if (!last || gimple_code (last) != GIMPLE_COND) - return NULL_TREE; - stmt = as_a <gcond *> (last); - - /* To keep the things simple, we do not directly remove the conditions, - but just replace tests with 0 != 0 resp. 1 != 0. Prevent the infinite - loop where we would unswitch again on such a condition. */ - if (gimple_cond_true_p (stmt) || gimple_cond_false_p (stmt)) - return NULL_TREE; - - /* Condition must be invariant. */ - FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) + if (!last) + return; + + if (gcond *stmt = safe_dyn_cast <gcond *> (last)) { - def = SSA_NAME_DEF_STMT (use); + /* To keep the things simple, we do not directly remove the conditions, + but just replace tests with 0 != 0 resp. 1 != 0. Prevent the infinite + loop where we would unswitch again on such a condition. */ + if (gimple_cond_true_p (stmt) || gimple_cond_false_p (stmt)) + return; + + /* At least the LHS needs to be symbolic. */ + if (TREE_CODE (gimple_cond_lhs (stmt)) != SSA_NAME) + return; + + /* Condition must be invariant. */ + FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) + { + def = SSA_NAME_DEF_STMT (use); + def_bb = gimple_bb (def); + if (def_bb + && flow_bb_inside_loop_p (loop, def_bb)) + return; + /* Unswitching on undefined values would introduce undefined + behavior that the original program might never exercise. */ + if (is_maybe_undefined (use, stmt, loop)) + return; + } + + unswitch_predicate *predicate = new unswitch_predicate (stmt); + candidates.safe_push (predicate); + } + else if (gswitch *stmt = safe_dyn_cast <gswitch *> (last)) + { + unsigned nlabels = gimple_switch_num_labels (stmt); + tree idx = gimple_switch_index (stmt); + if (TREE_CODE (idx) != SSA_NAME + || nlabels < 1) + return; + /* Index must be invariant. */ + def = SSA_NAME_DEF_STMT (idx); def_bb = gimple_bb (def); if (def_bb && flow_bb_inside_loop_p (loop, def_bb)) - return NULL_TREE; + return; /* Unswitching on undefined values would introduce undefined behavior that the original program might never exercise. */ - if (is_maybe_undefined (use, stmt, loop)) - return NULL_TREE; - } + if (is_maybe_undefined (idx, stmt, loop)) + return; + + /* Build compound expression for all outgoing edges of the switch. */ + auto_vec<tree, 16> preds; + auto_vec<int_range_max> edge_range; + preds.safe_grow_cleared (EDGE_COUNT (gimple_bb (stmt)->succs), true); + edge_range.safe_grow_cleared (EDGE_COUNT (gimple_bb (stmt)->succs), true); + edge e; + edge_iterator ei; + unsigned edge_index = 0; + FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs) + e->aux = (void *)(uintptr_t)edge_index++; + for (unsigned i = 1; i < gimple_switch_num_labels (stmt); ++i) + { + tree lab = gimple_switch_label (stmt, i); + tree cmp; + int_range<2> lab_range; + if (CASE_HIGH (lab) != NULL_TREE) + { + tree cmp1 = fold_build2 (GE_EXPR, boolean_type_node, idx, + CASE_LOW (lab)); + tree cmp2 = fold_build2 (LE_EXPR, boolean_type_node, idx, + CASE_HIGH (lab)); + cmp = fold_build2 (BIT_AND_EXPR, boolean_type_node, cmp1, cmp2); + lab_range.set (CASE_LOW (lab), CASE_HIGH (lab)); + } + else + { + cmp = fold_build2 (EQ_EXPR, boolean_type_node, idx, + CASE_LOW (lab)); + lab_range.set (CASE_LOW (lab)); + } - cond = build2 (gimple_cond_code (stmt), boolean_type_node, - gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); + /* Combine the expression with the existing one. */ + basic_block dest = label_to_block (cfun, CASE_LABEL (lab)); + e = find_edge (gimple_bb (stmt), dest); + tree &expr = preds[(uintptr_t)e->aux]; + if (expr == NULL_TREE) + expr = cmp; + else + expr = fold_build2 (BIT_IOR_EXPR, boolean_type_node, expr, cmp); + edge_range[(uintptr_t)e->aux].union_ (lab_range); + } - return cond; + /* Now register the predicates. */ + for (edge_index = 0; edge_index < preds.length (); ++edge_index) + { + edge e = EDGE_SUCC (gimple_bb (stmt), edge_index); + e->aux = NULL; + if (preds[edge_index] != NULL_TREE) + { + unswitch_predicate *predicate + = new unswitch_predicate (preds[edge_index], idx, + edge_index, e, + edge_range[edge_index]); + candidates.safe_push (predicate); + } + } + } } -/* Simplifies COND using checks in front of the entry of the LOOP. Just very - simplish (sufficient to prevent us from duplicating loop in unswitching - unnecessarily). */ +/* Merge ranges for the last item of PREDICATE_PATH with a predicate + that shared the same LHS. */ -static tree -simplify_using_entry_checks (class loop *loop, tree cond) +static void +merge_last (predicate_vector &predicate_path) { - edge e = loop_preheader_edge (loop); - gimple *stmt; + unswitch_predicate *last_predicate = predicate_path.last ().first; - while (1) + for (int i = predicate_path.length () - 2; i >= 0; i--) { - stmt = last_stmt (e->src); - if (stmt - && gimple_code (stmt) == GIMPLE_COND - && gimple_cond_code (stmt) == TREE_CODE (cond) - && operand_equal_p (gimple_cond_lhs (stmt), - TREE_OPERAND (cond, 0), 0) - && operand_equal_p (gimple_cond_rhs (stmt), - TREE_OPERAND (cond, 1), 0)) - return (e->flags & EDGE_TRUE_VALUE - ? boolean_true_node - : boolean_false_node); - - if (!single_pred_p (e->src)) - return cond; - - e = single_pred_edge (e->src); - if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun)) - return cond; + unswitch_predicate *predicate = predicate_path[i].first; + bool true_edge = predicate_path[i].second; + + if (operand_equal_p (predicate->lhs, last_predicate->lhs, 0)) + { + irange &other = (true_edge ? predicate->merged_true_range + : predicate->merged_false_range); + last_predicate->merged_true_range.intersect (other); + last_predicate->merged_false_range.intersect (other); + return; + } } } -/* Unswitch single LOOP. NUM is number of unswitchings done; we do not allow - it to grow too much, it is too easy to create example on that the code would - grow exponentially. */ +/* Add PREDICATE to PREDICATE_PATH on TRUE_EDGE. */ -static bool -tree_unswitch_single_loop (class loop *loop, int num) +static void +add_predicate_to_path (predicate_vector &predicate_path, + unswitch_predicate *predicate, bool true_edge) { - basic_block *bbs; - class loop *nloop; - unsigned i, found; - tree cond = NULL_TREE; - gimple *stmt; - bool changed = false; - HOST_WIDE_INT iterations; - - dump_user_location_t loc = find_loop_location (loop); + predicate->copy_merged_ranges (); + predicate_path.safe_push (std::make_pair (predicate, true_edge)); + merge_last (predicate_path); +} - /* Perform initial tests if unswitch is eligible. */ - if (num == 0) +static bool +find_range_for_lhs (predicate_vector &predicate_path, tree lhs, + int_range_max &range) +{ + for (int i = predicate_path.length () - 1; i >= 0; i--) { - /* Do not unswitch in cold regions. */ - if (optimize_loop_for_size_p (loop)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, loc, - "Not unswitching cold loops\n"); - return false; - } + unswitch_predicate *predicate = predicate_path[i].first; + bool true_edge = predicate_path[i].second; - /* The loop should not be too large, to limit code growth. */ - if (tree_num_loop_insns (loop, &eni_size_weights) - > (unsigned) param_max_unswitch_insns) + if (operand_equal_p (predicate->lhs, lhs, 0)) { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, loc, - "Not unswitching, loop too big\n"); - return false; + range = (true_edge ? predicate->merged_true_range + : predicate->merged_false_range); + return !range.undefined_p (); } + } - /* If the loop is not expected to iterate, there is no need - for unswitching. */ - iterations = estimated_loop_iterations_int (loop); - if (iterations < 0) - iterations = likely_max_loop_iterations_int (loop); - if (iterations >= 0 && iterations <= 1) + return false; +} + +/* Simplifies STMT using the predicate we unswitched on which is the last + in PREDICATE_PATH. For switch statements add newly unreachable edges + to IGNORED_EDGES (but do not set IGNORED_EDGE_FLAG on them). */ + +static tree +evaluate_control_stmt_using_entry_checks (gimple *stmt, + predicate_vector &predicate_path, + int ignored_edge_flag, + hash_set<edge> *ignored_edges) +{ + unswitch_predicate *last_predicate = predicate_path.last ().first; + bool true_edge = predicate_path.last ().second; + + if (gcond *cond = dyn_cast<gcond *> (stmt)) + { + tree lhs = gimple_cond_lhs (cond); + if (!operand_equal_p (lhs, last_predicate->lhs)) + return NULL_TREE; + /* Try a symbolic match which works for floating point and fully + symbolic conditions. */ + if (gimple_cond_code (cond) == TREE_CODE (last_predicate->condition) + && operand_equal_p (gimple_cond_rhs (cond), + TREE_OPERAND (last_predicate->condition, 1))) + return true_edge ? boolean_true_node : boolean_false_node; + /* Else try ranger if it supports LHS. */ + else if (irange::supports_type_p (TREE_TYPE (lhs))) { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, loc, - "Not unswitching, loop is not expected" - " to iterate\n"); - return false; + int_range<2> r; + int_range_max path_range; + + if (find_range_for_lhs (predicate_path, lhs, path_range) + && fold_range (r, cond, path_range) + && r.singleton_p ()) + return r.zero_p () ? boolean_false_node : boolean_true_node; } } + else if (gswitch *swtch = dyn_cast<gswitch *> (stmt)) + { + unsigned nlabels = gimple_switch_num_labels (swtch); - i = 0; - bbs = get_loop_body (loop); - found = loop->num_nodes; + tree idx = gimple_switch_index (swtch); - while (1) - { - /* Find a bb to unswitch on. */ - for (; i < loop->num_nodes; i++) - if ((cond = tree_may_unswitch_on (bbs[i], loop))) - break; + /* Already folded switch. */ + if (TREE_CONSTANT (idx)) + return NULL_TREE; - if (i == loop->num_nodes) + int_range_max path_range; + if (!find_range_for_lhs (predicate_path, idx, path_range)) + return NULL_TREE; + + tree result = NULL_TREE; + edge single_edge = NULL; + for (unsigned i = 0; i < nlabels; ++i) { - if (dump_enabled_p () - && num > param_max_unswitch_level) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, - "Not unswitching anymore, hit max level\n"); + tree lab = gimple_switch_label (swtch, i); + basic_block dest = label_to_block (cfun, CASE_LABEL (lab)); + edge e = find_edge (gimple_bb (stmt), dest); + if (e->flags & ignored_edge_flag) + continue; - if (found == loop->num_nodes) + int_range_max r; + if (!ranger->gori ().outgoing_edge_range_p (r, e, idx, + *get_global_range_query ())) + continue; + r.intersect (path_range); + if (r.undefined_p ()) + ignored_edges->add (e); + else { - free (bbs); - return changed; + if (!single_edge) + { + single_edge = e; + result = CASE_LOW (lab); + } + else if (single_edge != e) + result = NULL; } - break; } - cond = simplify_using_entry_checks (loop, cond); - stmt = last_stmt (bbs[i]); - if (integer_nonzerop (cond)) - { - /* Remove false path. */ - gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt), - boolean_true_node); - changed = true; - } - else if (integer_zerop (cond)) + /* Only one edge from the switch is alive. */ + if (single_edge && result) + return result; + } + + return NULL_TREE; +} + +/* Simplify LOOP based on PREDICATE_PATH where dead edges are properly + marked. */ + +static bool +simplify_loop_version (class loop *loop, predicate_vector &predicate_path, + int ignored_edge_flag, bitmap handled) +{ + bool changed = false; + basic_block *bbs = get_loop_body (loop); + + hash_set<edge> ignored_edges; + for (unsigned i = 0; i != loop->num_nodes; i++) + { + vec<unswitch_predicate *> &predicates = get_predicates_for_bb (bbs[i]); + if (predicates.is_empty ()) + continue; + + gimple *stmt = last_stmt (bbs[i]); + tree folded = evaluate_control_stmt_using_entry_checks (stmt, + predicate_path, + ignored_edge_flag, + &ignored_edges); + + if (gcond *cond = dyn_cast<gcond *> (stmt)) { - /* Remove true path. */ - gimple_cond_set_condition_from_tree (as_a <gcond *> (stmt), - boolean_false_node); - changed = true; + if (folded) + { + /* Remove path. */ + if (integer_nonzerop (folded)) + gimple_cond_set_condition_from_tree (cond, boolean_true_node); + else + gimple_cond_set_condition_from_tree (cond, boolean_false_node); + + gcc_assert (predicates.length () == 1); + bitmap_set_bit (handled, predicates[0]->num); + + update_stmt (cond); + changed = true; + } } - /* Do not unswitch too much. */ - else if (num > param_max_unswitch_level) + else if (gswitch *swtch = dyn_cast<gswitch *> (stmt)) { - i++; - continue; + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bbs[i]->succs) + if (ignored_edges.contains (e)) + e->flags |= ignored_edge_flag; + + for (unsigned j = 0; j < predicates.length (); j++) + { + edge e = EDGE_SUCC (bbs[i], predicates[j]->edge_index); + if (ignored_edges.contains (e)) + bitmap_set_bit (handled, predicates[j]->num); + } + + if (folded) + { + gimple_switch_set_index (swtch, folded); + update_stmt (swtch); + changed = true; + } } - /* In nested tree_unswitch_single_loop first optimize all conditions - using entry checks, then discover still reachable blocks in the - loop and find the condition only among those still reachable bbs. */ - else if (num != 0) + } + + free (bbs); + return changed; +} + +/* Evaluate reachable blocks in LOOP and call VISIT on them, aborting the + DFS walk if VISIT returns true. When PREDICATE_PATH is specified then + take into account that when computing reachability, otherwise just + look at the simplified state and IGNORED_EDGE_FLAG. */ + +template <typename VisitOp> +static void +evaluate_bbs (class loop *loop, predicate_vector *predicate_path, + int ignored_edge_flag, VisitOp visit) +{ + auto_bb_flag reachable_flag (cfun); + auto_vec<basic_block, 10> worklist (loop->num_nodes); + auto_vec<basic_block, 10> reachable (loop->num_nodes); + hash_set<edge> ignored_edges; + + loop->header->flags |= reachable_flag; + worklist.quick_push (loop->header); + reachable.safe_push (loop->header); + + while (!worklist.is_empty ()) + { + edge e; + edge_iterator ei; + int flags = ignored_edge_flag; + basic_block bb = worklist.pop (); + + if (visit (bb)) + break; + + gimple *last = last_stmt (bb); + if (gcond *cond = safe_dyn_cast <gcond *> (last)) { - if (found == loop->num_nodes) - found = i; - i++; - continue; + if (gimple_cond_true_p (cond)) + flags = EDGE_FALSE_VALUE; + else if (gimple_cond_false_p (cond)) + flags = EDGE_TRUE_VALUE; + else if (predicate_path) + { + tree res; + if (!get_predicates_for_bb (bb).is_empty () + && (res = evaluate_control_stmt_using_entry_checks + (cond, *predicate_path, ignored_edge_flag, + &ignored_edges))) + flags = (integer_nonzerop (res) + ? EDGE_FALSE_VALUE : EDGE_TRUE_VALUE); + } } - else + else if (gswitch *swtch = safe_dyn_cast<gswitch *> (last)) + if (predicate_path + && !get_predicates_for_bb (bb).is_empty ()) + evaluate_control_stmt_using_entry_checks (swtch, *predicate_path, + ignored_edge_flag, + &ignored_edges); + + /* Note that for the moment we do not account reachable conditions + which are simplified to take a known edge as zero size nor + are we accounting for the required addition of the versioning + condition. Those should cancel out conservatively. */ + + FOR_EACH_EDGE (e, ei, bb->succs) { - found = i; - break; - } + basic_block dest = e->dest; - update_stmt (stmt); - i++; + if (dest->loop_father == loop + && !(dest->flags & reachable_flag) + && !(e->flags & flags) + && !ignored_edges.contains (e)) + { + dest->flags |= reachable_flag; + worklist.safe_push (dest); + reachable.safe_push (dest); + } + } } - if (num != 0) - { - basic_block *tos, *worklist; + /* Clear the flag from basic blocks. */ + while (!reachable.is_empty ()) + reachable.pop ()->flags &= ~reachable_flag; +} - /* When called recursively, first do a quick discovery - of reachable bbs after the above changes and only - consider conditions in still reachable bbs. */ - tos = worklist = XNEWVEC (basic_block, loop->num_nodes); +/* Evaluate how many instruction will we have if we unswitch LOOP (with BBS) + based on PREDICATE predicate (using PREDICATE_PATH). Store the + result in TRUE_SIZE and FALSE_SIZE. */ - for (i = 0; i < loop->num_nodes; i++) - bbs[i]->flags &= ~BB_REACHABLE; +static void +evaluate_loop_insns_for_predicate (class loop *loop, + predicate_vector &predicate_path, + unswitch_predicate *predicate, + int ignored_edge_flag, + unsigned *true_size, unsigned *false_size) +{ + unsigned size = 0; + auto sum_size = [&](basic_block bb) -> bool + { size += (uintptr_t)bb->aux; return false; }; + + add_predicate_to_path (predicate_path, predicate, true); + evaluate_bbs (loop, &predicate_path, ignored_edge_flag, sum_size); + predicate_path.pop (); + unsigned true_loop_cost = size; + + size = 0; + add_predicate_to_path (predicate_path, predicate, false); + evaluate_bbs (loop, &predicate_path, ignored_edge_flag, sum_size); + predicate_path.pop (); + unsigned false_loop_cost = size; + + *true_size = true_loop_cost; + *false_size = false_loop_cost; +} - /* Start with marking header. */ - *tos++ = bbs[0]; - bbs[0]->flags |= BB_REACHABLE; +/* Unswitch single LOOP. PREDICATE_PATH contains so far used predicates + for unswitching. BUDGET is number of instruction for which we can increase + the loop and is updated when unswitching occurs. */ - /* Iterate: find everything reachable from what we've already seen - within the same innermost loop. Don't look through false edges - if condition is always true or true edges if condition is - always false. */ - while (tos != worklist) +static bool +tree_unswitch_single_loop (class loop *loop, dump_user_location_t loc, + predicate_vector &predicate_path, + unsigned loop_size, unsigned &budget, + int ignored_edge_flag, bitmap handled) +{ + class loop *nloop; + bool changed = false; + unswitch_predicate *predicate = NULL; + basic_block predicate_bb = NULL; + unsigned true_size = 0, false_size = 0; + + auto check_predicates = [&](basic_block bb) -> bool + { + for (auto pred : get_predicates_for_bb (bb)) { - basic_block b = *--tos; - edge e; - edge_iterator ei; - int flags = 0; + if (bitmap_bit_p (handled, pred->num)) + continue; - if (EDGE_COUNT (b->succs) == 2) - { - gimple *stmt = last_stmt (b); - if (stmt - && gimple_code (stmt) == GIMPLE_COND) - { - gcond *cond_stmt = as_a <gcond *> (stmt); - if (gimple_cond_true_p (cond_stmt)) - flags = EDGE_FALSE_VALUE; - else if (gimple_cond_false_p (cond_stmt)) - flags = EDGE_TRUE_VALUE; - } - } + evaluate_loop_insns_for_predicate (loop, predicate_path, + pred, ignored_edge_flag, + &true_size, &false_size); - FOR_EACH_EDGE (e, ei, b->succs) + /* We'll get LOOP replaced with a simplified version according + to PRED estimated to TRUE_SIZE and a copy simplified + according to the inverted PRED estimated to FALSE_SIZE. */ + if (true_size + false_size < budget + loop_size) { - basic_block dest = e->dest; - - if (dest->loop_father == loop - && !(dest->flags & BB_REACHABLE) - && !(e->flags & flags)) - { - *tos++ = dest; - dest->flags |= BB_REACHABLE; - } + predicate = pred; + predicate_bb = bb; + + /* There are cases where true_size and false_size add up to + less than the original loop_size. We do not want to + grow the remaining budget because of that. */ + if (true_size + false_size > loop_size) + budget -= (true_size + false_size - loop_size); + + /* FIXME: right now we select first candidate, but we can + choose the cheapest or hottest one. */ + return true; } + else if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, loc, + "not unswitching condition, cost too big " + "(%u insns copied to %u and %u)\n", loop_size, + true_size, false_size); } + return false; + }; + /* Check predicates of reachable blocks. */ + evaluate_bbs (loop, NULL, ignored_edge_flag, check_predicates); - free (worklist); + if (predicate != NULL) + { + if (!dbg_cnt (loop_unswitch)) + goto exit; - /* Find a bb to unswitch on. */ - for (; found < loop->num_nodes; found++) - if ((bbs[found]->flags & BB_REACHABLE) - && (cond = tree_may_unswitch_on (bbs[found], loop))) - break; + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, + "unswitching loop %d on %qs with condition: %T\n", + loop->num, predicate->switch_p ? "switch" : "if", + predicate->condition); + dump_printf_loc (MSG_NOTE, loc, + "optimized sizes estimated to %u (true) " + "and %u (false) from original size %u\n", + true_size, false_size, loop_size); + } - if (found == loop->num_nodes) + bitmap_set_bit (handled, predicate->num); + initialize_original_copy_tables (); + /* Unswitch the loop on this condition. */ + nloop = tree_unswitch_loop (loop, EDGE_SUCC (predicate_bb, + predicate->edge_index), + predicate->condition); + if (!nloop) { - free (bbs); - return changed; + free_original_copy_tables (); + goto exit; } - } - if (dump_enabled_p ()) - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, - "Unswitching loop on condition: %G\n", - last_stmt (bbs[found])); + /* Copy BB costs. */ + basic_block *bbs2 = get_loop_body (nloop); + for (unsigned i = 0; i < nloop->num_nodes; i++) + bbs2[i]->aux = get_bb_original (bbs2[i])->aux; + free (bbs2); - initialize_original_copy_tables (); - /* Unswitch the loop on this condition. */ - nloop = tree_unswitch_loop (loop, bbs[found], cond); - if (!nloop) - { free_original_copy_tables (); - free (bbs); - return changed; - } - /* Update the SSA form after unswitching. */ - update_ssa (TODO_update_ssa); - free_original_copy_tables (); + /* Update the SSA form after unswitching. */ + update_ssa (TODO_update_ssa); + + /* Invoke itself on modified loops. */ + bitmap handled_copy = BITMAP_ALLOC (NULL); + bitmap_copy (handled_copy, handled); + add_predicate_to_path (predicate_path, predicate, false); + changed |= simplify_loop_version (nloop, predicate_path, + ignored_edge_flag, handled_copy); + tree_unswitch_single_loop (nloop, loc, predicate_path, + false_size, budget, + ignored_edge_flag, handled_copy); + predicate_path.pop (); + BITMAP_FREE (handled_copy); + + /* FIXME: After unwinding above we have to reset all ->handled + flags as otherwise we fail to realize unswitching opportunities + in the below recursion. See gcc.dg/loop-unswitch-16.c */ + add_predicate_to_path (predicate_path, predicate, true); + changed |= simplify_loop_version (loop, predicate_path, + ignored_edge_flag, handled); + tree_unswitch_single_loop (loop, loc, predicate_path, + true_size, budget, + ignored_edge_flag, handled); + predicate_path.pop (); + changed = true; + } - /* Invoke itself on modified loops. */ - tree_unswitch_single_loop (nloop, num + 1); - tree_unswitch_single_loop (loop, num + 1); - free (bbs); - return true; +exit: + return changed; } -/* Unswitch a LOOP w.r. to given basic block UNSWITCH_ON. We only support - unswitching of innermost loops. COND is the condition determining which - loop is entered -- the new loop is entered if COND is true. Returns NULL - if impossible, new loop otherwise. */ +/* Unswitch a LOOP w.r. to given EDGE_TRUE. We only support unswitching of + innermost loops. COND is the condition determining which loop is entered; + the new loop is entered if COND is true. Returns NULL if impossible, new + loop otherwise. */ static class loop * -tree_unswitch_loop (class loop *loop, - basic_block unswitch_on, tree cond) +tree_unswitch_loop (class loop *loop, edge edge_true, tree cond) { - profile_probability prob_true; - edge edge_true, edge_false; - /* Some sanity checking. */ - gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on)); - gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2); + gcc_assert (flow_bb_inside_loop_p (loop, edge_true->src)); + gcc_assert (EDGE_COUNT (edge_true->src->succs) >= 2); gcc_assert (loop->inner == NULL); - extract_true_false_edges_from_block (unswitch_on, &edge_true, &edge_false); - prob_true = edge_true->probability; + profile_probability prob_true = edge_true->probability; return loop_version (loop, unshare_expr (cond), NULL, prob_true, prob_true.invert (), @@ -1010,6 +1539,57 @@ check_exit_phi (class loop *loop) return true; } +/* Remove all dead cases from switches that are unswitched. */ + +static void +clean_up_after_unswitching (int ignored_edge_flag) +{ + basic_block bb; + edge e; + edge_iterator ei; + + FOR_EACH_BB_FN (bb, cfun) + { + gswitch *stmt= safe_dyn_cast <gswitch *> (last_stmt (bb)); + if (stmt && !CONSTANT_CLASS_P (gimple_switch_index (stmt))) + { + unsigned nlabels = gimple_switch_num_labels (stmt); + unsigned index = 1; + tree lab = gimple_switch_default_label (stmt); + edge default_e = find_edge (gimple_bb (stmt), + label_to_block (cfun, CASE_LABEL (lab))); + for (unsigned i = 1; i < nlabels; ++i) + { + tree lab = gimple_switch_label (stmt, i); + basic_block dest = label_to_block (cfun, CASE_LABEL (lab)); + edge e = find_edge (gimple_bb (stmt), dest); + if (e == NULL) + ; /* The edge is already removed. */ + else if (e->flags & ignored_edge_flag) + { + /* We may not remove the default label so we also have + to preserve its edge. But we can remove the + non-default CASE sharing the edge. */ + if (e != default_e) + remove_edge (e); + } + else + { + gimple_switch_set_label (stmt, index, lab); + ++index; + } + } + + if (index != nlabels) + gimple_switch_set_num_labels (stmt, index); + } + + /* Clean up the ignored_edge_flag from edges. */ + FOR_EACH_EDGE (e, ei, bb->succs) + e->flags &= ~ignored_edge_flag; + } +} + /* Loop unswitching pass. */ namespace { @@ -1046,7 +1626,7 @@ pass_tree_unswitch::execute (function *fun) if (number_of_loops (fun) <= 1) return 0; - return tree_ssa_unswitch_loops (); + return tree_ssa_unswitch_loops (fun); } } // anon namespace diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index 8c9c46d..e61d973 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -2217,7 +2217,7 @@ spaceship_replacement (basic_block cond_bb, basic_block middle_bb, if (!TYPE_UNSIGNED (ty2) || !INTEGRAL_TYPE_P (ty2)) return false; - if (TYPE_PRECISION (ty1) != TYPE_PRECISION (ty2)) + if (TYPE_PRECISION (ty1) > TYPE_PRECISION (ty2)) return false; if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig_use_lhs)) return false; diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index 09223ba..d20a10a 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -5347,7 +5347,7 @@ vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INT count) sel[3 * i + nelt2] = 0; } indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (mode, indices)) + if (!can_vec_perm_const_p (mode, mode, indices)) { if (dump_enabled_p ()) dump_printf (MSG_MISSED_OPTIMIZATION, @@ -5365,7 +5365,7 @@ vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INT count) sel[3 * i + nelt2] = nelt + j2++; } indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (mode, indices)) + if (!can_vec_perm_const_p (mode, mode, indices)) { if (dump_enabled_p ()) dump_printf (MSG_MISSED_OPTIMIZATION, @@ -5390,12 +5390,12 @@ vect_grouped_store_supported (tree vectype, unsigned HOST_WIDE_INT count) sel[i * 2 + 1] = i + nelt; } vec_perm_indices indices (sel, 2, nelt); - if (can_vec_perm_const_p (mode, indices)) + if (can_vec_perm_const_p (mode, mode, indices)) { for (i = 0; i < 6; i++) sel[i] += exact_div (nelt, 2); indices.new_vector (sel, 2, nelt); - if (can_vec_perm_const_p (mode, indices)) + if (can_vec_perm_const_p (mode, mode, indices)) return true; } } @@ -5963,7 +5963,7 @@ vect_grouped_load_supported (tree vectype, bool single_element_p, else sel[i] = 0; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (mode, indices)) + if (!can_vec_perm_const_p (mode, mode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -5977,7 +5977,7 @@ vect_grouped_load_supported (tree vectype, bool single_element_p, else sel[i] = nelt + ((nelt + k) % 3) + 3 * (j++); indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (mode, indices)) + if (!can_vec_perm_const_p (mode, mode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6000,12 +6000,12 @@ vect_grouped_load_supported (tree vectype, bool single_element_p, for (i = 0; i < 3; i++) sel[i] = i * 2; vec_perm_indices indices (sel, 2, nelt); - if (can_vec_perm_const_p (mode, indices)) + if (can_vec_perm_const_p (mode, mode, indices)) { for (i = 0; i < 3; i++) sel[i] = i * 2 + 1; indices.new_vector (sel, 2, nelt); - if (can_vec_perm_const_p (mode, indices)) + if (can_vec_perm_const_p (mode, mode, indices)) return true; } } @@ -6327,6 +6327,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, gimple *perm_stmt; tree vectype = STMT_VINFO_VECTYPE (stmt_info); + machine_mode vmode = TYPE_MODE (vectype); unsigned int i; loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); @@ -6351,7 +6352,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt / 2; ++i) sel[nelt / 2 + i] = i * 2 + 1; vec_perm_indices indices (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6366,7 +6367,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt / 2; ++i) sel[nelt / 2 + i] = i * 2; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6381,7 +6382,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt; i++) sel[i] = nelt / 2 + i; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6397,7 +6398,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = nelt / 2; i < nelt; i++) sel[i] = nelt + i; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6461,7 +6462,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, k++; } vec_perm_indices indices (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6476,7 +6477,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt; i++) sel[i] = 2 * (nelt / 3) + (nelt % 3) + i; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6490,7 +6491,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt; i++) sel[i] = 2 * (nelt / 3) + 1 + i; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6504,7 +6505,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt; i++) sel[i] = (nelt / 3) + (nelt % 3) / 2 + i; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -6518,7 +6519,7 @@ vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain, for (i = 0; i < nelt; i++) sel[i] = 2 * (nelt / 3) + (nelt % 3) / 2 + i; indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, diff --git a/gcc/tree-vect-generic.cc b/gcc/tree-vect-generic.cc index f7de64c..92aba5d 100644 --- a/gcc/tree-vect-generic.cc +++ b/gcc/tree-vect-generic.cc @@ -1527,7 +1527,10 @@ lower_vec_perm (gimple_stmt_iterator *gsi) && tree_to_vec_perm_builder (&sel_int, mask)) { vec_perm_indices indices (sel_int, 2, elements); - if (can_vec_perm_const_p (TYPE_MODE (vect_type), indices)) + machine_mode vmode = TYPE_MODE (vect_type); + tree lhs_type = TREE_TYPE (gimple_assign_lhs (stmt)); + machine_mode lhs_mode = TYPE_MODE (lhs_type); + if (can_vec_perm_const_p (lhs_mode, vmode, indices)) { gimple_assign_set_rhs3 (stmt, mask); update_stmt (stmt); diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc index 1d4337e..e81de45 100644 --- a/gcc/tree-vect-loop-manip.cc +++ b/gcc/tree-vect-loop-manip.cc @@ -312,7 +312,8 @@ interleave_supported_p (vec_perm_indices *indices, tree vectype, sel.quick_push (base + i + nelts); } indices->new_vector (sel, 2, nelts); - return can_vec_perm_const_p (TYPE_MODE (vectype), *indices); + return can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype), + *indices); } /* Try to use permutes to define the masks in DEST_RGM using the masks @@ -2809,10 +2810,21 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1, if (LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo)) skip_epilog = false; + class loop *scalar_loop = LOOP_VINFO_SCALAR_LOOP (loop_vinfo); + auto_vec<profile_count> original_counts; + basic_block *original_bbs = NULL; + if (skip_vector) { split_edge (loop_preheader_edge (loop)); + if (epilog_peeling && (vect_epilogues || scalar_loop == NULL)) + { + original_bbs = get_loop_body (loop); + for (unsigned int i = 0; i < loop->num_nodes; i++) + original_counts.safe_push(original_bbs[i]->count); + } + /* Due to the order in which we peel prolog and epilog, we first propagate probability to the whole loop. The purpose is to avoid adjusting probabilities of both prolog and vector loops @@ -2827,7 +2839,6 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1, } dump_user_location_t loop_loc = find_loop_location (loop); - class loop *scalar_loop = LOOP_VINFO_SCALAR_LOOP (loop_vinfo); if (vect_epilogues) /* Make sure to set the epilogue's epilogue scalar loop, such that we can use the original scalar loop as remaining epilogue if necessary. */ @@ -2984,16 +2995,19 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1, a merge point of control flow. */ guard_to->count = guard_bb->count; - /* Scale probability of epilog loop back. - FIXME: We should avoid scaling down and back up. Profile may - get lost if we scale down to 0. */ - basic_block *bbs = get_loop_body (epilog); - for (unsigned int i = 0; i < epilog->num_nodes; i++) - bbs[i]->count = bbs[i]->count.apply_scale - (bbs[i]->count, - bbs[i]->count.apply_probability - (prob_vector)); - free (bbs); + /* Restore the counts of the epilog loop if we didn't use the scalar loop. */ + if (vect_epilogues || scalar_loop == NULL) + { + gcc_assert(epilog->num_nodes == loop->num_nodes); + basic_block *bbs = get_loop_body (epilog); + for (unsigned int i = 0; i < epilog->num_nodes; i++) + { + gcc_assert(get_bb_original (bbs[i]) == original_bbs[i]); + bbs[i]->count = original_counts[i]; + } + free (bbs); + free (original_bbs); + } } basic_block bb_before_epilog = loop_preheader_edge (epilog)->src; diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index f204b72..246347b 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -4527,7 +4527,7 @@ have_whole_vector_shift (machine_mode mode) { calc_vec_perm_mask_for_shift (i, nelt, &sel); indices.new_vector (sel, 2, nelt); - if (!can_vec_perm_const_p (mode, indices, false)) + if (!can_vec_perm_const_p (mode, mode, indices, false)) return false; } return true; diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index ac49c1a..0fad4db 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -2649,7 +2649,8 @@ vect_recog_rotate_pattern (vec_info *vinfo, vec_perm_indices indices (elts, 1, TYPE_VECTOR_SUBPARTS (char_vectype)); - if (can_vec_perm_const_p (TYPE_MODE (char_vectype), indices)) + machine_mode vmode = TYPE_MODE (char_vectype); + if (can_vec_perm_const_p (vmode, vmode, indices)) { /* vectorizable_bswap can handle the __builtin_bswap16 if we undo the argument promotion. */ diff --git a/gcc/tree-vect-slp-patterns.cc b/gcc/tree-vect-slp-patterns.cc index a6b0d10..e6a6db8 100644 --- a/gcc/tree-vect-slp-patterns.cc +++ b/gcc/tree-vect-slp-patterns.cc @@ -492,7 +492,7 @@ class complex_pattern : public vect_pattern } public: - void build (vec_info *); + void build (vec_info *) override; static internal_fn matches (complex_operation_t op, slp_tree_to_load_perm_map_t *, slp_tree *, @@ -595,7 +595,7 @@ class complex_add_pattern : public complex_pattern } public: - void build (vec_info *); + void build (vec_info *) final override; static internal_fn matches (complex_operation_t op, slp_tree_to_load_perm_map_t *, slp_compat_nodes_map_t *, slp_tree *, vec<slp_tree> *); @@ -977,7 +977,7 @@ class complex_mul_pattern : public complex_pattern } public: - void build (vec_info *); + void build (vec_info *) final override; static internal_fn matches (complex_operation_t op, slp_tree_to_load_perm_map_t *, slp_compat_nodes_map_t *, slp_tree *, vec<slp_tree> *); @@ -1204,7 +1204,7 @@ class complex_fms_pattern : public complex_pattern } public: - void build (vec_info *); + void build (vec_info *) final override; static internal_fn matches (complex_operation_t op, slp_tree_to_load_perm_map_t *, slp_compat_nodes_map_t *, slp_tree *, vec<slp_tree> *); @@ -1380,7 +1380,7 @@ class complex_operations_pattern : public complex_pattern } public: - void build (vec_info *); + void build (vec_info *) final override; static internal_fn matches (complex_operation_t op, slp_tree_to_load_perm_map_t *, slp_compat_nodes_map_t *, slp_tree *, vec<slp_tree> *); @@ -1446,7 +1446,7 @@ class addsub_pattern : public vect_pattern addsub_pattern (slp_tree *node, internal_fn ifn) : vect_pattern (node, NULL, ifn) {}; - void build (vec_info *); + void build (vec_info *) final override; static vect_pattern* recognize (slp_tree_to_load_perm_map_t *, slp_compat_nodes_map_t *, diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index cdfff1a..fe9361c 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -420,8 +420,9 @@ can_duplicate_and_interleave_p (vec_info *vinfo, unsigned int count, } vec_perm_indices indices1 (sel1, 2, nelts); vec_perm_indices indices2 (sel2, 2, nelts); - if (can_vec_perm_const_p (TYPE_MODE (vector_type), indices1) - && can_vec_perm_const_p (TYPE_MODE (vector_type), indices2)) + machine_mode vmode = TYPE_MODE (vector_type); + if (can_vec_perm_const_p (vmode, vmode, indices1) + && can_vec_perm_const_p (vmode, vmode, indices2)) { if (nvectors_out) *nvectors_out = nvectors; @@ -6762,7 +6763,7 @@ vect_transform_slp_perm_load (vec_info *vinfo, if (index == count && !noop_p) { indices.new_vector (mask, second_vec_index == -1 ? 1 : 2, nunits); - if (!can_vec_perm_const_p (mode, indices)) + if (!can_vec_perm_const_p (mode, mode, indices)) { if (dump_enabled_p ()) { @@ -7122,8 +7123,9 @@ vectorizable_slp_permutation (vec_info *vinfo, gimple_stmt_iterator *gsi, { indices.new_vector (mask, second_vec.first == -1U ? 1 : 2, nunits); bool identity_p = indices.series_p (0, 1, 0, 1); + machine_mode vmode = TYPE_MODE (vectype); if (!identity_p - && !can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + && !can_vec_perm_const_p (vmode, vmode, indices)) { if (dump_enabled_p ()) { diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 8327e9d..346d8ce 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -2016,7 +2016,8 @@ perm_mask_for_reverse (tree vectype) sel.quick_push (nunits - 1 - i); vec_perm_indices indices (sel, 1, nunits); - if (!can_vec_perm_const_p (TYPE_MODE (vectype), indices)) + if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype), + indices)) return NULL_TREE; return vect_gen_perm_mask_checked (vectype, indices); } @@ -3168,7 +3169,8 @@ vectorizable_bswap (vec_info *vinfo, elts.quick_push ((i + 1) * word_bytes - j - 1); vec_perm_indices indices (elts, 1, num_bytes); - if (!can_vec_perm_const_p (TYPE_MODE (char_vectype), indices)) + machine_mode vmode = TYPE_MODE (char_vectype); + if (!can_vec_perm_const_p (vmode, vmode, indices)) return false; if (! vec_stmt) @@ -6712,7 +6714,7 @@ scan_store_can_perm_p (tree vectype, tree init, sel[j] = nunits + k; } vec_perm_indices indices (sel, i == units_log2 ? 1 : 2, nunits); - if (!can_vec_perm_const_p (vec_mode, indices)) + if (!can_vec_perm_const_p (vec_mode, vec_mode, indices)) { if (i == units_log2) return -1; @@ -8582,7 +8584,8 @@ vect_gen_perm_mask_any (tree vectype, const vec_perm_indices &sel) tree vect_gen_perm_mask_checked (tree vectype, const vec_perm_indices &sel) { - gcc_assert (can_vec_perm_const_p (TYPE_MODE (vectype), sel)); + machine_mode vmode = TYPE_MODE (vectype); + gcc_assert (can_vec_perm_const_p (vmode, vmode, sel)); return vect_gen_perm_mask_any (vectype, sel); } diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 0784d65..62ae5a9 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -4304,7 +4304,7 @@ public: m_pta->enter (bb); for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - m_ranger->register_side_effects (gsi.phi ()); + m_ranger->register_inferred_ranges (gsi.phi ()); } void post_fold_bb (basic_block bb) override @@ -4322,7 +4322,7 @@ public: bool ret = m_simplifier.simplify (gsi); if (!ret) ret = m_ranger->fold_stmt (gsi, follow_single_use_edges); - m_ranger->register_side_effects (gsi_stmt (*gsi)); + m_ranger->register_inferred_ranges (gsi_stmt (*gsi)); return ret; } diff --git a/gcc/tree.cc b/gcc/tree.cc index df441c6..2bfb674 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -280,7 +280,7 @@ unsigned const char omp_clause_num_ops[] = 1, /* OMP_CLAUSE_DEPEND */ 1, /* OMP_CLAUSE_NONTEMPORAL */ 1, /* OMP_CLAUSE_UNIFORM */ - 1, /* OMP_CLAUSE_TO_DECLARE */ + 1, /* OMP_CLAUSE_ENTER */ 1, /* OMP_CLAUSE_LINK */ 1, /* OMP_CLAUSE_DETACH */ 1, /* OMP_CLAUSE_USE_DEVICE_PTR */ @@ -370,7 +370,7 @@ const char * const omp_clause_code_name[] = "depend", "nontemporal", "uniform", - "to", + "enter", "link", "detach", "use_device_ptr", @@ -1925,6 +1925,10 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_BIND_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_BIND)->omp_clause.subcode.bind_kind) +/* True if ENTER clause is spelled as TO. */ +#define OMP_CLAUSE_ENTER_TO(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ENTER)->base.public_flag) + #define OMP_CLAUSE_TILE_LIST(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_TILE), 0) #define OMP_CLAUSE_TILE_ITERVAR(NODE) \ |