diff options
Diffstat (limited to 'gcc')
723 files changed, 35773 insertions, 7768 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fec8c7a..d975768 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,463 @@ +2025-08-05 H.J. Lu <hjl.tools@gmail.com> + + PR target/121410 + * config/i386/i386-expand.cc (ix86_expand_set_or_cpymem): Use + STORE_MAX_PIECES to get the widest vector mode in vector loop + for memset. + +2025-08-05 Georg-Johann Lay <avr@gjlay.de> + + * config/avr/avr.cc (avr_rtx_costs_1) [SIGN_EXTEND]: Adjust cost. + * config/avr/avr.md (*sext.ashift<QIPSI:mode><HISI:mode>2): New + insn and a cc split. + +2025-08-05 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121306 + * config/i386/predicates.md (extract_operator): Replace with... + (extract_high_operator): ...this new predicate. + * config/i386/i386.md (*cmpqi_ext<mode>_1, *cmpqi_ext<mode>_2) + (*cmpqi_ext<mode>_3, *cmpqi_ext<mode>_4, *movstrictqi_ext<mode>_1) + (*extzv<mode>, *insvqi_2, *extendqi<SWI24:mode>_ext_1) + (*addqi_ext<mode>_1_slp, *addqi_ext<mode>_1_slp, *addqi_ext<mode>_0) + (*addqi_ext2<mode>_0, *addqi_ext<mode>_1, *<insn>qi_ext<mode>_2) + (*subqi_ext<mode>_1_slp, *subqi_ext<mode>_2_slp, *subqi_ext<mode>_0) + (*subqi_ext2<mode>_0, *subqi_ext<mode>_1, *testqi_ext<mode>_1) + (*testqi_ext<mode>_2, *<code>qi_ext<mode>_1_slp) + (*<code>qi_ext<mode>_2_slp. *<code>qi_ext<mode>_0) + (*<code>qi_ext2<mode>_0, *<code>qi_ext<mode>_1) + (*<code>qi_ext<mode>_1_cc, *<code>qi_ext<mode>_1_cc) + (*<code>qi_ext<mode>_2, *<code>qi_ext<mode>_3, *negqi_ext<mode>_1) + (*one_cmplqi_ext<mode>_1, *ashlqi_ext<mode>_1, *<insn>qi_ext<mode>_1) + (define_peephole2): Replace uses of extract_operator with + extract_high_operator, matching only the first operand. + Use zero_extract rather than match_op_dup when splitting. + +2025-08-05 Richard Biener <rguenther@suse.de> + + * tree-vectorizer.h (vect_relevant::hybrid): Remove. + * tree-vect-loop.cc (vect_analyze_loop_2): Do not call + vect_detect_hybrid_slp. + * tree-vect-slp.cc (maybe_push_to_hybrid_worklist): Remove. + (vect_detect_hybrid_slp): Likewise. + +2025-08-05 Georg-Johann Lay <avr@gjlay.de> + + PR target/121359 + * config/avr/avr.h: Remove -mlra and remains of reload. + * config/avr/avr.cc: Same. + * config/avr/avr.md: Same. + * config/avr/avr-log.cc: Same. + * config/avr/avr-protos.h: Same. + * config/avr/avr.opt: Same. + * config/avr/avr.opt.urls: Same. + +2025-08-05 H.J. Lu <hjl.tools@gmail.com> + + PR target/121306 + * config/i386/i386.md (*one_cmplqi_ext<mode>_1): Updated to + support the new pattern. + +2025-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121395 + * tree-vectorizer.h (_loop_vec_info::alternate_defs): New member. + (LOOP_VINFO_ALTERNATE_DEFS): New. + * tree-vect-stmts.cc (vect_stmt_relevant_p): Populate it. + (vectorizable_simd_clone_call): Do not register a SLP def + when there is none. + * tree-vect-slp.cc (vect_build_slp_tree_1): Allow a NULL + vectype when there's no LHS. Allow all calls w/o LHS. + (vect_analyze_slp): Process LOOP_VINFO_ALTERNATE_DEFS as + SLP graph entries. + (vect_make_slp_decision): Handle a NULL SLP_TREE_VECTYPE. + (vect_slp_analyze_node_operations_1): Likewise. + (vect_schedule_slp_node): Likewise. + +2025-08-05 Richard Biener <rguenther@suse.de> + + * tree-vectorizer.h (enum slp_vect_type): Rename loop_vect + to not_vect, clarify docs. + (HYBRID_SLP_STMT): Remove. + * tree-vectorizer.cc (vec_info::new_stmt_vec_info): Adjust. + * tree-vect-loop.cc (vect_analyze_loop_2): Likewise. + +2025-08-05 Richard Biener <rguenther@suse.de> + + * tree-vect-data-refs.cc (vect_get_data_access_cost): Use + ncopies == 1. + * tree-vect-slp.cc (vect_remove_slp_scalar_calls): Remove + hybrid/loop SLP skip. + * tree-vect-stmts.cc (vectorizable_store): Remove pure SLP assert. + +2025-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121382 + * tree-ssa-loop-ivopts.cc (create_new_iv): Rewrite the IV + step to defined form. + +2025-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121370 + * tree-scalar-evolution.cc (scev_dfs::add_to_evolution_1): + Avoid UB integer overflow in accumulating CHREC_RIGHT. + +2025-08-05 Yang Yujie <yangyujie@loongson.cn> + + * expr.cc (expand_expr_real_1): Do not call + reduce_to_bit_field_precision if the target assumes the _BitInt + results to be already extended. + (EXTEND_BITINT): Same. + * expr.h (bitint_extended): Declare the cache variable. + * function.cc (prepare_function_start): Initialize it. + +2025-08-05 Yang Yujie <yangyujie@loongson.cn> + + * explow.cc (promote_function_mode): Add a case for + small/medium _BitInts. + (promote_mode): Same. + +2025-08-05 Gerald Pfeifer <gerald@pfeifer.com> + + PR target/69374 + * doc/install.texi (Configuration): Mark up atexit as code. + +2025-08-05 Pan Li <pan2.li@intel.com> + + * config/riscv/riscv.cc (riscv_expand_xmode_usmul): Take + umulhu for high bits mul result. + +2025-08-04 Hans-Peter Nilsson <hp@bitrange.com> + + * defaults.h (MAX_FIXED_MODE_SIZE): Default to 2 * BITS_PER_WORD + for larger-than-32-bitters. + * doc/tm.texi.in (MAX_FIXED_MODE_SIZE): Adjust accordingly. Tweak + wording. + * doc/tm.texi: Regenerate. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + * dump-context.h: Convert "enum optinfo_item_kind" into + "enum class kind" within class optinfo_item. + * dumpfile.cc: Likewise. Use "auto" in a few places. + Convert "enum optinfo_kind" to "enum class kind" within + class optinfo. + * opt-problem.cc: Likewise. + * optinfo-emit-json.cc: Likewise. + * optinfo.cc: Likewise. + * optinfo.h: Likewise. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + PR diagnostics/116253 + * diagnostics/context.cc (context::set_nesting_level): New. + * diagnostics/context.h (context::set_nesting_level): New decl. + * doc/libgdiagnostics/topics/compatibility.rst + (LIBGDIAGNOSTICS_ABI_5): New. + * doc/libgdiagnostics/topics/physical-locations.rst + (diagnostic_manager_set_debug_physical_locations): New. + * libgdiagnostics++.h (manager::set_debug_physical_locations): + New. + * libgdiagnostics-private.h + (private_diagnostic_set_nesting_level): New decl. + * libgdiagnostics.cc (diagnostic_manager::diagnostic_manager): + Initialize m_debug_physical_locations. + (diagnostic_manager::new_location_from_file_and_line): Add debug + printing. + (diagnostic_manager::new_location_from_file_line_column): + Likewise. + (diagnostic_manager::new_location_from_range): Likewise. + (diagnostic_manager::set_debug_physical_locations): New. + (diagnostic_manager::ensure_linemap_for_file_and_line): Avoid + redundant calls to linemap_add. + (diagnostic_manager::new_location): Add debug printing. + (diagnostic_manager::m_debug_physical_locations): New field. + (diagnostic::diagnostic): Initialize m_nesting_level. + (diagnostic::get_nesting_level): New accessor. + (diagnostic::set_nesting_level): New. + (diagnostic::m_nesting_level): New field. + (diagnostic_manager::emit_va): Set and reset the nesting level + of the context from that of the diagnostic. + (diagnostic_manager_set_debug_physical_locations): New. + (private_diagnostic_set_nesting_level): New. + * libgdiagnostics.h + (diagnostic_manager_set_debug_physical_locations): New decl. + * libgdiagnostics.map (LIBGDIAGNOSTICS_ABI_5): New. + * libsarifreplay.cc (sarif_replayer::handle_result_obj): Support + the "nestingLevel" property. + * libsarifreplay.h (replay_options::m_debug_physical_locations): + New field. + * sarif-replay.cc: Add -fdebug-physical-locations. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + PR diagnostics/116792 + * diagnostics/html-sink.cc + (html_builder::make_element_for_diagnostic): Don't add the + metadata element if it's empty. + (html_builder::make_element_for_metadata): Return null rather than + an empty element. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + * diagnostics/context.h: Move struct counters to its own header + and include it. + * diagnostics/counters.h: New file, from the above. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + * diagnostics/context.h: Split struct source_printing_options out + into "diagnostics/source-printing-options.h" and include it. + * diagnostics/source-printing-options.h: New file, from the above. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + * diagnostics/context.cc: Update for renaming of option_manager to + option_id_manager and of context::m_option_mgr to + context::m_option_id_mgr. + * diagnostics/context.h: Likewise, moving class declaration to a + new diagnostics/option-id-manager.h. + * diagnostics/lazy-paths.cc: Likewise. + * diagnostics/option-id-manager.h: New file, from material in + diagnostics/context.h. + * lto-wrapper.cc: Update for renaming of option_manager to + option_id_manager. + * opts-common.cc: Likewise. + * opts-diagnostic.h: Likewise. + * opts.cc: Likewise. + * toplev.cc: Likewise. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + * diagnostics/buffering.h: Update comment to refer to output sinks + rather than output formats. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + * gimple-warn-recursion.cc (pass_warn_recursion::execute): Add + missing auto_diagnostic_group. + +2025-08-04 Konstantinos Eleftheriou <konstantinos.eleftheriou@vrull.eu> + + PR rtl-optimization/121303 + * avoid-store-forwarding.cc (is_store_forwarding): Add check + for `off_val` in `is_store_forwarding`. + +2025-08-04 Richard Biener <rguenther@suse.de> + + * tree-vect-slp.cc (vect_analyze_slp): When analyzing a loop + and slp instance discovery fails, immediately fail the whole + process. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve-builtins.cc + (function_expander::expand): Assert that the return value + has an appropriate mode. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-protos.h + (aarch64_convert_sve_data_to_pred): Remove the mode argument. + * config/aarch64/aarch64.cc + (aarch64_sve_emit_int_cmp): Allow PRED_MODE to be VNx16BI or + the natural predicate mode for the data mode. + (aarch64_convert_sve_data_to_pred): Remove the mode argument + and instead always create a VNx16BI result. + (aarch64_expand_sve_const_pred): Update call accordingly. + * config/aarch64/aarch64-sve-builtins-base.cc + (svdupq_impl::expand): Likewise, ensuring that the result + has mode VNx16BI. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-protos.h + (aarch64_emit_sve_pred_vec_duplicate): Declare. + * config/aarch64/aarch64.cc + (aarch64_emit_sve_pred_vec_duplicate): New function. + * config/aarch64/aarch64-sve.md (vec_duplicate<PRED_ALL:mode>): Use it. + * config/aarch64/aarch64-sve-builtins-base.cc + (svdup_impl::expand): Handle boolean values specially. Check for + constants and fall back on aarch64_emit_sve_pred_vec_duplicate + for the variable case, ensuring that the result has mode VNx16BI. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/iterators.md (PNEXT_ONLY): New int iterator. + * config/aarch64/aarch64-sve.md + (@aarch64_sve_<sve_pred_op><mode>): Restrict SVE_PITER pattern + to VNx16BI_ONLY. + (@aarch64_sve_<sve_pred_op><mode>): New PNEXT_ONLY pattern for + PRED_HSD. + (*aarch64_sve_<sve_pred_op><mode>): Likewise. + (*aarch64_sve_<sve_pred_op><mode>_cc): Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve2.md (@aarch64_pred_<sve_int_op><mode>): + Split SVE2_MATCH pattern into a VNx16QI_ONLY define_ins and a + VNx8HI_ONLY define_expand. Use a VNx16BI destination for the latter. + (*aarch64_pred_<sve_int_op><mode>): New SVE2_MATCH pattern for + VNx8HI_ONLY. + (*aarch64_pred_<sve_int_op><mode>_cc): Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md (@aarch64_pred_fac<cmp_op><mode>): + Replace with... + (@aarch64_pred_fac<cmp_op><mode>_acle): ...this new expander. + (*aarch64_pred_fac<cmp_op><mode>_strict_acle): New pattern. + * config/aarch64/aarch64-sve-builtins-base.cc + (svac_impl::expand): Update accordingly. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md (@aarch64_pred_fcm<cmp_op><mode>_acle) + (*aarch64_pred_fcm<cmp_op><mode>_acle, @aarch64_pred_fcmuo<mode>_acle) + (*aarch64_pred_fcmuo<mode>_acle): New patterns. + * config/aarch64/aarch64-sve-builtins-base.cc + (svcmp_impl::expand, svcmpuo_impl::expand): Use them. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md (@aarch64_pred_cmp<cmp_op><mode>_wide): + Split into VNx16QI_ONLY and SVE_FULL_HSI patterns. Use VNx16BI + results for both. + (*aarch64_pred_cmp<cmp_op><mode>_wide): New pattern. + (*aarch64_pred_cmp<cmp_op><mode>_wide_cc): Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md + (*aarch64_pred_cmp<cmp_op><mode>_wide_cc): Turn into a + define_insn_and_rewrite and rewrite the governing predicate + of the comparison so that it is identical to the PTEST's. + (*aarch64_pred_cmp<cmp_op><mode>_wide_ptest): Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md (@aarch64_pred_cmp<cmp_op><mode>_wide) + (*aarch64_pred_cmp<cmp_op><mode>_wide_cc): Use <VPRED> instead of + VNx16BI for the governing predicate. + (*aarch64_pred_cmp<cmp_op><mode>_wide_ptest): Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md (@aarch64_pred_cmp<cmp_op><mode>_acle) + (*aarch64_pred_cmp<cmp_op><mode>_acle, *cmp<cmp_op><mode>_acle_cc) + (*cmp<cmp_op><mode>_acle_and): New patterns that yield VNx16BI + results for all element types. + * config/aarch64/aarch64-sve-builtins-base.cc + (svcmp_impl::expand): Use them. + (svcmp_wide_impl::expand): Likewise when implementing an svcmp_wide + against an in-range constant. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-sve.md (@aarch64_sve_punpk<perm_hilo>_acle) + (*aarch64_sve_punpk<perm_hilo>_acle): New patterns. + * config/aarch64/aarch64-sve-builtins-base.cc + (svunpk_impl::expand): Use them for boolean svunpk*. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121294 + * config/aarch64/aarch64.md (UNSPEC_REV_PRED): New unspec. + * config/aarch64/aarch64-sve.md (@aarch64_sve_rev<mode>_acle) + (*aarch64_sve_rev<mode>_acle): New patterns. + * config/aarch64/aarch64-sve-builtins-base.cc + (svrev_impl::expand): Use the new patterns for boolean svrev. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121294 + * config/aarch64/iterators.md (UNSPEC_TRN1_CONV): Delete. + (UNSPEC_PERMUTE_PRED): New unspec. + * config/aarch64/aarch64-sve.md (@aarch64_sve_trn1_conv<mode>): + Replace with... + (@aarch64_sve_<perm_insn><mode>_acle) + (*aarch64_sve_<perm_insn><mode>_acle): ...these new patterns. + * config/aarch64/aarch64.cc (aarch64_expand_sve_const_pred_trn): + Update accordingly. + * config/aarch64/aarch64-sve-builtins-functions.h + (binary_permute::expand): Use the new _acle patterns for + predicate operations. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR testsuite/121118 + * config/aarch64/iterators.md (VNx16BI_ONLY): New mode iterator. + * config/aarch64/predicates.md (aarch64_ptrue_all_operand): New + predicate. + * config/aarch64/aarch64-sve.md + (@aarch64_sve_while_<while_optab_cmp><GPI:mode><VNx16BI_ONLY:mode>_acle) + (@aarch64_sve_while_<while_optab_cmp><GPI:mode><PRED_HSD:mode>_acle) + (*aarch64_sve_while_<while_optab_cmp><GPI:mode><PRED_HSD:mode>_acle) + (*while_<while_optab_cmp><GPI:mode><PRED_HSD:mode>_acle_cc): New + patterns. + * config/aarch64/aarch64-sve-builtins-functions.h + (while_comparison::expand): Use the new _acle patterns that + always return a VNx16BI. + * config/aarch64/aarch64-sve-builtins-sve2.cc + (svwhilerw_svwhilewr_impl::expand): Likewise. + * config/aarch64/aarch64.cc + (aarch64_sve_move_pred_via_while): Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121293 + * config/aarch64/aarch64-sve-builtins-base.cc (svdupq_lane::expand): + Use aarch64_sve_reinterpret instead of subregs. Explicitly + reinterpret the result back to the required mode, rather than + leaving the caller to take a subreg. + +2025-08-04 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121362 + * tree-ssa-sccvn.cc (vn_reference_lookup_3): Generalize + aggregate copy handling. + +2025-08-04 Filip Kastl <fkastl@suse.cz> + + * doc/invoke.texi: Add remark about -options being documented + under -fdump-tree. Remove remark about -graph working only for + RTL. + +2025-08-04 H.J. Lu <hjl.tools@gmail.com> + + PR target/120941 + * config/i386/i386-features.cc (x86_cse_kind): Moved before + ix86_place_single_vector_set. + (redundant_load): Likewise. + (ix86_place_single_vector_set): Replace the last argument to the + pointer to redundant_load. For X86_CSE_VEC_DUP, don't place the + vector set outside of the loop to avoid extra spills. + (remove_redundant_vector_load): Pass load to + ix86_place_single_vector_set. + +2025-08-03 Georg-Johann Lay <avr@gjlay.de> + + * config/avr/avr.md (define_insn_and_split) [reload_completed]: + For splits that just append a (clobber (reg:CC REG_CC)) to + the pattern, use avr_add_ccclobber (curr_insn) instead of + repeating the original pattern. + * config/avr/avr-dimode.md: Same. + * config/avr/avr-fixed.md: Same. + +2025-08-03 Georg-Johann Lay <avr@gjlay.de> + + * config/avr/avr.cc (avr_add_ccclobber): New function. + * config/avr/avr-protos.h (avr_add_ccclobber): New proto. + (DONE_ADD_CCC): New define. + +2025-08-03 Richard Biener <rguenther@suse.de> + + PR tree-optimization/90242 + * tree-ssa-sccvn.cc (vn_reference_compute_hash): Use + poly_offset_int for offset accumulation. For hashing + truncate to 64 bits and also hash 64 bits. + (vn_reference_eq): Likewise. + 2025-08-02 Gerald Pfeifer <gerald@pfeifer.com> PR target/69374 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 963d4c7..cf43af9 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250803 +20250806 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 85464e3..063d6a7 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,118 @@ +2025-08-04 Viljar Indus <indus@adacore.com> + + * contracts.adb: Use Is_Ignored_In_Codegen instead of just + using Is_Ignored. + * exp_ch6.adb: Likewise. + * exp_prag.adb: Likewise. + * exp_util.adb: Likewise. + * frontend.adb: Avoid removal of ignored nodes in GNATProve_Mode. + * gnat1drv.adb: Avoid forcing Assertions_Enabled in GNATProve_Mode. + * lib-writ.adb (Write_With_File_Names): Avoid early exit + with ignored entities in GNATProve_Mode. + * lib-xref.adb: Likewise. + * opt.adb: Remove check for Assertions_Enabled. + * sem_attr.adb: Use Is_Ignored_In_Codegen instead of Is_Ignored. + * sem_ch13.adb: Likewise. Additionally always add predicates in + GNATProve_Mode. + * sem_prag.adb: Likewise. Additionally remove modifications + to applied policies in GNATProve_Mode. + * sem_util.adb (Is_Ignored_In_Codegen): New function that overrides + Is_Ignored in GNATProve_Mode and Codepeer_Mode. + (Is_Ignored_Ghost_Pragma_In_Codegen): Likewise for + Is_Ignored_Ghost_Pragma. + (Is_Ignored_Ghost_Entity_In_Codegen): Likewise for + Is_Ignored_Ghost_Entity. + (Policy_In_List): Remove overriding of policies in GNATProve_Mode. + * sem_util.ads: Add specs for new functions. + * (Predicates_Enabled): Always generate predicates in + GNATProve_Mode. + +2025-08-04 Bob Duff <duff@adacore.com> + + * treepr.adb (Print_Node_Ref): Protect against + Entity (N) being empty before calling + Compile_Time_Known_Value. + +2025-08-04 Viljar Indus <indus@adacore.com> + + * sem_prag.adb (Validate_Compile_Time_Warning_Errors): + Check if the original compile time pragma was replaced and + validate the original node instead. + +2025-08-04 Viljar Indus <indus@adacore.com> + + * sem_prag.adb (Validate_Compile_Time_Warning_Or_Error): + simplify the implementation. + +2025-08-04 Steve Baird <baird@adacore.com> + + * exp_ch6.adb (Apply_Access_Discrims_Accessibility_Check): If the + accessibility level being checked is known statically, then + statically check it against the level of the function being + returned from. + +2025-08-04 Viljar Indus <indus@adacore.com> + + * atree.adb: update references to Ghost_Mode. + * exp_ch3.adb: use a structure type to store all of the existing + ghost mode related state variables. + * exp_disp.adb: Likewise. + * exp_spark.adb: Likewise. + * exp_util.adb: Likewise. + * expander.adb: Likewise. + * freeze.adb: Likewise and replace references to existing ghost + mode variables. + * ghost.adb (Install_Ghost_Region): install the changes of + the region in to the new Ghost_Config structure. + (Restore_Ghost_Region): Use the new Ghost_Config instead. + In general replace all references to the existing ghost mode + variables with the new structure equivalent. + * ghost.ads (Restore_Ghost_Region): update the spec. + * opt.ads (Ghost_Config_Type): A new type that has two of the + previous ghost code related global variables as memembers - + Ghost_Mode and Ignored_Ghost_Region. + (Ghost_Config) New variable to store the previous Ghost_Mode and + Ignored_Ghost_Region info. + * rtsfind.adb: Replace references to existing ghost mode variables. + * sem.adb: Likewise. + * sem_ch12.adb: Likewise. + * sem_ch13.adb: Likewise. + * sem_ch3.adb: Likewise. + * sem_ch5.adb: Likewise. + * sem_ch6.adb: Likewise. + * sem_ch7.adb: Likewise. + * sem_prag.adb: Likewise. + * sem_util.adb: Likewise. + +2025-08-04 Steve Baird <baird@adacore.com> + + * freeze.adb (Freeze_Profile): Do not emit a warning stating that + a formal parameter's size is 8 if the parameter's size is not 8. + +2025-08-04 Viljar Indus <indus@adacore.com> + + * table.adb (Max): Move variable to the body and initialize + it with the same value as in the Init function. + * table.ads (Max): Likewise. + +2025-08-04 Bob Duff <duff@adacore.com> + + * par.adb: Move and rewrite some comments. + (Util): Shared code and comments for dealing with + defining_identifier_lists. + * par-util.adb (Append): Shared code for appending + one identifier onto Defining_Identifiers. + (P_Def_Ids): Shared code for parsing a defining_identifier_list. + Unfortunately, this is not used in all cases, because some of + them mix in sophisticated error recovery, which we do not + modify here. + * par-ch12.adb (P_Formal_Object_Declarations): + Use Defining_Identifiers and related code. + * par-ch3.adb (P_Identifier_Declarations): Likewise. + (P_Known_Discriminant_Part_Opt): Likewise. + (P_Component_Items): Likewise. + * par-ch6.adb (P_Formal_Part): Likewise. + 2025-07-31 Eric Botcazou <ebotcazou@gcc.gnu.org> Revert: diff --git a/gcc/ada/atree.adb b/gcc/ada/atree.adb index 20ca189..0ff3d6e 100644 --- a/gcc/ada/atree.adb +++ b/gcc/ada/atree.adb @@ -1802,12 +1802,12 @@ package body Atree is -- The Ghost node is created within a Ghost region - if Ghost_Mode = Check then + if Ghost_Config.Ghost_Mode = Check then if Nkind (N) in N_Entity then Set_Is_Checked_Ghost_Entity (N); end if; - elsif Ghost_Mode = Ignore then + elsif Ghost_Config.Ghost_Mode = Ignore then if Nkind (N) in N_Entity then Set_Is_Ignored_Ghost_Entity (N); end if; diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb index 70e9487..7e4e4a2 100644 --- a/gcc/ada/contracts.adb +++ b/gcc/ada/contracts.adb @@ -2714,10 +2714,11 @@ package body Contracts is procedure Append_Enabled_Item (Item : Node_Id; List : in out List_Id) is begin - -- Do not chain ignored or disabled pragmas + -- Do not chain ignored or disabled pragmas. Note that disabled + -- pragmas are also considered ignored. if Nkind (Item) = N_Pragma - and then (Is_Ignored (Item) or else Is_Disabled (Item)) + and then Is_Ignored_In_Codegen (Item) then null; diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index 6cf7c9c..00b3aae 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -9601,8 +9601,7 @@ package body Exp_Ch3 is Def_Id : constant Entity_Id := Entity (N); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Result : Boolean := False; @@ -9956,13 +9955,13 @@ package body Exp_Ch3 is end if; end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); return Result; exception when RE_Not_Available => - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); return False; end Freeze_Type; diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index eb7422c..e877469 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -921,7 +921,8 @@ package body Exp_Ch6 is -- in accessibility.adb (which can cause the extra formal parameter -- needed for the check(s) generated here to be missing in the case -- of a tagged result type); this is a workaround and can - -- prevent generation of a required check. + -- prevent generation of a required check (or even a required + -- legality check - see "statically too deep" check below). if No (Extra_Accessibility_Of_Result (Func)) then return; @@ -969,6 +970,15 @@ package body Exp_Ch6 is Accessibility_Level (Discr_Exp, Level => Dynamic_Level); Analyze (Discrim_Level); + if Nkind (Discrim_Level) = N_Integer_Literal + and then Intval (Discrim_Level) > Scope_Depth (Func) + then + Error_Msg_N + ("level of type of access discriminant value of " + & "return expression is statically too deep", + Enclosing_Declaration_Or_Statement (Exp)); + end if; + Insert_Action (Exp, Make_Raise_Program_Error (Loc, Condition => @@ -8089,7 +8099,7 @@ package body Exp_Ch6 is Get_Class_Wide_Pragma (Id, Pragma_Precondition); begin - if No (Prag) or else Is_Ignored (Prag) then + if No (Prag) or else Is_Ignored_In_Codegen (Prag) then return; end if; diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb index 619ac40..1c09e20 100644 --- a/gcc/ada/exp_disp.adb +++ b/gcc/ada/exp_disp.adb @@ -4593,8 +4593,7 @@ package body Exp_Disp is Name_TSD : constant Name_Id := New_External_Name (Tname, 'B', Suffix_Index => -1); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit AI : Elmt_Id; @@ -6526,7 +6525,7 @@ package body Exp_Disp is Register_CG_Node (Typ); <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); return Result; end Make_DT; diff --git a/gcc/ada/exp_prag.adb b/gcc/ada/exp_prag.adb index 340f2dc..7ec963a 100644 --- a/gcc/ada/exp_prag.adb +++ b/gcc/ada/exp_prag.adb @@ -134,7 +134,9 @@ package body Exp_Prag is -- Analyze_xxx_In_Decl_Part). The second part of the analysis will -- not happen if the pragma is rewritten. - if Assertion_Expression_Pragma (Prag_Id) and then Is_Ignored (N) then + if Assertion_Expression_Pragma (Prag_Id) + and then Is_Ignored_In_Codegen (N) + then return; -- Rewrite the pragma into a null statement when it is ignored using @@ -143,7 +145,7 @@ package body Exp_Prag is elsif Should_Ignore_Pragma_Sem (N) or else (Prag_Id = Pragma_Default_Scalar_Storage_Order - and then Ignore_Rep_Clauses) + and then Ignore_Rep_Clauses) then Rewrite (N, Make_Null_Statement (Sloc (N))); return; @@ -480,7 +482,7 @@ package body Exp_Prag is begin -- Nothing to do if pragma is ignored - if Is_Ignored (N) then + if Is_Ignored_In_Codegen (N) then return; end if; @@ -1837,7 +1839,7 @@ package body Exp_Prag is -- Do nothing if pragma is not enabled. If pragma is disabled, it has -- already been rewritten as a Null statement. - if Is_Ignored (CCs) then + if Is_Ignored_In_Codegen (CCs) then return; -- Guard against malformed contract cases @@ -2538,7 +2540,7 @@ package body Exp_Prag is -- Nothing to do when the pragma is ignored because its semantics are -- suppressed. - if Is_Ignored (IC_Prag) then + if Is_Ignored_In_Codegen (IC_Prag) then return; -- Nothing to do when the pragma or its argument are illegal because @@ -3001,7 +3003,7 @@ package body Exp_Prag is -- Also do this in CodePeer mode, because the expanded code is too -- complicated for CodePeer to analyse. - if Is_Ignored (N) + if Is_Ignored_In_Codegen (N) or else Chars (Last_Var) = Name_Structural or else CodePeer_Mode then @@ -3391,7 +3393,7 @@ package body Exp_Prag is -- Do nothing if pragma is not present or is disabled. -- Also ignore structural variants for execution. - if Is_Ignored (Prag) + if Is_Ignored_In_Codegen (Prag) or else Chars (Nlists.Last (Choices (Last_Variant))) = Name_Structural then return; diff --git a/gcc/ada/exp_spark.adb b/gcc/ada/exp_spark.adb index a75a507..0f92034 100644 --- a/gcc/ada/exp_spark.adb +++ b/gcc/ada/exp_spark.adb @@ -1128,8 +1128,7 @@ package body Exp_SPARK is Wrapper_Decl_List : List_Id; Wrapper_Body_List : List_Id := No_List; - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit begin @@ -1253,7 +1252,7 @@ package body Exp_SPARK is end if; end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end SPARK_Freeze_Type; end Exp_SPARK; diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 5a6fca0..e9ec7b7 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -1903,7 +1903,7 @@ package body Exp_Util is begin -- The DIC pragma is ignored, nothing left to do - if Is_Ignored (DIC_Prag) then + if Is_Ignored_In_Codegen (DIC_Prag) then null; -- Otherwise the DIC expression must be checked at run time. @@ -2311,8 +2311,7 @@ package body Exp_Util is Loc : constant Source_Ptr := Sloc (Typ); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit DIC_Prag : Node_Id; @@ -2558,7 +2557,7 @@ package body Exp_Util is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Build_DIC_Procedure_Body; ------------------------------------- @@ -2575,8 +2574,7 @@ package body Exp_Util is is Loc : constant Source_Ptr := Sloc (Typ); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit DIC_Prag : Node_Id; @@ -2783,7 +2781,7 @@ package body Exp_Util is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Build_DIC_Procedure_Declaration; ------------------------------------ @@ -3237,7 +3235,7 @@ package body Exp_Util is begin -- The invariant is ignored, nothing left to do - if Is_Ignored (Prag) then + if Is_Ignored_In_Codegen (Prag) then null; -- Otherwise the invariant is checked. Build a pragma Check to verify @@ -3709,8 +3707,7 @@ package body Exp_Util is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Dummy : Entity_Id; @@ -4058,7 +4055,7 @@ package body Exp_Util is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Build_Invariant_Procedure_Body; ------------------------------------------- @@ -4075,8 +4072,7 @@ package body Exp_Util is is Loc : constant Source_Ptr := Sloc (Typ); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Proc_Decl : Node_Id; @@ -4292,7 +4288,7 @@ package body Exp_Util is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Build_Invariant_Procedure_Declaration; ------------------------ @@ -10640,8 +10636,7 @@ package body Exp_Util is is Loc : constant Source_Ptr := Sloc (Expr); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Call : Node_Id; @@ -10685,7 +10680,7 @@ package body Exp_Util is Name => New_Occurrence_Of (Func_Id, Loc), Parameter_Associations => Param_Assocs); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); return Call; end Make_Predicate_Call; diff --git a/gcc/ada/expander.adb b/gcc/ada/expander.adb index 3d7b0d7..25f4950 100644 --- a/gcc/ada/expander.adb +++ b/gcc/ada/expander.adb @@ -84,8 +84,7 @@ package body Expander is -- Ghost mode. procedure Expand (N : Node_Id) is - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit begin @@ -559,7 +558,7 @@ package body Expander is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Expand; --------------------------- diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb index dbd7cf4..2ebffff 100644 --- a/gcc/ada/freeze.adb +++ b/gcc/ada/freeze.adb @@ -2878,8 +2878,7 @@ package body Freeze is is Loc : constant Source_Ptr := Sloc (N); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Atype : Entity_Id; @@ -4813,6 +4812,8 @@ package body Freeze is and then Convention (F_Type) = Convention_Ada and then not Has_Warnings_Off (F_Type) and then not Has_Size_Clause (F_Type) + and then Present (Esize (F_Type)) + and then Esize (F_Type) = 8 then Error_Msg_N ("& is an 8-bit Ada Boolean?x?", Formal); @@ -8358,12 +8359,12 @@ package body Freeze is -- and Per-Object Expressions" will suppress the insertion, and the -- freeze node will be dropped on the floor. - if Saved_GM = Ignore - and then Ghost_Mode /= Ignore - and then Present (Ignored_Ghost_Region) + if Saved_Ghost_Config.Ghost_Mode = Ignore + and then Ghost_Config.Ghost_Mode /= Ignore + and then Present (Ghost_Config.Ignored_Ghost_Region) then Insert_Actions - (Assoc_Node => Ignored_Ghost_Region, + (Assoc_Node => Ghost_Config.Ignored_Ghost_Region, Ins_Actions => Result, Spec_Expr_OK => True); @@ -8371,7 +8372,7 @@ package body Freeze is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); return Result; end Freeze_Entity; diff --git a/gcc/ada/frontend.adb b/gcc/ada/frontend.adb index 564f153..92bc3c6 100644 --- a/gcc/ada/frontend.adb +++ b/gcc/ada/frontend.adb @@ -477,7 +477,7 @@ begin -- executable. This action must be performed very late because it -- heavily alters the tree. - if Operating_Mode = Generate_Code or else GNATprove_Mode then + if Operating_Mode = Generate_Code and not CodePeer_Mode then Remove_Ignored_Ghost_Code; end if; diff --git a/gcc/ada/ghost.adb b/gcc/ada/ghost.adb index 6f648f2..f9c2853 100644 --- a/gcc/ada/ghost.adb +++ b/gcc/ada/ghost.adb @@ -447,7 +447,7 @@ package body Ghost is -- The context is Ghost when it appears within a Ghost package or -- subprogram. - if Ghost_Mode > None then + if Ghost_Config.Ghost_Mode > None then return True; -- Routine Expand_Record_Extension creates a parent subtype without @@ -719,7 +719,7 @@ package body Ghost is -- The context is ghost when it appears within a Ghost package or -- subprogram. - if Ghost_Mode > None then + if Ghost_Config.Ghost_Mode > None then return; -- The context is ghost if Formal is explicitly marked as ghost @@ -1130,22 +1130,22 @@ package body Ghost is -- The context is already within an ignored Ghost region. Maintain the -- start of the outermost ignored Ghost region. - if Present (Ignored_Ghost_Region) then + if Present (Ghost_Config.Ignored_Ghost_Region) then null; -- The current region is the outermost ignored Ghost region. Save its -- starting node. elsif Present (N) and then Mode = Ignore then - Ignored_Ghost_Region := N; + Ghost_Config.Ignored_Ghost_Region := N; -- Otherwise the current region is not ignored, nothing to save else - Ignored_Ghost_Region := Empty; + Ghost_Config.Ignored_Ghost_Region := Empty; end if; - Ghost_Mode := Mode; + Ghost_Config.Ghost_Mode := Mode; end Install_Ghost_Region; procedure Install_Ghost_Region (Mode : Name_Id; N : Node_Id) is @@ -1504,10 +1504,10 @@ package body Ghost is -- A body declared within a Ghost region is automatically Ghost -- (SPARK RM 6.9(2)). - elsif Ghost_Mode = Check then + elsif Ghost_Config.Ghost_Mode = Check then Policy := Name_Check; - elsif Ghost_Mode = Ignore then + elsif Ghost_Config.Ghost_Mode = Ignore then Policy := Name_Ignore; -- Inherit the "ghostness" of the previous declaration when the body @@ -1553,10 +1553,10 @@ package body Ghost is -- A completion elaborated in a Ghost region is automatically Ghost -- (SPARK RM 6.9(2)). - if Ghost_Mode = Check then + if Ghost_Config.Ghost_Mode = Check then Policy := Name_Check; - elsif Ghost_Mode = Ignore then + elsif Ghost_Config.Ghost_Mode = Ignore then Policy := Name_Ignore; -- The completion becomes Ghost when its initial declaration is also @@ -1603,10 +1603,10 @@ package body Ghost is -- A declaration elaborated in a Ghost region is automatically Ghost -- (SPARK RM 6.9(2)). - elsif Ghost_Mode = Check then + elsif Ghost_Config.Ghost_Mode = Check then Policy := Name_Check; - elsif Ghost_Mode = Ignore then + elsif Ghost_Config.Ghost_Mode = Ignore then Policy := Name_Ignore; -- A child package or subprogram declaration becomes Ghost when its @@ -1698,10 +1698,10 @@ package body Ghost is -- An instantiation declaration within a Ghost region is automatically -- Ghost (SPARK RM 6.9(2)). - elsif Ghost_Mode = Check then + elsif Ghost_Config.Ghost_Mode = Check then Policy := Name_Check; - elsif Ghost_Mode = Ignore then + elsif Ghost_Config.Ghost_Mode = Ignore then Policy := Name_Ignore; -- Inherit the "ghostness" of the generic unit, but the current Ghost @@ -2018,10 +2018,9 @@ package body Ghost is -- Restore_Ghost_Region -- -------------------------- - procedure Restore_Ghost_Region (Mode : Ghost_Mode_Type; N : Node_Id) is + procedure Restore_Ghost_Region (Config : Ghost_Config_Type) is begin - Ghost_Mode := Mode; - Ignored_Ghost_Region := N; + Ghost_Config := Config; end Restore_Ghost_Region; -------------------- diff --git a/gcc/ada/ghost.ads b/gcc/ada/ghost.ads index 3863e50..62c809c 100644 --- a/gcc/ada/ghost.ads +++ b/gcc/ada/ghost.ads @@ -243,7 +243,7 @@ package Ghost is -- WARNING: this is a separate front end pass, care should be taken to keep -- it optimized. - procedure Restore_Ghost_Region (Mode : Ghost_Mode_Type; N : Node_Id); + procedure Restore_Ghost_Region (Config : Ghost_Config_Type); pragma Inline (Restore_Ghost_Region); -- Restore a Ghost region to a previous state described by mode Mode and -- ignored region start node N. This routine must be used in conjunction diff --git a/gcc/ada/gnat1drv.adb b/gcc/ada/gnat1drv.adb index 52063c8..ee2c329 100644 --- a/gcc/ada/gnat1drv.adb +++ b/gcc/ada/gnat1drv.adb @@ -503,11 +503,6 @@ procedure Gnat1drv is Operating_Mode := Check_Semantics; - -- Enable assertions, since they give valuable extra information for - -- formal verification. - - Assertions_Enabled := True; - -- Disable validity checks, since it generates code raising -- exceptions for invalid data, which confuses GNATprove. Invalid -- data is directly detected by GNATprove's flow analysis. diff --git a/gcc/ada/lib-writ.adb b/gcc/ada/lib-writ.adb index b7a7f12..fb7c416 100644 --- a/gcc/ada/lib-writ.adb +++ b/gcc/ada/lib-writ.adb @@ -905,7 +905,7 @@ package body Lib.Writ is -- Do not generate a with line for an ignored Ghost unit because -- the unit does not have an ALI file. - if Is_Ignored_Ghost_Entity (Cunit_Entity (Unum)) then + if Is_Ignored_Ghost_Entity_In_Codegen (Cunit_Entity (Unum)) then goto Next_With_Line; end if; diff --git a/gcc/ada/lib-xref.adb b/gcc/ada/lib-xref.adb index 145d314..aa9ae57 100644 --- a/gcc/ada/lib-xref.adb +++ b/gcc/ada/lib-xref.adb @@ -1729,7 +1729,7 @@ package body Lib.Xref is -- entity because neither the entity nor its references will -- appear in the final tree. - if Is_Ignored_Ghost_Entity (Ent) then + if Is_Ignored_Ghost_Entity_In_Codegen (Ent) then goto Orphan_Continue; end if; @@ -2190,7 +2190,7 @@ package body Lib.Xref is -- entity because neither the entity nor its references will -- appear in the final tree. - if Is_Ignored_Ghost_Entity (Ent) then + if Is_Ignored_Ghost_Entity_In_Codegen (Ent) then goto Continue; end if; diff --git a/gcc/ada/opt.adb b/gcc/ada/opt.adb index d2291a9..bd74215 100644 --- a/gcc/ada/opt.adb +++ b/gcc/ada/opt.adb @@ -204,14 +204,7 @@ package body Opt is SPARK_Mode_Pragma := SPARK_Mode_Pragma_Config; else - -- In GNATprove mode assertions should be always enabled, even - -- when analysing internal units. - - if GNATprove_Mode then - pragma Assert (Assertions_Enabled); - null; - - elsif GNAT_Mode_Config then + if GNAT_Mode_Config then Assertions_Enabled := Assertions_Enabled_Config; else Assertions_Enabled := False; diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads index e595b08..73f9fe8 100644 --- a/gcc/ada/opt.ads +++ b/gcc/ada/opt.ads @@ -746,9 +746,20 @@ package Opt is -- Possible legal modes that can be set by aspect/pragma Ghost as well as -- value None, which indicates that no such aspect/pragma applies. - Ghost_Mode : Ghost_Mode_Type := None; + type Ghost_Config_Type is record + Ghost_Mode : Ghost_Mode_Type := None; + -- The current Ghost mode in effect + + Ignored_Ghost_Region : Node_Id := Empty; + -- The start of the current ignored Ghost region. This value must always + -- reflect the starting node of the outermost ignored Ghost region. If a + -- nested ignored Ghost region is entered, the value must remain + -- unchanged. + end record; + + Ghost_Config : Ghost_Config_Type; -- GNAT - -- The current Ghost mode in effect + -- All relevant Ghost mode settings Global_Discard_Names : Boolean := False; -- GNAT, GNATBIND @@ -810,12 +821,6 @@ package Opt is -- use of -gnateu, causing subsequent unrecognized switches to result in -- a warning rather than an error. - Ignored_Ghost_Region : Node_Id := Empty; - -- GNAT - -- The start of the current ignored Ghost region. This value must always - -- reflect the starting node of the outermost ignored Ghost region. If a - -- nested ignored Ghost region is entered, the value must remain unchanged. - Implicit_Packing : Boolean := False; -- GNAT -- If set True, then a Size attribute clause on an array is allowed to diff --git a/gcc/ada/par-ch12.adb b/gcc/ada/par-ch12.adb index b539a29..5fb6f8c 100644 --- a/gcc/ada/par-ch12.adb +++ b/gcc/ada/par-ch12.adb @@ -420,32 +420,17 @@ package body Ch12 is procedure P_Formal_Object_Declarations (Decls : List_Id) is Decl_Node : Node_Id; - Ident : Pos; Not_Null_Present : Boolean := False; - Num_Idents : Pos; Scan_State : Saved_Scan_State; - Idents : array (Pos range 1 .. 4096) of Entity_Id; - -- This array holds the list of defining identifiers. The upper bound - -- of 4096 is intended to be essentially infinite, and we do not even - -- bother to check for it being exceeded. + Def_Ids : Defining_Identifiers; + Ident : Pos; begin - Idents (1) := P_Defining_Identifier (C_Comma_Colon); - Num_Idents := 1; - while Comma_Present loop - Num_Idents := Num_Idents + 1; - Idents (Num_Idents) := P_Defining_Identifier (C_Comma_Colon); - end loop; - + P_Def_Ids (Def_Ids); T_Colon; - -- If there are multiple identifiers, we repeatedly scan the - -- type and initialization expression information by resetting - -- the scan pointer (so that we get completely separate trees - -- for each occurrence). - - if Num_Idents > 1 then + if Def_Ids.Num_Idents > 1 then Save_Scan_State (Scan_State); end if; @@ -454,7 +439,7 @@ package body Ch12 is Ident := 1; Ident_Loop : loop Decl_Node := New_Node (N_Formal_Object_Declaration, Token_Ptr); - Set_Defining_Identifier (Decl_Node, Idents (Ident)); + Set_Defining_Identifier (Decl_Node, Def_Ids.Idents (Ident)); P_Mode (Decl_Node); Not_Null_Present := P_Null_Exclusion; -- Ada 2005 (AI-423) @@ -488,13 +473,13 @@ package body Ch12 is Set_Prev_Ids (Decl_Node, True); end if; - if Ident < Num_Idents then + if Ident < Def_Ids.Num_Idents then Set_More_Ids (Decl_Node, True); end if; Append (Decl_Node, Decls); - exit Ident_Loop when Ident = Num_Idents; + exit Ident_Loop when Ident = Def_Ids.Num_Idents; Ident := Ident + 1; Restore_Scan_State (Scan_State); end loop Ident_Loop; diff --git a/gcc/ada/par-ch3.adb b/gcc/ada/par-ch3.adb index fe727d7..a685812 100644 --- a/gcc/ada/par-ch3.adb +++ b/gcc/ada/par-ch3.adb @@ -1302,19 +1302,13 @@ package body Ch3 is Ident_Sloc : Source_Ptr; Scan_State : Saved_Scan_State; List_OK : Boolean := True; - Ident : Nat; Init_Expr : Node_Id; Init_Loc : Source_Ptr; Con_Loc : Source_Ptr; Not_Null_Present : Boolean := False; - Idents : array (Int range 1 .. 4096) of Entity_Id; - -- Used to save identifiers in the identifier list. The upper bound - -- of 4096 is expected to be infinite in practice, and we do not even - -- bother to check if this upper bound is exceeded. - - Num_Idents : Nat := 1; - -- Number of identifiers stored in Idents + Def_Ids : Defining_Identifiers; + Ident : Pos; function Identifier_Starts_Statement return Boolean; -- Called with Token being an identifier that might start a declaration @@ -1389,10 +1383,9 @@ package body Ch3 is procedure No_List is begin - if Num_Idents > 1 then + if Def_Ids.Num_Idents > 1 then Error_Msg_N - ("identifier list not allowed for RENAMES", - Idents (2)); + ("identifier list not allowed for RENAMES", Def_Ids.Idents (2)); end if; List_OK := False; @@ -1443,7 +1436,7 @@ package body Ch3 is Ident_Sloc := Token_Ptr; Save_Scan_State (Scan_State); -- at first identifier - Idents (1) := P_Defining_Identifier (C_Comma_Colon); + Append (Def_Ids, P_Defining_Identifier (C_Comma_Colon)); -- If we have a colon after the identifier, then we can assume that -- this is in fact a valid identifier declaration and can steam ahead. @@ -1455,8 +1448,7 @@ package body Ch3 is elsif Token = Tok_Comma then while Comma_Present loop - Num_Idents := Num_Idents + 1; - Idents (Num_Idents) := P_Defining_Identifier (C_Comma_Colon); + Append (Def_Ids, P_Defining_Identifier (C_Comma_Colon)); end loop; Save_Scan_State (Scan_State); -- at colon @@ -1510,7 +1502,7 @@ package body Ch3 is Decl_Node := New_Node (N_Object_Renaming_Declaration, Ident_Sloc); Set_Name (Decl_Node, P_Name); - Set_Defining_Identifier (Decl_Node, Idents (1)); + Set_Defining_Identifier (Decl_Node, Def_Ids.Idents (1)); P_Aspect_Specifications (Decl_Node, Semicolon => False); @@ -1917,7 +1909,7 @@ package body Ch3 is end if; end if; - Set_Defining_Identifier (Decl_Node, Idents (Ident)); + Set_Defining_Identifier (Decl_Node, Def_Ids.Idents (Ident)); P_Aspect_Specifications (Decl_Node, Semicolon => False); -- Allow initialization expression to follow aspects (note that in @@ -1945,17 +1937,17 @@ package body Ch3 is T_Semicolon; if List_OK then - if Ident < Num_Idents then - Set_More_Ids (Decl_Node, True); - end if; - if Ident > 1 then Set_Prev_Ids (Decl_Node, True); end if; + + if Ident < Def_Ids.Num_Idents then + Set_More_Ids (Decl_Node, True); + end if; end if; Append (Decl_Node, Decls); - exit Ident_Loop when Ident = Num_Idents; + exit Ident_Loop when Ident = Def_Ids.Num_Idents; Restore_Scan_State (Scan_State); T_Colon; Ident := Ident + 1; @@ -3191,14 +3183,7 @@ package body Ch3 is Specification_List : List_Id; Ident_Sloc : Source_Ptr; Scan_State : Saved_Scan_State; - Num_Idents : Nat; Not_Null_Present : Boolean; - Ident : Nat; - - Idents : array (Int range 1 .. 4096) of Entity_Id; - -- This array holds the list of defining identifiers. The upper bound - -- of 4096 is intended to be essentially infinite, and we do not even - -- bother to check for it being exceeded. begin if Token = Tok_Left_Paren then @@ -3207,97 +3192,91 @@ package body Ch3 is P_Pragmas_Misplaced; Specification_Loop : loop + declare + Def_Ids : Defining_Identifiers; + Ident : Pos; + begin + Ident_Sloc := Token_Ptr; + P_Def_Ids (Def_Ids); - Ident_Sloc := Token_Ptr; - Idents (1) := P_Defining_Identifier (C_Comma_Colon); - Num_Idents := 1; - - while Comma_Present loop - Num_Idents := Num_Idents + 1; - Idents (Num_Idents) := P_Defining_Identifier (C_Comma_Colon); - end loop; - - -- If there are multiple identifiers, we repeatedly scan the - -- type and initialization expression information by resetting - -- the scan pointer (so that we get completely separate trees - -- for each occurrence). + if Def_Ids.Num_Idents > 1 then + Save_Scan_State (Scan_State); + end if; - if Num_Idents > 1 then - Save_Scan_State (Scan_State); - end if; + T_Colon; - T_Colon; + -- Loop through defining identifiers in list - -- Loop through defining identifiers in list + Ident := 1; + Ident_Loop : loop + Specification_Node := + New_Node (N_Discriminant_Specification, Ident_Sloc); + Set_Defining_Identifier + (Specification_Node, Def_Ids.Idents (Ident)); + Not_Null_Present := -- Ada 2005 (AI-231, AI-447) + P_Null_Exclusion (Allow_Anonymous_In_95 => True); - Ident := 1; - Ident_Loop : loop - Specification_Node := - New_Node (N_Discriminant_Specification, Ident_Sloc); - Set_Defining_Identifier (Specification_Node, Idents (Ident)); - Not_Null_Present := -- Ada 2005 (AI-231, AI-447) - P_Null_Exclusion (Allow_Anonymous_In_95 => True); + if Token = Tok_Access then + if Ada_Version = Ada_83 then + Error_Msg_SC + ("(Ada 83) access discriminant not allowed!"); + end if; - if Token = Tok_Access then - if Ada_Version = Ada_83 then - Error_Msg_SC - ("(Ada 83) access discriminant not allowed!"); - end if; + Set_Discriminant_Type + (Specification_Node, + P_Access_Definition (Not_Null_Present)); - Set_Discriminant_Type - (Specification_Node, - P_Access_Definition (Not_Null_Present)); + -- Catch ouf-of-order keywords - -- Catch ouf-of-order keywords + elsif Token = Tok_Constant then + Scan; - elsif Token = Tok_Constant then - Scan; + if Token = Tok_Access then + Error_Msg_SC -- CODEFIX + ("ACCESS must come before CONSTANT"); + Set_Discriminant_Type + (Specification_Node, + P_Access_Definition (Not_Null_Present)); - if Token = Tok_Access then - Error_Msg_SC -- CODEFIX - ("ACCESS must come before CONSTANT"); - Set_Discriminant_Type - (Specification_Node, - P_Access_Definition (Not_Null_Present)); + else + Error_Msg_SC ("misplaced CONSTANT"); + end if; else - Error_Msg_SC ("misplaced CONSTANT"); + Set_Discriminant_Type + (Specification_Node, P_Subtype_Mark); + No_Constraint; + Set_Null_Exclusion_Present -- Ada 2005 (AI-231) + (Specification_Node, Not_Null_Present); end if; - else - Set_Discriminant_Type - (Specification_Node, P_Subtype_Mark); - No_Constraint; - Set_Null_Exclusion_Present -- Ada 2005 (AI-231) - (Specification_Node, Not_Null_Present); - end if; - - Set_Expression - (Specification_Node, Init_Expr_Opt (True)); + Set_Expression + (Specification_Node, Init_Expr_Opt (True)); - if Token = Tok_With then - P_Aspect_Specifications - (Specification_Node, Semicolon => False); - end if; + if Token = Tok_With then + P_Aspect_Specifications + (Specification_Node, Semicolon => False); + end if; - if Ident > 1 then - Set_Prev_Ids (Specification_Node, True); - end if; + if Ident > 1 then + Set_Prev_Ids (Specification_Node, True); + end if; - if Ident < Num_Idents then - Set_More_Ids (Specification_Node, True); - end if; + if Ident < Def_Ids.Num_Idents then + Set_More_Ids (Specification_Node, True); + end if; - Append (Specification_Node, Specification_List); - exit Ident_Loop when Ident = Num_Idents; - Ident := Ident + 1; - Restore_Scan_State (Scan_State); - T_Colon; - end loop Ident_Loop; + Append (Specification_Node, Specification_List); + exit Ident_Loop when Ident = Def_Ids.Num_Idents; + Ident := Ident + 1; + Restore_Scan_State (Scan_State); + T_Colon; + end loop Ident_Loop; - exit Specification_Loop when Token /= Tok_Semicolon; - Scan; -- past ; - P_Pragmas_Misplaced; + exit Specification_Loop when Token /= Tok_Semicolon; + Scan; -- past ; + P_Pragmas_Misplaced; + end; end loop Specification_Loop; T_Right_Paren; @@ -3770,14 +3749,10 @@ package body Ch3 is Decl_Node : Node_Id := Empty; -- initialize to prevent warning Scan_State : Saved_Scan_State; Not_Null_Present : Boolean := False; - Num_Idents : Nat; - Ident : Nat; Ident_Sloc : Source_Ptr; - Idents : array (Int range 1 .. 4096) of Entity_Id; - -- This array holds the list of defining identifiers. The upper bound - -- of 4096 is intended to be essentially infinite, and we do not even - -- bother to check for it being exceeded. + Def_Ids : Defining_Identifiers; + Ident : Pos; begin if Token /= Tok_Identifier then @@ -3788,20 +3763,9 @@ package body Ch3 is Ident_Sloc := Token_Ptr; Check_Bad_Layout; - Idents (1) := P_Defining_Identifier (C_Comma_Colon); - Num_Idents := 1; - - while Comma_Present loop - Num_Idents := Num_Idents + 1; - Idents (Num_Idents) := P_Defining_Identifier (C_Comma_Colon); - end loop; - - -- If there are multiple identifiers, we repeatedly scan the - -- type and initialization expression information by resetting - -- the scan pointer (so that we get completely separate trees - -- for each occurrence). + P_Def_Ids (Def_Ids); - if Num_Idents > 1 then + if Def_Ids.Num_Idents > 1 then Save_Scan_State (Scan_State); end if; @@ -3817,7 +3781,7 @@ package body Ch3 is begin Decl_Node := New_Node (N_Component_Declaration, Ident_Sloc); - Set_Defining_Identifier (Decl_Node, Idents (Ident)); + Set_Defining_Identifier (Decl_Node, Def_Ids.Idents (Ident)); if Token = Tok_Constant then Error_Msg_SC ("constant component not permitted"); @@ -3876,7 +3840,7 @@ package body Ch3 is Set_Prev_Ids (Decl_Node, True); end if; - if Ident < Num_Idents then + if Ident < Def_Ids.Num_Idents then Set_More_Ids (Decl_Node, True); end if; @@ -3890,7 +3854,7 @@ package body Ch3 is end if; end; - exit Ident_Loop when Ident = Num_Idents; + exit Ident_Loop when Ident = Def_Ids.Num_Idents; Ident := Ident + 1; Restore_Scan_State (Scan_State); T_Colon; diff --git a/gcc/ada/par-ch6.adb b/gcc/ada/par-ch6.adb index 0f7765b..2465108 100644 --- a/gcc/ada/par-ch6.adb +++ b/gcc/ada/par-ch6.adb @@ -1384,20 +1384,16 @@ package body Ch6 is Specification_List : List_Id; Specification_Node : Node_Id; Scan_State : Saved_Scan_State; - Num_Idents : Nat; - Ident : Nat; Ident_Sloc : Source_Ptr; Not_Null_Present : Boolean := False; Not_Null_Sloc : Source_Ptr; - Idents : array (Int range 1 .. 4096) of Entity_Id; - -- This array holds the list of defining identifiers. The upper bound - -- of 4096 is intended to be essentially infinite, and we do not even - -- bother to check for it being exceeded. - begin Specification_List := New_List; Specification_Loop : loop + declare + Def_Ids : Defining_Identifiers; + Ident : Pos; begin if Token = Tok_Pragma then Error_Msg_SC ("pragma not allowed in formal part"); @@ -1406,8 +1402,7 @@ package body Ch6 is Ignore (Tok_Left_Paren); Ident_Sloc := Token_Ptr; - Idents (1) := P_Defining_Identifier (C_Comma_Colon); - Num_Idents := 1; + Append (Def_Ids, P_Defining_Identifier (C_Comma_Colon)); Ident_Loop : loop exit Ident_Loop when Token = Tok_Colon; @@ -1457,8 +1452,7 @@ package body Ch6 is -- Here if a comma is present, or to be assumed T_Comma; - Num_Idents := Num_Idents + 1; - Idents (Num_Idents) := P_Defining_Identifier (C_Comma_Colon); + Append (Def_Ids, P_Defining_Identifier (C_Comma_Colon)); end loop Ident_Loop; -- Fall through the loop on encountering a colon, or deciding @@ -1466,12 +1460,7 @@ package body Ch6 is T_Colon; - -- If there are multiple identifiers, we repeatedly scan the - -- type and initialization expression information by resetting - -- the scan pointer (so that we get completely separate trees - -- for each occurrence). - - if Num_Idents > 1 then + if Def_Ids.Num_Idents > 1 then Save_Scan_State (Scan_State); end if; @@ -1482,7 +1471,8 @@ package body Ch6 is Ident_List_Loop : loop Specification_Node := New_Node (N_Parameter_Specification, Ident_Sloc); - Set_Defining_Identifier (Specification_Node, Idents (Ident)); + Set_Defining_Identifier + (Specification_Node, Def_Ids.Idents (Ident)); -- Scan possible ALIASED for Ada 2012 (AI-142) @@ -1574,12 +1564,12 @@ package body Ch6 is Set_Prev_Ids (Specification_Node, True); end if; - if Ident < Num_Idents then + if Ident < Def_Ids.Num_Idents then Set_More_Ids (Specification_Node, True); end if; Append (Specification_Node, Specification_List); - exit Ident_List_Loop when Ident = Num_Idents; + exit Ident_List_Loop when Ident = Def_Ids.Num_Idents; Ident := Ident + 1; Restore_Scan_State (Scan_State); end loop Ident_List_Loop; diff --git a/gcc/ada/par-util.adb b/gcc/ada/par-util.adb index 78a76b3..6a6afd0 100644 --- a/gcc/ada/par-util.adb +++ b/gcc/ada/par-util.adb @@ -34,6 +34,22 @@ with GNAT.Spelling_Checker; use GNAT.Spelling_Checker; separate (Par) package body Util is + ------------ + -- Append -- + ------------ + + procedure Append + (Def_Ids : in out Defining_Identifiers; Def_Id : Entity_Id) + is + begin + if Def_Ids.Num_Idents >= Defining_Identifiers_Array'Last then + raise Program_Error; + end if; + + Def_Ids.Num_Idents := Def_Ids.Num_Idents + 1; + Def_Ids.Idents (Def_Ids.Num_Idents) := Def_Id; + end Append; + --------------------- -- Bad_Spelling_Of -- --------------------- @@ -691,6 +707,19 @@ package body Util is end if; end No_Constraint; + --------------- + -- P_Def_Ids -- + --------------- + + procedure P_Def_Ids (Def_Ids : out Defining_Identifiers) is + pragma Assert (Def_Ids.Num_Idents = 0); + begin + loop + Append (Def_Ids, P_Defining_Identifier (C_Comma_Colon)); + exit when not Comma_Present; + end loop; + end P_Def_Ids; + --------------------- -- Pop_Scope_Stack -- --------------------- diff --git a/gcc/ada/par.adb b/gcc/ada/par.adb index e11ec7e..99bbed2 100644 --- a/gcc/ada/par.adb +++ b/gcc/ada/par.adb @@ -227,6 +227,69 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is -- that there is a missing body, but it seems more reasonable to let the -- later semantic checking discover this. + -------------------------------------------- + -- Handling IS Used in Place of Semicolon -- + -------------------------------------------- + + -- This is a somewhat trickier situation, and we can't catch it in all + -- cases, but we do our best to detect common situations resulting from + -- a "cut and paste" operation which forgets to change the IS to semicolon. + -- Consider the following example: + + -- package body X is + -- procedure A; + -- procedure B is -- Error: IS should be semicolon + -- procedure C; + -- ... + -- procedure D is + -- begin + -- ... + -- end; + -- begin + -- ... + -- end; -- end of B? + + -- The trouble is that the section of text from PROCEDURE B through the + -- END; marked "-- end of B?" constitutes a valid procedure body, and the + -- danger is that we find out far too late that something is wrong. + + -- We have two approaches to helping to control this situation. First we + -- make every attempt to avoid swallowing the last END; if we can be sure + -- that some error will result from doing so. In particular, we won't + -- accept the END; unless it is exactly correct (in particular it must not + -- have incorrect name tokens), and we won't accept it if it is immediately + -- followed by end of file, WITH or SEPARATE (tokens that unmistakeably + -- signal the start of a compilation unit, and which therefore allow us to + -- reserve the END; for the outer level.) For more details on this aspect + -- of the handling, see package Par.Endh. + + -- If we can avoid eating up the END; then the result in the absence of + -- any additional steps would be to post a missing END referring back to + -- the subprogram with the bogus IS. Similarly, if the enclosing package + -- has no BEGIN, then the result is a missing BEGIN message, which again + -- refers back to the subprogram header. + + -- Such an error message is not too bad, but it's not ideal, because + -- the declarations following the IS have been absorbed into the wrong + -- scope. In the above case, this could result for example in a bogus + -- complaint that the body of D was missing from the package. + + -- To catch at least some of these cases, we take the following additional + -- steps. First, a subprogram body is marked as having a suspicious IS if + -- the declaration line is followed by a line that starts with a symbol + -- that can start a declaration in the same column, or to the left of the + -- column in which the FUNCTION or PROCEDURE starts (normal style is to + -- indent any declarations that really belong a subprogram). If such a + -- subprogram encounters a missing BEGIN or missing END, then we decide + -- that the IS should have been a semicolon, and the subprogram body node + -- is marked (by setting the Bad_Is_Detected flag true. Note that we do + -- not do this for library level procedures, only for nested procedures, + -- since for library level procedures, we must have a body. + + -- The processing for a declarative part checks to see if the last + -- declaration scanned is marked in this way, and if it is, the tree + -- is modified to reflect the IS being interpreted as a semicolon. + ---------------------------------------------------- -- Handling of Reserved Words Used as Identifiers -- ---------------------------------------------------- @@ -294,71 +357,6 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is C_Vertical_Bar_Arrow); -- Consider as identifier if followed by | or => - -------------------------------------------- - -- Handling IS Used in Place of Semicolon -- - -------------------------------------------- - - -- This is a somewhat trickier situation, and we can't catch it in all - -- cases, but we do our best to detect common situations resulting from - -- a "cut and paste" operation which forgets to change the IS to semicolon. - -- Consider the following example: - - -- package body X is - -- procedure A; - -- procedure B is - -- procedure C; - -- ... - -- procedure D is - -- begin - -- ... - -- end; - -- begin - -- ... - -- end; - - -- The trouble is that the section of text from PROCEDURE B through END; - -- constitutes a valid procedure body, and the danger is that we find out - -- far too late that something is wrong (indeed most compilers will behave - -- uncomfortably on the above example). - - -- We have two approaches to helping to control this situation. First we - -- make every attempt to avoid swallowing the last END; if we can be sure - -- that some error will result from doing so. In particular, we won't - -- accept the END; unless it is exactly correct (in particular it must not - -- have incorrect name tokens), and we won't accept it if it is immediately - -- followed by end of file, WITH or SEPARATE (all tokens that unmistakeably - -- signal the start of a compilation unit, and which therefore allow us to - -- reserve the END; for the outer level.) For more details on this aspect - -- of the handling, see package Par.Endh. - - -- If we can avoid eating up the END; then the result in the absence of - -- any additional steps would be to post a missing END referring back to - -- the subprogram with the bogus IS. Similarly, if the enclosing package - -- has no BEGIN, then the result is a missing BEGIN message, which again - -- refers back to the subprogram header. - - -- Such an error message is not too bad (it's already a big improvement - -- over what many parsers do), but it's not ideal, because the declarations - -- following the IS have been absorbed into the wrong scope. In the above - -- case, this could result for example in a bogus complaint that the body - -- of D was missing from the package. - - -- To catch at least some of these cases, we take the following additional - -- steps. First, a subprogram body is marked as having a suspicious IS if - -- the declaration line is followed by a line which starts with a symbol - -- that can start a declaration in the same column, or to the left of the - -- column in which the FUNCTION or PROCEDURE starts (normal style is to - -- indent any declarations which really belong a subprogram). If such a - -- subprogram encounters a missing BEGIN or missing END, then we decide - -- that the IS should have been a semicolon, and the subprogram body node - -- is marked (by setting the Bad_Is_Detected flag true. Note that we do - -- not do this for library level procedures, only for nested procedures, - -- since for library level procedures, we must have a body. - - -- The processing for a declarative part checks to see if the last - -- declaration scanned is marked in this way, and if it is, the tree - -- is modified to reflect the IS being interpreted as a semicolon. - --------------------------------------------------- -- Parser Type Definitions and Control Variables -- --------------------------------------------------- @@ -1450,6 +1448,47 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is -- the Node N (which is a Defining_Identifier node with the Chars field -- set) is a renaming of an entity in package Standard. + ----------------------------------- + -- Multiple defining identifiers -- + ----------------------------------- + + -- RM-3.3.1(7) says: + -- + -- Any declaration that includes a defining_identifier_list with + -- more than one defining_identifier is equivalent to a series of + -- declarations each containing one defining_identifier from the list, + -- with the rest of the text of the declaration copied for each + -- declaration in the series, in the same order as the list. + -- + -- We parse such declarations by first calling P_Def_Ids (see below). + -- Then, if there are multiple identifiers, we repeatedly scan the + -- type and initialization expression information by resetting the + -- scan pointer (so that we get completely separate trees for each + -- occurrence). + + -- Defining_Identifiers is a sequence of identifiers parsed by + -- P_Def_Ids. Idents holds the identifiers, and Num_Idents + -- points to the last-used array elements. The upper bound + -- is intended to be essentially infinite, so we don't bother + -- giving a good error message when it is exceeded -- we + -- simply raise an exception. + + type Defining_Identifiers_Array is + array (Pos range 1 .. 4096) of Entity_Id; + + type Defining_Identifiers is record + Num_Idents : Nat := 0; + Idents : Defining_Identifiers_Array; + end record; + + procedure Append + (Def_Ids : in out Defining_Identifiers; Def_Id : Entity_Id); + -- Append one defining identifier onto Def_Ids. + + procedure P_Def_Ids (Def_Ids : out Defining_Identifiers); + -- Parse a defining_identifier_list, appending the identifiers + -- onto Def_Ids, which should be initially empty. + end Util; -------------- diff --git a/gcc/ada/rtsfind.adb b/gcc/ada/rtsfind.adb index 86713ff..f47aacc 100644 --- a/gcc/ada/rtsfind.adb +++ b/gcc/ada/rtsfind.adb @@ -1030,8 +1030,7 @@ package body Rtsfind is U : RT_Unit_Table_Record renames RT_Unit_Table (U_Id); Priv_Par : constant Elist_Id := New_Elmt_List; Lib_Unit : Node_Id; - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; Saved_SM : constant SPARK_Mode_Type := SPARK_Mode; @@ -1099,7 +1098,7 @@ package body Rtsfind is procedure Restore_SPARK_Context is begin Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); end Restore_SPARK_Context; @@ -1289,7 +1288,7 @@ package body Rtsfind is declare LibUnit : constant Node_Id := Unit (Cunit (U.Unum)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; + Saved_GM : constant Ghost_Mode_Type := Ghost_Config.Ghost_Mode; Clause : Node_Id; Withn : Node_Id; @@ -1308,13 +1307,13 @@ package body Rtsfind is -- later, after ignored ghost code is converted to a null -- statement. - Ghost_Mode := None; + Ghost_Config.Ghost_Mode := None; Withn := Make_With_Clause (Standard_Location, Name => Make_Unit_Name (U, Defining_Unit_Name (Specification (LibUnit)))); - Ghost_Mode := Saved_GM; + Ghost_Config.Ghost_Mode := Saved_GM; Set_Corresponding_Spec (Withn, U.Entity); Set_First_Name (Withn); @@ -1627,7 +1626,9 @@ package body Rtsfind is -- is pulled within an ignored Ghost context because all this code will -- disappear. - if U_Id = System_Secondary_Stack and then Ghost_Mode /= Ignore then + if U_Id = System_Secondary_Stack + and then Ghost_Config.Ghost_Mode /= Ignore + then Sec_Stack_Used := True; end if; diff --git a/gcc/ada/sem.adb b/gcc/ada/sem.adb index e168d62..944ece1 100644 --- a/gcc/ada/sem.adb +++ b/gcc/ada/sem.adb @@ -104,8 +104,7 @@ package body Sem is -- Ghost mode. procedure Analyze (N : Node_Id) is - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit begin @@ -842,7 +841,7 @@ package body Sem is Expand_SPARK_Potential_Renaming (N); end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze; -- Version with check(s) suppressed @@ -1440,8 +1439,7 @@ package body Sem is -- the Ghost mode. procedure Do_Analyze is - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; -- Save Ghost and SPARK mode-related data to restore on exit @@ -1489,7 +1487,7 @@ package body Sem is Style_Max_Line_Length := Saved_ML; Style_Check_Max_Line_Length := Saved_CML; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; end Do_Analyze; diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index f38380c..78b6318 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -5092,7 +5092,7 @@ package body Sem_Attr is -- early transformation also avoids the generation of a useless loop -- entry constant. - if Present (Encl_Prag) and then Is_Ignored (Encl_Prag) then + if Present (Encl_Prag) and then Is_Ignored_In_Codegen (Encl_Prag) then Rewrite (N, Relocate_Node (P)); Preanalyze_And_Resolve (N); diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index b5c9e88..1ba76dc 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -4900,8 +4900,7 @@ package body Sem_Ch12 is Loc : constant Source_Ptr := Sloc (N); Is_Abbrev : constant Boolean := Is_Abbreviated_Instance (Defining_Entity (N)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; Saved_SM : constant SPARK_Mode_Type := SPARK_Mode; @@ -5680,7 +5679,7 @@ package body Sem_Ch12 is end if; Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); Style_Check := Saved_Style_Check; @@ -5695,7 +5694,7 @@ package body Sem_Ch12 is end if; Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); Style_Check := Saved_Style_Check; end Analyze_Package_Instantiation; @@ -6340,8 +6339,7 @@ package body Sem_Ch12 is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; Saved_SM : constant SPARK_Mode_Type := SPARK_Mode; @@ -6736,7 +6734,7 @@ package body Sem_Ch12 is end if; Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); exception @@ -6750,7 +6748,7 @@ package body Sem_Ch12 is end if; Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); end Analyze_Subprogram_Instantiation; @@ -12874,8 +12872,7 @@ package body Sem_Ch12 is -- the package body. Saved_CS : constant Config_Switches_Type := Save_Config_Switches; - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; Saved_LSST : constant Suppress_Stack_Entry_Ptr := @@ -13405,7 +13402,7 @@ package body Sem_Ch12 is Expander_Mode_Restore; Restore_Config_Switches (Saved_CS); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); Restore_Warnings (Saved_Warn); end Instantiate_Package_Body; @@ -13436,8 +13433,7 @@ package body Sem_Ch12 is -- the subprogram body. Saved_CS : constant Config_Switches_Type := Save_Config_Switches; - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; Saved_LSST : constant Suppress_Stack_Entry_Ptr := @@ -13740,7 +13736,7 @@ package body Sem_Ch12 is Expander_Mode_Restore; Restore_Config_Switches (Saved_CS); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); Restore_SPARK_Mode (Saved_SM, Saved_SMP); Restore_Warnings (Saved_Warn); end Instantiate_Subprogram_Body; diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb index b7ada50..31735e4 100644 --- a/gcc/ada/sem_ch13.adb +++ b/gcc/ada/sem_ch13.adb @@ -4799,7 +4799,7 @@ package body Sem_Ch13 is and then not Is_Ignored_Ghost_Entity (E) then if A_Id = Aspect_Pre then - if Is_Ignored (Aspect) then + if Is_Ignored_In_Codegen (Aspect) then Set_Ignored_Class_Preconditions (E, New_Copy_Tree (Expr)); else @@ -4813,7 +4813,7 @@ package body Sem_Ch13 is elsif No (Class_Postconditions (E)) and then No (Ignored_Class_Postconditions (E)) then - if Is_Ignored (Aspect) then + if Is_Ignored_In_Codegen (Aspect) then Set_Ignored_Class_Postconditions (E, New_Copy_Tree (Expr)); else @@ -10282,8 +10282,7 @@ package body Sem_Ch13 is procedure Build_Predicate_Function (Typ : Entity_Id; N : Node_Id) is Loc : constant Source_Ptr := Sloc (Typ); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Expr : Node_Id; @@ -10449,7 +10448,7 @@ package body Sem_Ch13 is -- which is needed to generate the corresponding predicate -- function. - if Is_Ignored_Ghost_Pragma (Prag) then + if Is_Ignored_Ghost_Pragma_In_Codegen (Prag) then Add_Condition (New_Occurrence_Of (Standard_True, Sloc (Prag))); else @@ -10490,7 +10489,8 @@ package body Sem_Ch13 is -- "and"-in the Arg2 condition to evolving expression - if not Is_Ignored_Ghost_Pragma (Prag) then + if not Is_Ignored_Ghost_Pragma_In_Codegen (Prag) + then Add_Condition (Arg2_Copy); end if; end; @@ -11090,7 +11090,7 @@ package body Sem_Ch13 is end; end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); if Restore_Scope then Pop_Scope; @@ -11110,8 +11110,7 @@ package body Sem_Ch13 is is Loc : constant Source_Ptr := Sloc (Typ); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Func_Decl : Node_Id; @@ -11192,7 +11191,7 @@ package body Sem_Ch13 is Insert_After (Parent (Typ), Func_Decl); Analyze (Func_Decl); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); return Func_Decl; end Build_Predicate_Function_Declaration; diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index 3726169..9f69e4f 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -4386,8 +4386,7 @@ package body Sem_Ch3 is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Prev_Entity : Entity_Id := Empty; @@ -5475,7 +5474,7 @@ package body Sem_Ch3 is Check_No_Hidden_State (Id); end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Object_Declaration; --------------------------- @@ -21707,8 +21706,7 @@ package body Sem_Ch3 is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Full_Indic : Node_Id; @@ -22401,7 +22399,7 @@ package body Sem_Ch3 is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Process_Full_View; ----------------------------------- diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index 0661e64..9e4936b 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -385,8 +385,7 @@ package body Sem_Ch5 is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit T1 : Entity_Id; @@ -1193,7 +1192,7 @@ package body Sem_Ch5 is Analyze_Dimension (N); <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); -- If the right-hand side contains target names, expansion has been -- disabled to prevent expansion that might move target names out of @@ -2108,7 +2107,7 @@ package body Sem_Ch5 is -- A label declared within a Ghost region becomes Ghost (SPARK RM -- 6.9(2)). - if Ghost_Mode > None then + if Ghost_Config.Ghost_Mode > None then Set_Is_Ghost_Entity (Id); end if; end Analyze_Implicit_Label_Declaration; diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb index 709f625..b7ddc4b 100644 --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -1372,8 +1372,7 @@ package body Sem_Ch6 is Loc : constant Source_Ptr := Sloc (N); Spec : constant Node_Id := Specification (N); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; -- Save the Ghost and SPARK mode-related data to restore on exit @@ -1529,7 +1528,7 @@ package body Sem_Ch6 is <<Leave>> Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Null_Procedure; ----------------------------- @@ -1624,8 +1623,7 @@ package body Sem_Ch6 is Loc : constant Source_Ptr := Sloc (N); P : constant Node_Id := Name (N); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Actual : Node_Id; @@ -1890,7 +1888,7 @@ package body Sem_Ch6 is end if; <<Leave>> - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Procedure_Call; ------------------------------ @@ -3608,8 +3606,7 @@ package body Sem_Ch6 is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_EA : constant Boolean := Expander_Active; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; @@ -3836,7 +3833,7 @@ package body Sem_Ch6 is -- user entities, as internally generated entitities might still need -- to be expanded (e.g. those generated for types). - if Present (Ignored_Ghost_Region) + if Present (Ghost_Config.Ignored_Ghost_Region) and then Comes_From_Source (Body_Id) then Expander_Active := False; @@ -5022,12 +5019,12 @@ package body Sem_Ch6 is end if; <<Leave>> - if Present (Ignored_Ghost_Region) then + if Present (Ghost_Config.Ignored_Ghost_Region) then Expander_Active := Saved_EA; end if; Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Subprogram_Body_Helper; ------------------------------------ diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb index c2e60aa..d28bafb 100644 --- a/gcc/ada/sem_ch7.adb +++ b/gcc/ada/sem_ch7.adb @@ -714,8 +714,7 @@ package body Sem_Ch7 is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; Saved_EA : constant Boolean := Expander_Active; Saved_ISMP : constant Boolean := Ignore_SPARK_Mode_Pragmas_In_Instance; @@ -836,7 +835,7 @@ package body Sem_Ch7 is -- user entities, as internally generated entities might still need -- to be expanded (e.g. those generated for types). - if Present (Ignored_Ghost_Region) + if Present (Ghost_Config.Ignored_Ghost_Region) and then Comes_From_Source (Body_Id) then Expander_Active := False; @@ -1149,12 +1148,12 @@ package body Sem_Ch7 is end if; end if; - if Present (Ignored_Ghost_Region) then + if Present (Ghost_Config.Ignored_Ghost_Region) then Expander_Active := Saved_EA; end if; Ignore_SPARK_Mode_Pragmas_In_Instance := Saved_ISMP; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Package_Body_Helper; --------------------------------- diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 2717c38..4fd5b65 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -436,8 +436,7 @@ package body Sem_Prag is Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Errors : Nat; @@ -492,7 +491,7 @@ package body Sem_Prag is End_Scope; end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end if; Set_Is_Analyzed_Pragma (N); @@ -607,8 +606,7 @@ package body Sem_Prag is CCases : constant Node_Id := Expression (Get_Argument (N, Spec_Id)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit CCase : Node_Id; @@ -695,7 +693,7 @@ package body Sem_Prag is Set_Is_Analyzed_Pragma (N); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Contract_Cases_In_Decl_Part; ---------------------------------- @@ -2464,8 +2462,7 @@ package body Sem_Prag is Exceptional_Contracts : constant Node_Id := Expression (Get_Argument (N, Spec_Id)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Exceptional_Contract : Node_Id; @@ -2556,7 +2553,7 @@ package body Sem_Prag is Set_Is_Analyzed_Pragma (N); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Exceptional_Cases_In_Decl_Part; ------------------------------------- @@ -2772,8 +2769,7 @@ package body Sem_Prag is Exit_Contracts : constant Node_Id := Expression (Get_Argument (N, Spec_Id)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Exit_Contract : Node_Id; @@ -2863,7 +2859,7 @@ package body Sem_Prag is Set_Is_Analyzed_Pragma (N); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Exit_Cases_In_Decl_Part; -------------------------------------------- @@ -3688,8 +3684,7 @@ package body Sem_Prag is Pack_Id : constant Entity_Id := Defining_Entity (Pack_Decl); Expr : constant Node_Id := Expression (Get_Argument (N, Pack_Id)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit begin @@ -3713,7 +3708,7 @@ package body Sem_Prag is Preanalyze_And_Resolve (Expr, Standard_Boolean); Set_Is_Analyzed_Pragma (N); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Initial_Condition_In_Decl_Part; -------------------------------------- @@ -5766,7 +5761,7 @@ package body Sem_Prag is begin if Pname = Name_Pre_Class then - if Is_Ignored (N) then + if Is_Ignored_In_Codegen (N) then Set_Ignored_Class_Preconditions (Subp_Id, New_Copy_Tree (Expr)); else @@ -5774,7 +5769,7 @@ package body Sem_Prag is end if; else - if Is_Ignored (N) then + if Is_Ignored_In_Codegen (N) then Set_Ignored_Class_Postconditions (Subp_Id, New_Copy_Tree (Expr)); else @@ -12987,7 +12982,9 @@ package body Sem_Prag is -- An abstract state declared within a Ghost region becomes -- Ghost (SPARK RM 6.9(2)). - if Ghost_Mode > None or else Is_Ghost_Entity (Pack_Id) then + if Ghost_Config.Ghost_Mode > None + or else Is_Ghost_Entity (Pack_Id) + then Set_Is_Ghost_Entity (State_Id); end if; @@ -14302,7 +14299,7 @@ package body Sem_Prag is -- cannot occur within a Ghost subprogram or package -- (SPARK RM 6.9(16)). - if Ghost_Mode > None then + if Ghost_Config.Ghost_Mode > None then Error_Pragma ("pragma % cannot appear within ghost subprogram or " & "package"); @@ -14871,25 +14868,15 @@ package body Sem_Prag is Set_Is_Ignored (N, False); else - -- In CodePeer mode and GNATprove mode, we need to - -- consider all assertions, unless they are disabled, - -- because transformations of the AST may depend on - -- assertions being checked. + Set_Is_Checked (N, False); + Set_Is_Ignored (N, True); - if CodePeer_Mode or GNATprove_Mode then - Set_Is_Checked (N, True); - Set_Is_Ignored (N, False); - else - Set_Is_Checked (N, False); - Set_Is_Ignored (N, True); - end if; end if; end Handle_Dynamic_Predicate_Check; -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Cname : Name_Id; @@ -15047,7 +15034,7 @@ package body Sem_Prag is -- False at compile time, and we do not want to delete this -- warning when we delete the if statement. - if Expander_Active and Is_Ignored (N) then + if Expander_Active and Is_Ignored_In_Codegen (N) then Eloc := Sloc (Expr); Rewrite (N, @@ -15100,7 +15087,7 @@ package body Sem_Prag is In_Assertion_Expr := In_Assertion_Expr - 1; end if; - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Check; -------------------------- @@ -16246,10 +16233,10 @@ package body Sem_Prag is Cond := New_Occurrence_Of (Boolean_Literals - (Expander_Active and then not Is_Ignored (N)), + (Expander_Active and then not Is_Ignored_In_Codegen (N)), Loc); - if not Is_Ignored (N) then + if not Is_Ignored_In_Codegen (N) then Set_SCO_Pragma_Enabled (Loc); end if; @@ -18720,7 +18707,7 @@ package body Sem_Prag is -- region (SPARK RM 6.9(6)). if Is_False (Expr_Value (Expr)) - and then Ghost_Mode > None + and then Ghost_Config.Ghost_Mode > None then Error_Pragma ("pragma % with value False cannot appear in enabled " @@ -28323,8 +28310,7 @@ package body Sem_Prag is Expr : constant Node_Id := Expression (Get_Argument (N, Spec_Id)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Errors : Nat; @@ -28417,7 +28403,7 @@ package body Sem_Prag is Check_Postcondition_Use_In_Inlined_Subprogram (N, Spec_Id); Set_Is_Analyzed_Pragma (N); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Pre_Post_Condition_In_Decl_Part; --------------------------------------- @@ -28437,8 +28423,7 @@ package body Sem_Prag is Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Errors : Nat; @@ -28561,7 +28546,7 @@ package body Sem_Prag is Check_Postcondition_Use_In_Inlined_Subprogram (N, Spec_Id); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end if; Set_Is_Analyzed_Pragma (N); @@ -31803,8 +31788,7 @@ package body Sem_Prag is Variants : constant Node_Id := Expression (Get_Argument (N, Spec_Id)); - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit Variant : Node_Id; @@ -31899,7 +31883,7 @@ package body Sem_Prag is Set_Is_Analyzed_Pragma (N); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Analyze_Subprogram_Variant_In_Decl_Part; ------------------------------------ @@ -32195,20 +32179,8 @@ package body Sem_Prag is when Name_Ignore | Name_Off => - -- In CodePeer mode and GNATprove mode, we need to - -- consider all assertions, unless they are disabled. - -- Force Is_Checked on ignored assertions, in particular - -- because transformations of the AST may depend on - -- assertions being checked (e.g. the translation of - -- attribute 'Loop_Entry). - - if CodePeer_Mode or GNATprove_Mode then - Set_Is_Checked (N, True); - Set_Is_Ignored (N, False); - else - Set_Is_Checked (N, False); - Set_Is_Ignored (N, True); - end if; + Set_Is_Checked (N, False); + Set_Is_Ignored (N, True); when Name_Check | Name_On @@ -34270,113 +34242,123 @@ package body Sem_Prag is (N : Node_Id; Eloc : Source_Ptr) is - Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N)); - Arg1x : constant Node_Id := Get_Pragma_Arg (Arg1); - Arg2 : constant Node_Id := Next (Arg1); + Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N)); + Arg1x : constant Node_Id := Get_Pragma_Arg (Arg1); + Prag_Id : constant Pragma_Id := Get_Pragma_Id (N); - Pname : constant Name_Id := Pragma_Name_Unmapped (N); - Prag_Id : constant Pragma_Id := Get_Pragma_Id (Pname); + procedure Emit_Compile_Time_Message (Msg_Arg : Node_Id); + -- Emit the pragma a as diagnostic message. New_Line characters are + -- considered separators for those messages where the following lines + -- are considered as continuation messages for the same diagnostic. - begin - Analyze_And_Resolve (Arg1x, Standard_Boolean); + ------------------------------- + -- Emit_Compile_Time_Message -- + ------------------------------- - if Compile_Time_Known_Value (Arg1x) then - if Is_True (Expr_Value (Arg1x)) then + procedure Emit_Compile_Time_Message (Msg_Arg : Node_Id) is + -- We have already verified that the Msg_Arg is a static + -- string expression. Its string value must be retrieved + -- explicitly if it is a declared constant, otherwise it has + -- been constant-folded previously. + + Cent : constant Entity_Id := Cunit_Entity (Current_Sem_Unit); + Str : constant String_Id := + Strval (Expr_Value_S (Get_Pragma_Arg (Msg_Arg))); + Str_Len : constant Nat := String_Length (Str); + + Force : constant Boolean := + Prag_Id = Pragma_Compile_Time_Warning + and then Is_Spec_Name (Unit_Name (Current_Sem_Unit)) + and then (Ekind (Cent) /= E_Package + or else not In_Private_Part (Cent)); + -- Set True if this is the warning case, and we are in the + -- visible part of a package spec, or in a subprogram spec, + -- in which case we want to force the client to see the + -- warning, even though it is not in the main unit. + + Msg_Ctrl : Bounded_String (6); + -- Control characters for the message. + -- The longest value contains 6 characters: "\<<~!!" + + C : Character; + CC : Char_Code; + Cont : Boolean; + Ptr : Nat; - -- We have already verified that the second argument is a static - -- string expression. Its string value must be retrieved - -- explicitly if it is a declared constant, otherwise it has - -- been constant-folded previously. + begin + -- Loop through segments of message separated by line feeds. + -- We output these segments as separate messages with + -- continuation marks for all but the first. - declare - Cent : constant Entity_Id := Cunit_Entity (Current_Sem_Unit); - Str : constant String_Id := - Strval (Expr_Value_S (Get_Pragma_Arg (Arg2))); - Str_Len : constant Nat := String_Length (Str); - - Force : constant Boolean := - Prag_Id = Pragma_Compile_Time_Warning - and then Is_Spec_Name (Unit_Name (Current_Sem_Unit)) - and then (Ekind (Cent) /= E_Package - or else not In_Private_Part (Cent)); - -- Set True if this is the warning case, and we are in the - -- visible part of a package spec, or in a subprogram spec, - -- in which case we want to force the client to see the - -- warning, even though it is not in the main unit. - - C : Character; - CC : Char_Code; - Cont : Boolean; - Ptr : Nat; + Cont := False; + Ptr := 1; + loop + Error_Msg_Strlen := 0; + Msg_Ctrl.Length := 0; - begin - -- Loop through segments of message separated by line feeds. - -- We output these segments as separate messages with - -- continuation marks for all but the first. + -- Loop to copy characters from argument to error message + -- string buffer. - Cont := False; - Ptr := 1; - loop - Error_Msg_Strlen := 0; + loop + exit when Ptr > Str_Len; + CC := Get_String_Char (Str, Ptr); + Ptr := Ptr + 1; - -- Loop to copy characters from argument to error message - -- string buffer. + -- Ignore wide chars ??? else store character - loop - exit when Ptr > Str_Len; - CC := Get_String_Char (Str, Ptr); - Ptr := Ptr + 1; + if In_Character_Range (CC) then + C := Get_Character (CC); + exit when C = ASCII.LF; + Error_Msg_Strlen := Error_Msg_Strlen + 1; + Error_Msg_String (Error_Msg_Strlen) := C; + end if; + end loop; - -- Ignore wide chars ??? else store character + -- Here with one line ready to go - if In_Character_Range (CC) then - C := Get_Character (CC); - exit when C = ASCII.LF; - Error_Msg_Strlen := Error_Msg_Strlen + 1; - Error_Msg_String (Error_Msg_Strlen) := C; - end if; - end loop; + Error_Msg_Warn := Prag_Id = Pragma_Compile_Time_Warning; - -- Here with one line ready to go + if Cont then + Append (Msg_Ctrl, "\"); + end if; - Error_Msg_Warn := Prag_Id = Pragma_Compile_Time_Warning; + Append (Msg_Ctrl, "<<~"); - -- If this is a warning in a spec, then we want clients - -- to see the warning, so mark the message with the - -- special sequence !! to force the warning. In the case - -- of a package spec, we do not force this if we are in - -- the private part of the spec. + -- If this is a warning in a spec, then we want clients + -- to see the warning, so mark the message with the + -- special sequence !! to force the warning. In the case + -- of a package spec, we do not force this if we are in + -- the private part of the spec. - if Force then - if Cont = False then - Error_Msg - ("<<~!!", Eloc, N, Is_Compile_Time_Pragma => True); - Cont := True; - else - Error_Msg - ("\<<~!!", Eloc, N, Is_Compile_Time_Pragma => True); - end if; + if Force then + Append (Msg_Ctrl, "!!"); + end if; - -- Error, rather than warning, or in a body, so we do not - -- need to force visibility for client (error will be - -- output in any case, and this is the situation in which - -- we do not want a client to get a warning, since the - -- warning is in the body or the spec private part). + -- Error, rather than warning, or in a body, so we do not + -- need to force visibility for client (error will be + -- output in any case, and this is the situation in which + -- we do not want a client to get a warning, since the + -- warning is in the body or the spec private part). - else - if Cont = False then - Error_Msg - ("<<~", Eloc, N, Is_Compile_Time_Pragma => True); - Cont := True; - else - Error_Msg - ("\<<~", Eloc, N, Is_Compile_Time_Pragma => True); - end if; - end if; + Error_Msg + (To_String (Msg_Ctrl), Eloc, N, Is_Compile_Time_Pragma => True); - exit when Ptr > Str_Len; - end loop; - end; + -- The next lines are considered continuation messages + + Cont := True; + + exit when Ptr > Str_Len; + end loop; + end Emit_Compile_Time_Message; + + -- Start of processing for Validate_Compile_Time_Warning_Or_Error + + begin + Analyze_And_Resolve (Arg1x, Standard_Boolean); + + if Compile_Time_Known_Value (Arg1x) then + if Is_True (Expr_Value (Arg1x)) then + Emit_Compile_Time_Message (Next (Arg1)); end if; -- Arg1x is not known at compile time, so possibly issue an error @@ -35101,7 +35083,17 @@ package body Sem_Prag is begin Set_Scope (T.Scope); Reset_Analyzed_Flags (T.Prag); - Validate_Compile_Time_Warning_Or_Error (T.Prag, T.Eloc); + if Nkind (T.Prag) = N_Pragma then + Validate_Compile_Time_Warning_Or_Error (T.Prag, T.Eloc); + else + pragma Assert (Nkind (Original_Node (T.Prag)) = N_Pragma); + + -- The pragma was likely removed in ignored ghost code. Check + -- the original node instead. + + Validate_Compile_Time_Warning_Or_Error + (Original_Node (T.Prag), T.Eloc); + end if; Unset_Scope (T.Scope); end; end loop; diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index b2b4fed..d19b3b9 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -1963,8 +1963,7 @@ package body Sem_Util is -- Local variables - Saved_GM : constant Ghost_Mode_Type := Ghost_Mode; - Saved_IGR : constant Node_Id := Ignored_Ghost_Region; + Saved_Ghost_Config : constant Ghost_Config_Type := Ghost_Config; -- Save the Ghost-related attributes to restore on exit -- Start of processing for Build_Elaboration_Entity @@ -2060,7 +2059,7 @@ package body Sem_Util is Set_Has_Qualified_Name (Elab_Ent); Set_Has_Fully_Qualified_Name (Elab_Ent); - Restore_Ghost_Region (Saved_GM, Saved_IGR); + Restore_Ghost_Region (Saved_Ghost_Config); end Build_Elaboration_Entity; -------------------------------- @@ -12473,6 +12472,41 @@ package body Sem_Util is end if; end Is_Extended_Access_Type; + ---------------------------------------- + -- Is_Ignored_Ghost_Entity_In_Codegen -- + ---------------------------------------- + + function Is_Ignored_Ghost_Entity_In_Codegen (N : Entity_Id) return Boolean + is + begin + return + Is_Ignored_Ghost_Entity (N) + and then not GNATprove_Mode + and then not CodePeer_Mode; + end Is_Ignored_Ghost_Entity_In_Codegen; + + ---------------------------------------- + -- Is_Ignored_Ghost_Pragma_In_Codegen -- + ---------------------------------------- + + function Is_Ignored_Ghost_Pragma_In_Codegen (N : Node_Id) return Boolean is + begin + return + Is_Ignored_Ghost_Pragma (N) + and then not GNATprove_Mode + and then not CodePeer_Mode; + end Is_Ignored_Ghost_Pragma_In_Codegen; + + --------------------------- + -- Is_Ignored_In_Codegen -- + --------------------------- + + function Is_Ignored_In_Codegen (N : Node_Id) return Boolean is + begin + return + Is_Ignored (N) and then not GNATprove_Mode and then not CodePeer_Mode; + end Is_Ignored_In_Codegen; + --------------------------------- -- Side_Effect_Free_Statements -- --------------------------------- @@ -22574,7 +22608,7 @@ package body Sem_Util is -- Mark the Ghost and SPARK mode in effect if Modes then - if Ghost_Mode = Ignore then + if Ghost_Config.Ghost_Mode = Ignore then Set_Is_Ignored_Ghost_Node (N); end if; @@ -26439,16 +26473,6 @@ package body Sem_Util is end if; end if; - -- In CodePeer mode and GNATprove mode, we need to consider all - -- assertions, unless they are disabled. Force Name_Check on - -- ignored assertions. - - if Kind in Name_Ignore | Name_Off - and then (CodePeer_Mode or GNATprove_Mode) - then - Kind := Name_Check; - end if; - return Kind; end Policy_In_Effect; @@ -26482,9 +26506,11 @@ package body Sem_Util is function Predicate_Enabled (Typ : Entity_Id) return Boolean is begin - return Present (Predicate_Function (Typ)) - and then not Predicates_Ignored (Typ) - and then not Predicate_Checks_Suppressed (Empty); + return + Present (Predicate_Function (Typ)) + and then (GNATprove_Mode + or else (not Predicates_Ignored (Typ) + and then not Predicate_Checks_Suppressed (Empty))); end Predicate_Enabled; ---------------------------------- diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index 4554f24..47fcc7d 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -2079,6 +2079,18 @@ package Sem_Util is -- . machine_emax = 2**14 -- . machine_emin = 3 - machine_emax + function Is_Ignored_Ghost_Entity_In_Codegen (N : Node_Id) return Boolean; + -- True if N Is_Ignored_Ghost_Entity and GNATProve_mode and Codepeer_Mode + -- are not active. + + function Is_Ignored_Ghost_Pragma_In_Codegen (N : Node_Id) return Boolean; + -- True if N Is_Ignored_Ghost_Pragma and GNATProve_mode and Codepeer_Mode + -- are not active. + + function Is_Ignored_In_Codegen (N : Node_Id) return Boolean; + -- True if N Is_Ignored and GNATProve_mode and Codepeer_Mode are not + -- active. + function Is_EVF_Expression (N : Node_Id) return Boolean; -- Determine whether node N denotes a reference to a formal parameter of -- a specific tagged type whose related subprogram is subject to pragma diff --git a/gcc/ada/table.adb b/gcc/ada/table.adb index 37c4949..31891de 100644 --- a/gcc/ada/table.adb +++ b/gcc/ada/table.adb @@ -40,6 +40,9 @@ package body Table is Min : constant Int := Int (Table_Low_Bound); -- Subscript of the minimum entry in the currently allocated table + Max : Int := Min + (Table_Initial * Table_Factor) - 1; + -- Subscript of the maximum entry in the currently allocated table + Length : Int := 0; -- Number of entries in currently allocated table. The value of zero -- ensures that we initially allocate the table. diff --git a/gcc/ada/table.ads b/gcc/ada/table.ads index 22e9172..623ce14 100644 --- a/gcc/ada/table.ads +++ b/gcc/ada/table.ads @@ -223,9 +223,6 @@ package Table is -- the official interfaces (since a modification to Last may require a -- reallocation of the table). - Max : Int; - -- Subscript of the maximum entry in the currently allocated table - type Saved_Table is record Last_Val : Int; Max : Int; diff --git a/gcc/ada/treepr.adb b/gcc/ada/treepr.adb index 375608d..857b926 100644 --- a/gcc/ada/treepr.adb +++ b/gcc/ada/treepr.adb @@ -1600,19 +1600,17 @@ package body Treepr is -- If this is a discrete expression whose value is known, print that -- value. - if Nkind (N) in N_Subexpr + if ((Is_Entity_Name (N) -- e.g. enumeration literal + and then Present (Entity (N))) + or else Nkind (N) in N_Integer_Literal + | N_Character_Literal + | N_Unchecked_Type_Conversion) and then Compile_Time_Known_Value (N) and then Present (Etype (N)) and then Is_Discrete_Type (Etype (N)) then - if Is_Entity_Name (N) -- e.g. enumeration literal - or else Nkind (N) in N_Integer_Literal - | N_Character_Literal - | N_Unchecked_Type_Conversion - then - Print_Str (" val = "); - UI_Write (Expr_Value (N)); - end if; + Print_Str (" val = "); + UI_Write (Expr_Value (N)); end if; if Nkind (N) in N_Entity then diff --git a/gcc/avoid-store-forwarding.cc b/gcc/avoid-store-forwarding.cc index 1de6fd6..78ed736 100644 --- a/gcc/avoid-store-forwarding.cc +++ b/gcc/avoid-store-forwarding.cc @@ -145,11 +145,18 @@ is_store_forwarding (rtx store_mem, rtx load_mem, HOST_WIDE_INT *off_val) poly_int64 load_offset, store_offset; rtx load_base = strip_offset (XEXP (load_mem, 0), &load_offset); rtx store_base = strip_offset (XEXP (store_mem, 0), &store_offset); + poly_int64 off_diff = store_offset - load_offset; + + HOST_WIDE_INT off_val_tmp = 0; + bool is_off_diff_constant = off_diff.is_constant (&off_val_tmp); + if (off_val) + *off_val = off_val_tmp; + return (MEM_SIZE (load_mem).is_constant () && rtx_equal_p (load_base, store_base) && known_subrange_p (store_offset, MEM_SIZE (store_mem), load_offset, MEM_SIZE (load_mem)) - && (store_offset - load_offset).is_constant (off_val)); + && is_off_diff_constant); } /* Given a list of small stores that are forwarded to LOAD_INSN, try to diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 4a13fc0..814accf 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -16659,7 +16659,7 @@ c_parser_omp_variable_list (c_parser *parser, || CONVERT_EXPR_P (decl)) decl = TREE_OPERAND (decl, 0); - tree u = build_omp_clause (clause_loc, kind); + tree u = build_omp_clause (loc, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; list = u; @@ -20072,7 +20072,7 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list) map ( [map-type-modifier[,] ...] map-kind: variable-list ) map-type-modifier: - always | close */ + always | close | present | iterator (iterators-definition) */ static tree c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) @@ -20087,15 +20087,35 @@ c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) int pos = 1; int map_kind_pos = 0; - while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + int iterator_length = 0; + for (;;) { - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON) + c_token *tok = c_parser_peek_nth_token_raw (parser, pos); + if (tok->type != CPP_NAME) + break; + + const char *p = IDENTIFIER_POINTER (tok->value); + c_token *next_tok = c_parser_peek_nth_token_raw (parser, pos + 1); + if (strcmp (p, "iterator") == 0 && next_tok->type == CPP_OPEN_PAREN) + { + unsigned n = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &n) + && c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + { + iterator_length = n - pos + 1; + pos = n; + next_tok = c_parser_peek_nth_token_raw (parser, pos + 1); + } + } + + if (next_tok->type == CPP_COLON) { map_kind_pos = pos; break; } - if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + if (next_tok->type == CPP_COMMA) pos++; else if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_OPEN_PAREN) @@ -20117,6 +20137,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) int present_modifier = 0; int mapper_modifier = 0; tree mapper_name = NULL_TREE; + tree iterators = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { c_token *tok = c_parser_peek_token (parser); @@ -20150,6 +20171,17 @@ c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) close_modifier++; c_parser_consume_token (parser); } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + c_parser_error (parser, "too many %<iterator%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + iterators = c_parser_omp_iterators (parser); + pos += iterator_length - 1; + } else if (strcmp ("mapper", p) == 0) { c_parser_consume_token (parser); @@ -20223,8 +20255,8 @@ c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) else { c_parser_error (parser, "%<map%> clause with map-type modifier other " - "than %<always%>, %<close%>, %<mapper%> or " - "%<present%>"); + "than %<always%>, %<close%>, %<iterator%>, " + "%<mapper%> or %<present%>"); parens.skip_until_found_close (parser); return list; } @@ -20273,9 +20305,19 @@ c_parser_omp_clause_map (c_parser *parser, tree list, bool declare_mapper_p) tree last_new = NULL_TREE; + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) { OMP_CLAUSE_SET_MAP_KIND (c, kind); + OMP_CLAUSE_ITERATORS (c) = iterators; last_new = c; } @@ -20534,8 +20576,11 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list) to ( variable-list ) OpenMP 5.1: - from ( [present :] variable-list ) - to ( [present :] variable-list ) */ + from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + + motion-modifier: + present | iterator (iterators-definition) */ static tree c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, @@ -20546,18 +20591,85 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, if (!parens.require_open (parser)) return list; + int pos = 1, colon_pos = 0; + int iterator_length = 0; + + while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME) + { + const char *identifier = + IDENTIFIER_POINTER (c_parser_peek_nth_token_raw (parser, pos)->value); + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type + == CPP_OPEN_PAREN) + { + unsigned int npos = pos + 2; + if (c_parser_check_balanced_raw_token_sequence (parser, &npos) + && (c_parser_peek_nth_token_raw (parser, npos)->type + == CPP_CLOSE_PAREN)) + { + if (strcmp (identifier, "iterator") == 0) + iterator_length = npos - pos + 1; + pos = npos; + } + } + if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA) + pos += 2; + else + pos++; + if (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_COLON) + { + colon_pos = pos; + break; + } + } + bool present = false; - c_token *token = c_parser_peek_token (parser); + tree iterators = NULL_TREE; - if (token->type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (token->value), "present") == 0 - && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + for (int pos = 1; pos < colon_pos; ++pos) { - present = true; - c_parser_consume_token (parser); - c_parser_consume_token (parser); + c_token *token = c_parser_peek_token (parser); + if (token->type == CPP_COMMA) + { + c_parser_consume_token (parser); + continue; + } + const char *p = IDENTIFIER_POINTER (token->value); + if (strcmp ("present", p) == 0) + { + if (present) + { + c_parser_error (parser, "too many %<present%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + present = true; + c_parser_consume_token (parser); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + c_parser_error (parser, "too many %<iterator%> modifiers"); + parens.skip_until_found_close (parser); + return list; + } + iterators = c_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + else + { + error_at (token->location, + "%qs clause with modifier other than %<iterator%> or " + "%<present%>", + kind == OMP_CLAUSE_TO ? "to" : "from"); + parens.skip_until_found_close (parser); + return list; + } } + if (colon_pos) + c_parser_require (parser, CPP_COLON, "expected %<:%>"); + tree nl = c_parser_omp_variable_list (parser, loc, kind, list); parens.skip_until_found_close (parser); @@ -20565,6 +20677,19 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind, for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_MOTION_PRESENT (c) = 1; + if (iterators) + { + tree block = pop_scope (); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + + if (iterators) + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ITERATORS (c) = iterators; + return nl; } diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ed6e56e..b192663 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -16204,7 +16204,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* We've reached the end of a list of expanded nodes. Reset the group start pointer. */ if (c == grp_sentinel) - grp_start_p = NULL; + { + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc != grp_sentinel; + gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + grp_start_p = NULL; + } switch (OMP_CLAUSE_CODE (c)) { @@ -16962,6 +16969,13 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + if (OMP_CLAUSE_ITERATORS (c) + && c_omp_finish_iterators (OMP_CLAUSE_ITERATORS (c))) + { + t = error_mark_node; + break; + } + /* FALLTHRU */ case OMP_CLAUSE__CACHE_: { using namespace omp_addr_tokenizer; @@ -17690,6 +17704,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); } + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc; gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + if (simdlen && safelen && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen), diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 38c307c..36bd885 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -1020,7 +1020,7 @@ void aarch64_err_no_fpadvsimd (machine_mode); void aarch64_expand_epilogue (rtx_call_insn *); rtx aarch64_ptrue_all (unsigned int); opt_machine_mode aarch64_ptrue_all_mode (rtx); -rtx aarch64_convert_sve_data_to_pred (rtx, machine_mode, rtx); +rtx aarch64_convert_sve_data_to_pred (rtx, rtx); rtx aarch64_expand_sve_dupq (rtx, machine_mode, rtx); void aarch64_expand_mov_immediate (rtx, rtx); rtx aarch64_stack_protect_canary_mem (machine_mode, rtx, aarch64_salt_type); @@ -1039,6 +1039,7 @@ void aarch64_expand_sve_mem_move (rtx, rtx, machine_mode); bool aarch64_maybe_expand_sve_subreg_move (rtx, rtx); rtx aarch64_replace_reg_mode (rtx, machine_mode); void aarch64_split_sve_subreg_move (rtx, rtx, rtx); +void aarch64_emit_sve_pred_vec_duplicate (machine_mode, rtx, rtx); void aarch64_expand_prologue (void); void aarch64_decompose_vec_struct_index (machine_mode, rtx *, rtx *, bool); void aarch64_expand_vector_init (rtx, rtx); diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc index b439683..ecc0687 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc @@ -214,7 +214,8 @@ public: expand (function_expander &e) const override { e.add_ptrue_hint (0, e.gp_mode (0)); - insn_code icode = code_for_aarch64_pred_fac (m_unspec, e.vector_mode (0)); + insn_code icode = code_for_aarch64_pred_fac_acle (m_unspec, + e.vector_mode (0)); return e.use_exact_insn (icode); } @@ -497,10 +498,10 @@ public: { bool unsigned_p = e.type_suffix (0).unsigned_p; rtx_code code = get_rtx_code (m_code, unsigned_p); - return e.use_exact_insn (code_for_aarch64_pred_cmp (code, mode)); + return e.use_exact_insn (code_for_aarch64_pred_cmp_acle (code, mode)); } - insn_code icode = code_for_aarch64_pred_fcm (m_unspec_for_fp, mode); + insn_code icode = code_for_aarch64_pred_fcm_acle (m_unspec_for_fp, mode); return e.use_exact_insn (icode); } @@ -542,7 +543,7 @@ public: /* If the argument is a constant that the unwidened comparisons can handle directly, use them instead. */ - insn_code icode = code_for_aarch64_pred_cmp (code, mode); + insn_code icode = code_for_aarch64_pred_cmp_acle (code, mode); rtx op2 = unwrap_const_vec_duplicate (e.args[3]); if (CONSTANT_P (op2) && insn_data[icode].operand[4].predicate (op2, DImode)) @@ -581,7 +582,8 @@ public: expand (function_expander &e) const override { e.add_ptrue_hint (0, e.gp_mode (0)); - return e.use_exact_insn (code_for_aarch64_pred_fcmuo (e.vector_mode (0))); + auto mode = e.vector_mode (0); + return e.use_exact_insn (code_for_aarch64_pred_fcmuo_acle (mode)); } }; @@ -1048,6 +1050,23 @@ public: rtx expand (function_expander &e) const override { + machine_mode mode = e.vector_mode (0); + if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) + { + gcc_assert (e.pred == PRED_none); + + rtx src = e.args[0]; + if (GET_CODE (src) == CONST_INT) + return (src == const0_rtx + ? CONST0_RTX (VNx16BImode) + : aarch64_ptrue_all (e.type_suffix (0).element_bytes)); + + rtx dest = e.get_reg_target (); + src = force_reg (GET_MODE (src), src); + aarch64_emit_sve_pred_vec_duplicate (mode, dest, src); + return dest; + } + if (e.pred == PRED_none || e.pred == PRED_x) /* There's no benefit to using predicated instructions for _x here. */ return e.use_unpred_insn (e.direct_optab_handler (vec_duplicate_optab)); @@ -1056,7 +1075,6 @@ public: the duplicate of the function argument and the "false" value is the value of inactive lanes. */ insn_code icode; - machine_mode mode = e.vector_mode (0); if (valid_for_const_vector_p (GET_MODE_INNER (mode), e.args.last ())) /* Duplicate the constant to fill a vector. The pattern optimizes various cases involving constant operands, falling back to SEL @@ -1197,8 +1215,7 @@ public: if (mode != e.vector_mode (0)) { rtx data_dupq = aarch64_expand_sve_dupq (NULL, mode, vq_reg); - return aarch64_convert_sve_data_to_pred (e.possible_target, - e.vector_mode (0), data_dupq); + return aarch64_convert_sve_data_to_pred (e.possible_target, data_dupq); } return aarch64_expand_sve_dupq (e.possible_target, mode, vq_reg); @@ -1259,9 +1276,10 @@ public: index = target; } - e.args[0] = gen_lowpart (VNx2DImode, e.args[0]); + e.args[0] = aarch64_sve_reinterpret (VNx2DImode, e.args[0]); e.args[1] = index; - return e.use_exact_insn (CODE_FOR_aarch64_sve_tblvnx2di); + rtx res = e.use_exact_insn (CODE_FOR_aarch64_sve_tblvnx2di); + return aarch64_sve_reinterpret (mode, res); } }; @@ -2857,7 +2875,10 @@ public: rtx expand (function_expander &e) const override { - return e.use_exact_insn (code_for_aarch64_sve_rev (e.vector_mode (0))); + auto mode = e.vector_mode (0); + return e.use_exact_insn (e.type_suffix (0).bool_p + ? code_for_aarch64_sve_rev_acle (mode) + : code_for_aarch64_sve_rev (mode)); } }; @@ -3248,7 +3269,7 @@ public: unsigned int unpacks = m_high_p ? UNSPEC_UNPACKSHI : UNSPEC_UNPACKSLO; insn_code icode; if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) - icode = code_for_aarch64_sve_punpk (unpacku, mode); + icode = code_for_aarch64_sve_punpk_acle (unpacku); else { int unspec = e.type_suffix (0).unsigned_p ? unpacku : unpacks; diff --git a/gcc/config/aarch64/aarch64-sve-builtins-functions.h b/gcc/config/aarch64/aarch64-sve-builtins-functions.h index 6f1c694..c05946d 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-functions.h +++ b/gcc/config/aarch64/aarch64-sve-builtins-functions.h @@ -630,7 +630,10 @@ public: rtx expand (function_expander &e) const override { - insn_code icode = code_for_aarch64_sve (m_unspec, e.vector_mode (0)); + auto mode = e.vector_mode (0); + insn_code icode = (e.type_suffix (0).bool_p + ? code_for_aarch64_sve_acle (m_unspec, mode) + : code_for_aarch64_sve (m_unspec, mode)); return e.use_exact_insn (icode); } @@ -838,7 +841,8 @@ public: machine_mode pred_mode = e.vector_mode (0); scalar_mode reg_mode = GET_MODE_INNER (e.vector_mode (1)); - return e.use_exact_insn (code_for_while (unspec, reg_mode, pred_mode)); + auto icode = code_for_aarch64_sve_while_acle (unspec, reg_mode, pred_mode); + return e.use_exact_insn (icode); } /* The unspec codes associated with signed and unsigned operations diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc index 73004a8..95c5ed8 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc @@ -881,7 +881,9 @@ public: { for (unsigned int i = 0; i < 2; ++i) e.args[i] = e.convert_to_pmode (e.args[i]); - return e.use_exact_insn (code_for_while (m_unspec, Pmode, e.gp_mode (0))); + auto icode = code_for_aarch64_sve_while_acle (m_unspec, Pmode, + e.gp_mode (0)); + return e.use_exact_insn (icode); } int m_unspec; diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index 01833a8..e394c9a 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -4593,7 +4593,27 @@ function_expander::expand () gcc_assert (args.last ()->mode == DImode); emit_move_insn (gen_rtx_REG (DImode, FPM_REGNUM), args.last ()); } - return base->expand (*this); + rtx result = base->expand (*this); + if (function_returns_void_p ()) + gcc_assert (result == const0_rtx); + else + { + auto expected_mode = result_mode (); + if (GET_MODE_CLASS (expected_mode) == MODE_INT) + /* Scalar integer constants don't store a mode. + + It's OK for a variable result to have a different mode from the + function return type. In particular, some functions that return int + expand into instructions that have a DImode result, with all 64 bits + of the DImode being well-defined (usually zero). */ + gcc_assert (CONST_SCALAR_INT_P (result) + || GET_MODE_CLASS (GET_MODE (result)) == MODE_INT); + else + /* In other cases, the return value should have the same mode + as the return type. */ + gcc_assert (GET_MODE (result) == expected_mode); + } + return result; } /* Return a structure type that contains a single field of type FIELD_TYPE. diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 80a3288..88d323a 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -2990,10 +2990,7 @@ (vec_duplicate:PRED_ALL (match_operand:QI 1 "register_operand")))] "TARGET_SVE" { - rtx tmp = gen_reg_rtx (DImode); - rtx op1 = gen_lowpart (DImode, operands[1]); - emit_insn (gen_ashldi3 (tmp, op1, gen_int_mode (63, DImode))); - emit_insn (gen_while_ultdi<mode> (operands[0], const0_rtx, tmp)); + aarch64_emit_sve_pred_vec_duplicate (<MODE>mode, operands[0], operands[1]); DONE; } ) @@ -8361,6 +8358,71 @@ } ) +;; Likewise, but yield a VNx16BI result regardless of the element width. +;; The .b case is equivalent to the above. +(define_expand "@aarch64_pred_cmp<cmp_op><mode>_acle" + [(parallel + [(set (match_operand:<VPRED> 0 "register_operand") + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (SVE_INT_CMP:<VPRED> + (match_operand:VNx16QI_ONLY 3 "register_operand") + (match_operand:VNx16QI_ONLY 4 "aarch64_sve_cmp_<sve_imm_con>_operand"))] + UNSPEC_PRED_Z)) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE" +) + +;; For wider elements, bitcast the predicate result to a VNx16BI and use +;; an (and ...) to indicate that only every second, fourth, or eighth bit +;; is set. +(define_expand "@aarch64_pred_cmp<cmp_op><mode>_acle" + [(parallel + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (SVE_INT_CMP:<VPRED> + (match_operand:SVE_FULL_HSDI 3 "register_operand") + (match_operand:SVE_FULL_HSDI 4 "aarch64_sve_cmp_<sve_imm_con>_operand"))] + UNSPEC_PRED_Z) + 0) + (match_dup 5))) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE" + { + operands[5] = aarch64_ptrue_all (GET_MODE_UNIT_SIZE (<MODE>mode)); + } +) + +(define_insn "*aarch64_pred_cmp<cmp_op><mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (SVE_INT_CMP:<VPRED> + (match_operand:SVE_FULL_HSDI 3 "register_operand") + (match_operand:SVE_FULL_HSDI 4 "aarch64_sve_cmp_<sve_imm_con>_operand"))] + UNSPEC_PRED_Z) + 0) + (match_operand:<VPRED> 5 "aarch64_ptrue_all_operand"))) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE" + {@ [ cons: =0 , 1 , 3 , 4 ; attrs: pred_clobber ] + [ &Upa , Upl, w , <sve_imm_con>; yes ] cmp<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, #%4 + [ ?Upl , 0 , w , <sve_imm_con>; yes ] ^ + [ Upa , Upl, w , <sve_imm_con>; no ] ^ + [ &Upa , Upl, w , w ; yes ] cmp<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype> + [ ?Upl , 0 , w , w ; yes ] ^ + [ Upa , Upl, w , w ; no ] ^ + } +) + ;; Predicated integer comparisons in which both the flag and predicate ;; results are interesting. (define_insn_and_rewrite "*cmp<cmp_op><mode>_cc" @@ -8402,6 +8464,49 @@ } ) +(define_insn_and_rewrite "*cmp<cmp_op><mode>_acle_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand 6) + (match_operand:SI 7 "aarch64_sve_ptrue_flag") + (SVE_INT_CMP:<VPRED> + (match_operand:SVE_FULL_HSDI 2 "register_operand") + (match_operand:SVE_FULL_HSDI 3 "aarch64_sve_cmp_<sve_imm_con>_operand"))] + UNSPEC_PRED_Z)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_dup 6) + (match_dup 7) + (SVE_INT_CMP:<VPRED> + (match_dup 2) + (match_dup 3))] + UNSPEC_PRED_Z) + 0) + (match_operand:<VPRED> 8 "aarch64_ptrue_all_operand")))] + "TARGET_SVE + && aarch64_sve_same_pred_for_ptest_p (&operands[4], &operands[6])" + {@ [ cons: =0 , 1 , 2 , 3 ; attrs: pred_clobber ] + [ &Upa , Upl, w , <sve_imm_con>; yes ] cmp<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, #%3 + [ ?Upl , 0 , w , <sve_imm_con>; yes ] ^ + [ Upa , Upl, w , <sve_imm_con>; no ] ^ + [ &Upa , Upl, w , w ; yes ] cmp<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.<Vetype> + [ ?Upl , 0 , w , w ; yes ] ^ + [ Upa , Upl, w , w ; no ] ^ + } + "&& !rtx_equal_p (operands[4], operands[6])" + { + operands[6] = copy_rtx (operands[4]); + operands[7] = operands[5]; + } +) + ;; Predicated integer comparisons in which only the flags result is ;; interesting. (define_insn_and_rewrite "*cmp<cmp_op><mode>_ptest" @@ -8467,14 +8572,52 @@ (clobber (reg:CC_NZC CC_REGNUM))])] ) +(define_insn_and_split "*cmp<cmp_op><mode>_acle_and" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa, Upa") + (and:VNx16BI + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand 4) + (const_int SVE_KNOWN_PTRUE) + (SVE_INT_CMP:<VPRED> + (match_operand:SVE_FULL_HSDI 2 "register_operand" "w, w") + (match_operand:SVE_FULL_HSDI 3 "aarch64_sve_cmp_<sve_imm_con>_operand" "<sve_imm_con>, w"))] + UNSPEC_PRED_Z) + 0) + (match_operand:VNx16BI 1 "register_operand" "Upl, Upl")) + (match_operand:<VPRED> 5 "aarch64_ptrue_all_operand"))) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE" + "#" + "&& 1" + [(parallel + [(set (match_dup 0) + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_dup 1) + (const_int SVE_MAYBE_NOT_PTRUE) + (SVE_INT_CMP:<VPRED> + (match_dup 2) + (match_dup 3))] + UNSPEC_PRED_Z) + 0) + (match_dup 5))) + (clobber (reg:CC_NZC CC_REGNUM))])] + { + operands[1] = gen_lowpart (<VPRED>mode, operands[1]); + } +) + ;; Predicated integer wide comparisons. (define_insn "@aarch64_pred_cmp<cmp_op><mode>_wide" [(set (match_operand:<VPRED> 0 "register_operand") (unspec:<VPRED> - [(match_operand:VNx16BI 1 "register_operand") + [(match_operand:<VPRED> 1 "register_operand") (match_operand:SI 2 "aarch64_sve_ptrue_flag") (unspec:<VPRED> - [(match_operand:SVE_FULL_BHSI 3 "register_operand") + [(match_operand:VNx16QI_ONLY 3 "register_operand") (match_operand:VNx2DI 4 "register_operand")] SVE_COND_INT_CMP_WIDE)] UNSPEC_PRED_Z)) @@ -8487,16 +8630,61 @@ } ) +(define_expand "@aarch64_pred_cmp<cmp_op><mode>_wide" + [(parallel + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:SVE_FULL_HSI 3 "register_operand") + (match_operand:VNx2DI 4 "register_operand")] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z) + 0) + (match_dup 5))) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE" + { + operands[5] = aarch64_ptrue_all (GET_MODE_UNIT_SIZE (<MODE>mode)); + } +) + +(define_insn "*aarch64_pred_cmp<cmp_op><mode>_wide" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:SVE_FULL_HSI 3 "register_operand") + (match_operand:VNx2DI 4 "register_operand")] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z) + 0) + (match_operand:<VPRED> 5 "aarch64_ptrue_all_operand"))) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE" + {@ [ cons: =0, 1 , 2, 3, 4; attrs: pred_clobber ] + [ &Upa , Upl, , w, w; yes ] cmp<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.d + [ ?Upl , 0 , , w, w; yes ] ^ + [ Upa , Upl, , w, w; no ] ^ + } +) + ;; Predicated integer wide comparisons in which both the flag and ;; predicate results are interesting. -(define_insn "*aarch64_pred_cmp<cmp_op><mode>_wide_cc" +(define_insn_and_rewrite "*aarch64_pred_cmp<cmp_op><mode>_wide_cc" [(set (reg:CC_NZC CC_REGNUM) (unspec:CC_NZC [(match_operand:VNx16BI 1 "register_operand") (match_operand 4) (match_operand:SI 5 "aarch64_sve_ptrue_flag") (unspec:<VPRED> - [(match_operand:VNx16BI 6 "register_operand") + [(match_operand:<VPRED> 6 "register_operand") (match_operand:SI 7 "aarch64_sve_ptrue_flag") (unspec:<VPRED> [(match_operand:SVE_FULL_BHSI 2 "register_operand") @@ -8520,18 +8708,65 @@ [ ?Upl , 0 , w, w, Upl; yes ] ^ [ Upa , Upl, w, w, Upl; no ] ^ } + "&& !rtx_equal_p (operands[4], operands[6])" + { + operands[6] = copy_rtx (operands[4]); + operands[7] = operands[5]; + } +) + +(define_insn_and_rewrite "*aarch64_pred_cmp<cmp_op><mode>_wide_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:<VPRED> 6 "register_operand") + (match_operand:SI 7 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:SVE_FULL_HSI 2 "register_operand") + (match_operand:VNx2DI 3 "register_operand")] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_dup 6) + (match_dup 7) + (unspec:<VPRED> + [(match_dup 2) + (match_dup 3)] + SVE_COND_INT_CMP_WIDE)] + UNSPEC_PRED_Z) + 0) + (match_operand:<VPRED> 8 "aarch64_ptrue_all_operand")))] + "TARGET_SVE + && aarch64_sve_same_pred_for_ptest_p (&operands[4], &operands[6])" + {@ [ cons: =0, 1 , 2, 3, 6 ; attrs: pred_clobber ] + [ &Upa , Upl, w, w, Upl; yes ] cmp<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.d + [ ?Upl , 0 , w, w, Upl; yes ] ^ + [ Upa , Upl, w, w, Upl; no ] ^ + } + "&& !rtx_equal_p (operands[4], operands[6])" + { + operands[6] = copy_rtx (operands[4]); + operands[7] = operands[5]; + } ) ;; Predicated integer wide comparisons in which only the flags result ;; is interesting. -(define_insn "*aarch64_pred_cmp<cmp_op><mode>_wide_ptest" +(define_insn_and_rewrite "*aarch64_pred_cmp<cmp_op><mode>_wide_ptest" [(set (reg:CC_NZC CC_REGNUM) (unspec:CC_NZC [(match_operand:VNx16BI 1 "register_operand") (match_operand 4) (match_operand:SI 5 "aarch64_sve_ptrue_flag") (unspec:<VPRED> - [(match_operand:VNx16BI 6 "register_operand") + [(match_operand:<VPRED> 6 "register_operand") (match_operand:SI 7 "aarch64_sve_ptrue_flag") (unspec:<VPRED> [(match_operand:SVE_FULL_BHSI 2 "register_operand") @@ -8547,6 +8782,11 @@ [ ?Upl , 0 , w, w, Upl; yes ] ^ [ Upa , Upl, w, w, Upl; no ] ^ } + "&& !rtx_equal_p (operands[4], operands[6])" + { + operands[6] = copy_rtx (operands[4]); + operands[7] = operands[5]; + } ) ;; ------------------------------------------------------------------------- @@ -8584,6 +8824,58 @@ "while<cmp_op>\t%0.<PRED_ALL:Vetype>, %<w>1, %<w>2" ) +;; Likewise, but yield a VNx16BI result regardless of the element width. +;; The .b case is equivalent to the above. +(define_expand "@aarch64_sve_while_<while_optab_cmp><GPI:mode><VNx16BI_ONLY:mode>_acle" + [(parallel + [(set (match_operand:VNx16BI_ONLY 0 "register_operand") + (unspec:VNx16BI_ONLY + [(const_int SVE_WHILE_B) + (match_operand:GPI 1 "aarch64_reg_or_zero") + (match_operand:GPI 2 "aarch64_reg_or_zero")] + SVE_WHILE)) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE" +) + +;; For wider elements, bitcast the predicate result to a VNx16BI and use +;; an (and ...) to indicate that only every second, fourth, or eighth bit +;; is set. +(define_expand "@aarch64_sve_while_<while_optab_cmp><GPI:mode><PRED_HSD:mode>_acle" + [(parallel + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:PRED_HSD + [(const_int SVE_WHILE_B) + (match_operand:GPI 1 "aarch64_reg_or_zero") + (match_operand:GPI 2 "aarch64_reg_or_zero")] + SVE_WHILE) + 0) + (match_dup 3))) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE" + { + operands[3] = aarch64_ptrue_all (<data_bytes>); + } +) + +(define_insn "*aarch64_sve_while_<while_optab_cmp><GPI:mode><PRED_HSD:mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:PRED_HSD + [(const_int SVE_WHILE_B) + (match_operand:GPI 1 "aarch64_reg_or_zero" "rZ") + (match_operand:GPI 2 "aarch64_reg_or_zero" "rZ")] + SVE_WHILE) + 0) + (match_operand:PRED_HSD 3 "aarch64_ptrue_all_operand"))) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE" + "while<cmp_op>\t%0.<PRED_HSD:Vetype>, %<w>1, %<w>2" +) + ;; The WHILE instructions set the flags in the same way as a PTEST with ;; a PTRUE GP. Handle the case in which both results are useful. The GP ;; operands to the PTEST aren't needed, so we allow them to be anything. @@ -8615,6 +8907,38 @@ } ) +(define_insn_and_rewrite "*while_<while_optab_cmp><GPI:mode><PRED_HSD:mode>_acle_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand 3) + (match_operand 4) + (const_int SVE_KNOWN_PTRUE) + (unspec:PRED_HSD + [(const_int SVE_WHILE_B) + (match_operand:GPI 1 "aarch64_reg_or_zero" "rZ") + (match_operand:GPI 2 "aarch64_reg_or_zero" "rZ")] + SVE_WHILE)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:PRED_HSD [(const_int SVE_WHILE_B) + (match_dup 1) + (match_dup 2)] + SVE_WHILE) + 0) + (match_operand:PRED_HSD 5 "aarch64_ptrue_all_operand")))] + "TARGET_SVE" + "while<cmp_op>\t%0.<PRED_HSD:Vetype>, %<w>1, %<w>2" + ;; Force the compiler to drop the unused predicate operand, so that we + ;; don't have an unnecessary PTRUE. + "&& (!CONSTANT_P (operands[3]) || !CONSTANT_P (operands[4]))" + { + operands[3] = CONSTM1_RTX (VNx16BImode); + operands[4] = CONSTM1_RTX (<PRED_HSD:MODE>mode); + } +) + ;; Same, but handle the case in which only the flags result is useful. (define_insn_and_rewrite "@while_<while_optab_cmp><GPI:mode><PRED_ALL:mode>_ptest" [(set (reg:CC_NZC CC_REGNUM) @@ -8685,6 +9009,43 @@ } ) +(define_expand "@aarch64_pred_fcm<cmp_op><mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "aarch64_predicate_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:SVE_F 3 "register_operand") + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")] + SVE_COND_FP_CMP_I0) + 0) + (match_dup 5)))] + "TARGET_SVE" + { + operands[5] = aarch64_ptrue_all (GET_MODE_UNIT_SIZE (<MODE>mode)); + } +) + +(define_insn "*aarch64_pred_fcm<cmp_op><mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "aarch64_predicate_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:SVE_F 3 "register_operand") + (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")] + SVE_COND_FP_CMP_I0) + 0) + (match_operand:<VPRED> 5 "aarch64_ptrue_all_operand")))] + "TARGET_SVE" + {@ [ cons: =0 , 1 , 3 , 4 ] + [ Upa , Upl , w , Dz ] fcm<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, #0.0 + [ Upa , Upl , w , w ] fcm<cmp_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype> + } +) + ;; Same for unordered comparisons. (define_insn "@aarch64_pred_fcmuo<mode>" [(set (match_operand:<VPRED> 0 "register_operand" "=Upa") @@ -8698,6 +9059,40 @@ "fcmuo\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype>" ) +(define_expand "@aarch64_pred_fcmuo<mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "aarch64_predicate_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:SVE_F 3 "register_operand") + (match_operand:SVE_F 4 "register_operand")] + UNSPEC_COND_FCMUO) + 0) + (match_dup 5)))] + "TARGET_SVE" + { + operands[5] = aarch64_ptrue_all (GET_MODE_UNIT_SIZE (<MODE>mode)); + } +) + +(define_insn "*aarch64_pred_fcmuo<mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "aarch64_predicate_operand" "Upl") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:SVE_F 3 "register_operand" "w") + (match_operand:SVE_F 4 "register_operand" "w")] + UNSPEC_COND_FCMUO) + 0) + (match_operand:<VPRED> 5 "aarch64_ptrue_all_operand")))] + "TARGET_SVE" + "fcmuo\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype>" +) + ;; Floating-point comparisons predicated on a PTRUE, with the results ANDed ;; with another predicate P. This does not have the same trapping behavior ;; as predicating the comparison itself on P, but it's a legitimate fold, @@ -8916,23 +9311,30 @@ ;; ------------------------------------------------------------------------- ;; Predicated floating-point absolute comparisons. -(define_expand "@aarch64_pred_fac<cmp_op><mode>" - [(set (match_operand:<VPRED> 0 "register_operand") - (unspec:<VPRED> - [(match_operand:<VPRED> 1 "register_operand") - (match_operand:SI 2 "aarch64_sve_ptrue_flag") - (unspec:SVE_FULL_F - [(match_dup 1) - (match_dup 2) - (match_operand:SVE_FULL_F 3 "register_operand")] - UNSPEC_COND_FABS) - (unspec:SVE_FULL_F - [(match_dup 1) - (match_dup 2) - (match_operand:SVE_FULL_F 4 "register_operand")] - UNSPEC_COND_FABS)] - SVE_COND_FP_ABS_CMP))] +(define_expand "@aarch64_pred_fac<cmp_op><mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:SVE_FULL_F + [(match_dup 1) + (match_dup 2) + (match_operand:SVE_FULL_F 3 "register_operand")] + UNSPEC_COND_FABS) + (unspec:SVE_FULL_F + [(match_dup 1) + (match_dup 2) + (match_operand:SVE_FULL_F 4 "register_operand")] + UNSPEC_COND_FABS)] + SVE_COND_FP_ABS_CMP) + 0) + (match_dup 5)))] "TARGET_SVE" + { + operands[5] = aarch64_ptrue_all (GET_MODE_UNIT_SIZE (<MODE>mode)); + } ) (define_insn_and_rewrite "*aarch64_pred_fac<cmp_op><mode>_relaxed" @@ -8981,6 +9383,30 @@ "fac<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.<Vetype>" ) +(define_insn "*aarch64_pred_fac<cmp_op><mode>_strict_acle" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand" "Upl") + (match_operand:SI 4 "aarch64_sve_ptrue_flag") + (unspec:SVE_FULL_F + [(match_dup 1) + (match_operand:SI 5 "aarch64_sve_gp_strictness") + (match_operand:SVE_FULL_F 2 "register_operand" "w")] + UNSPEC_COND_FABS) + (unspec:SVE_FULL_F + [(match_dup 1) + (match_operand:SI 6 "aarch64_sve_gp_strictness") + (match_operand:SVE_FULL_F 3 "register_operand" "w")] + UNSPEC_COND_FABS)] + SVE_COND_FP_ABS_CMP) + 0) + (match_operand:<VPRED> 7 "aarch64_ptrue_all_operand")))] + "TARGET_SVE" + "fac<cmp_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.<Vetype>" +) + ;; ------------------------------------------------------------------------- ;; ---- [PRED] Select ;; ------------------------------------------------------------------------- @@ -9429,7 +9855,30 @@ (unspec:PRED_ALL [(match_operand:PRED_ALL 1 "register_operand" "Upa")] UNSPEC_REV))] "TARGET_SVE" - "rev\t%0.<Vetype>, %1.<Vetype>") + "rev\t%0.<Vetype>, %1.<Vetype>" +) + +(define_expand "@aarch64_sve_rev<mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (unspec:VNx16BI + [(match_operand:VNx16BI 1 "register_operand") + (match_dup:PRED_ALL 2)] + UNSPEC_REV_PRED))] + "TARGET_SVE" + { + operands[2] = CONST0_RTX (<MODE>mode); + } +) + +(define_insn "*aarch64_sve_rev<mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (unspec:VNx16BI + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand:PRED_ALL 2 "aarch64_simd_imm_zero")] + UNSPEC_REV_PRED))] + "TARGET_SVE" + "rev\t%0.<Vetype>, %1.<Vetype>" +) ;; ------------------------------------------------------------------------- ;; ---- [PRED] Special-purpose binary permutes @@ -9454,18 +9903,39 @@ "<perm_insn>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>" ) -;; Special purpose permute used by the predicate generation instructions. -;; Unlike the normal permute patterns, these instructions operate on VNx16BI -;; regardless of the element size, so that all input and output bits are -;; well-defined. Operand 3 then indicates the size of the permute. -(define_insn "@aarch64_sve_trn1_conv<mode>" +;; Special-purpose permutes used by the ACLE intrinsics and predicate +;; generation instructions. Unlike the normal permute patterns, these +;; instructions operate on VNx16BI regardless of the element size, so that +;; all input and output bits are well-defined. Operand 3 then indicates +;; the size of the permute. +;; +;; To make generation easier, this pattern embeds the permute type as the +;; fourth operand to the unspec. On the one hand, this avoids overloading +;; unspecs like UNSPEC_ZIP1 to represent two different operations. On the +;; other hand, it avoids having a separate unspec for each variant, and +;; having to map from one kind of unspec to the other. +(define_expand "@aarch64_sve_<perm_insn><mode>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (unspec:VNx16BI [(match_operand:VNx16BI 1 "register_operand") + (match_operand:VNx16BI 2 "register_operand") + (match_dup:PRED_ALL 3) + (const_int PERMUTE)] + UNSPEC_PERMUTE_PRED))] + "TARGET_SVE" + { + operands[3] = CONST0_RTX (<MODE>mode); + } +) + +(define_insn "*aarch64_sve_<perm_insn><mode>_acle" [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") (unspec:VNx16BI [(match_operand:VNx16BI 1 "register_operand" "Upa") (match_operand:VNx16BI 2 "register_operand" "Upa") - (match_operand:PRED_ALL 3 "aarch64_simd_imm_zero")] - UNSPEC_TRN1_CONV))] + (match_operand:PRED_ALL 3 "aarch64_simd_imm_zero") + (const_int PERMUTE)] + UNSPEC_PERMUTE_PRED))] "TARGET_SVE" - "trn1\t%0.<PRED_ALL:Vetype>, %1.<PRED_ALL:Vetype>, %2.<PRED_ALL:Vetype>" + "<perm_insn>\t%0.<PRED_ALL:Vetype>, %1.<PRED_ALL:Vetype>, %2.<PRED_ALL:Vetype>" ) ;; ========================================================================= @@ -10454,6 +10924,34 @@ "punpk<perm_hilo>\t%0.h, %1.b" ) +(define_expand "@aarch64_sve_punpk<perm_hilo>_acle" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:VNx8BI + [(match_operand:VNx16BI 1 "register_operand")] + UNPACK_UNSIGNED) + 0) + (match_dup 2)))] + "TARGET_SVE" + { + operands[2] = aarch64_ptrue_all (2); + } +) + +(define_insn "*aarch64_sve_punpk<perm_hilo>_acle" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:VNx8BI + [(match_operand:VNx16BI 1 "register_operand" "Upa")] + UNPACK_UNSIGNED) + 0) + (match_operand:VNx8BI 2 "aarch64_ptrue_all_operand")))] + "TARGET_SVE" + "punpk<perm_hilo>\t%0.h, %1.b" +) + ;; ========================================================================= ;; == Vector partitioning ;; ========================================================================= @@ -10678,14 +11176,49 @@ ;; ------------------------------------------------------------------------- (define_insn "@aarch64_sve_<sve_pred_op><mode>" - [(set (match_operand:PRED_ALL 0 "register_operand" "=Upa") - (unspec:PRED_ALL - [(match_operand:PRED_ALL 1 "register_operand" "Upa") + [(set (match_operand:VNx16BI_ONLY 0 "register_operand" "=Upa") + (unspec:VNx16BI_ONLY + [(match_operand:VNx16BI_ONLY 1 "register_operand" "Upa") (match_operand:SI 2 "aarch64_sve_ptrue_flag") - (match_operand:PRED_ALL 3 "register_operand" "0")] + (match_operand:VNx16BI_ONLY 3 "register_operand" "0")] SVE_PITER)) (clobber (reg:CC_NZC CC_REGNUM))] - "TARGET_SVE && <max_elem_bits> >= <elem_bits>" + "TARGET_SVE" + "<sve_pred_op>\t%0.<Vetype>, %1, %0.<Vetype>" +) + +(define_expand "@aarch64_sve_<sve_pred_op><mode>" + [(parallel + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:PRED_HSD + [(match_operand:PRED_HSD 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:PRED_HSD 3 "register_operand")] + PNEXT_ONLY) + 0) + (match_dup 4))) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE" + { + operands[4] = aarch64_ptrue_all (<data_bytes>); + } +) + +(define_insn "*aarch64_sve_<sve_pred_op><mode>" + [(set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:PRED_HSD + [(match_operand:PRED_HSD 1 "register_operand" "Upa") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (match_operand:PRED_HSD 3 "register_operand" "0")] + PNEXT_ONLY) + 0) + (match_operand:PRED_HSD 4 "aarch64_ptrue_all_operand"))) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE" "<sve_pred_op>\t%0.<Vetype>, %1, %0.<Vetype>" ) @@ -10719,6 +11252,38 @@ } ) +(define_insn_and_rewrite "*aarch64_sve_<sve_pred_op><mode>_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upa") + (match_operand 2) + (match_operand:SI 3 "aarch64_sve_ptrue_flag") + (unspec:PRED_HSD + [(match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (match_operand:PRED_HSD 6 "register_operand" "0")] + PNEXT_ONLY)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:PRED_HSD + [(match_dup 4) + (match_dup 5) + (match_dup 6)] + PNEXT_ONLY) + 0) + (match_operand:PRED_HSD 7 "aarch64_ptrue_all_operand")))] + "TARGET_SVE + && aarch64_sve_same_pred_for_ptest_p (&operands[2], &operands[4])" + "<sve_pred_op>\t%0.<Vetype>, %1, %0.<Vetype>" + "&& !rtx_equal_p (operands[2], operands[4])" + { + operands[4] = operands[2]; + operands[5] = operands[3]; + } +) + ;; Same, but with only the flags result being interesting. (define_insn_and_rewrite "*aarch64_sve_<sve_pred_op><mode>_ptest" [(set (reg:CC_NZC CC_REGNUM) diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md index 31bdd85..a4c3257 100644 --- a/gcc/config/aarch64/aarch64-sve2.md +++ b/gcc/config/aarch64/aarch64-sve2.md @@ -4068,8 +4068,8 @@ [(match_operand:<VPRED> 1 "register_operand") (match_operand:SI 2 "aarch64_sve_ptrue_flag") (unspec:<VPRED> - [(match_operand:SVE_FULL_BHI 3 "register_operand") - (match_operand:SVE_FULL_BHI 4 "register_operand")] + [(match_operand:VNx16QI_ONLY 3 "register_operand") + (match_operand:VNx16QI_ONLY 4 "register_operand")] SVE2_MATCH)] UNSPEC_PRED_Z)) (clobber (reg:CC_NZC CC_REGNUM))] @@ -4081,6 +4081,51 @@ } ) +(define_expand "@aarch64_pred_<sve_int_op><mode>" + [(parallel + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:VNx8HI_ONLY 3 "register_operand") + (match_operand:VNx8HI_ONLY 4 "register_operand")] + SVE2_MATCH)] + UNSPEC_PRED_Z) + 0) + (match_dup 5))) + (clobber (reg:CC_NZC CC_REGNUM))])] + "TARGET_SVE2 && TARGET_NON_STREAMING" + { + operands[5] = aarch64_ptrue_all (GET_MODE_UNIT_SIZE (<MODE>mode)); + } +) + +(define_insn "*aarch64_pred_<sve_int_op><mode>" + [(set (match_operand:VNx16BI 0 "register_operand") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_operand:<VPRED> 1 "register_operand") + (match_operand:SI 2 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:VNx8HI_ONLY 3 "register_operand") + (match_operand:VNx8HI_ONLY 4 "register_operand")] + SVE2_MATCH)] + UNSPEC_PRED_Z) + 0) + (match_operand:<VPRED> 5 "aarch64_ptrue_all_operand"))) + (clobber (reg:CC_NZC CC_REGNUM))] + "TARGET_SVE2 && TARGET_NON_STREAMING" + {@ [ cons: =0, 1 , 3, 4; attrs: pred_clobber ] + [ &Upa , Upl, w, w; yes ] <sve_int_op>\t%0.<Vetype>, %1/z, %3.<Vetype>, %4.<Vetype> + [ ?Upl , 0 , w, w; yes ] ^ + [ Upa , Upl, w, w; no ] ^ + } +) + ;; Predicated string matching in which both the flag and predicate results ;; are interesting. (define_insn_and_rewrite "*aarch64_pred_<sve_int_op><mode>_cc" @@ -4118,6 +4163,45 @@ } ) +(define_insn_and_rewrite "*aarch64_pred_<sve_int_op><mode>_cc" + [(set (reg:CC_NZC CC_REGNUM) + (unspec:CC_NZC + [(match_operand:VNx16BI 1 "register_operand" "Upl") + (match_operand 4) + (match_operand:SI 5 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand 6) + (match_operand:SI 7 "aarch64_sve_ptrue_flag") + (unspec:<VPRED> + [(match_operand:VNx8HI_ONLY 2 "register_operand" "w") + (match_operand:VNx8HI_ONLY 3 "register_operand" "w")] + SVE2_MATCH)] + UNSPEC_PRED_Z)] + UNSPEC_PTEST)) + (set (match_operand:VNx16BI 0 "register_operand" "=Upa") + (and:VNx16BI + (subreg:VNx16BI + (unspec:<VPRED> + [(match_dup 6) + (match_dup 7) + (unspec:<VPRED> + [(match_dup 2) + (match_dup 3)] + SVE2_MATCH)] + UNSPEC_PRED_Z) + 0) + (match_operand:<VPRED> 8 "aarch64_ptrue_all_operand")))] + "TARGET_SVE2 + && TARGET_NON_STREAMING + && aarch64_sve_same_pred_for_ptest_p (&operands[4], &operands[6])" + "<sve_int_op>\t%0.<Vetype>, %1/z, %2.<Vetype>, %3.<Vetype>" + "&& !rtx_equal_p (operands[4], operands[6])" + { + operands[6] = copy_rtx (operands[4]); + operands[7] = operands[5]; + } +) + ;; Predicated string matching in which only the flags result is interesting. (define_insn_and_rewrite "*aarch64_pred_<sve_int_op><mode>_ptest" [(set (reg:CC_NZC CC_REGNUM) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index f4a2062..d30c9c7 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -3962,16 +3962,24 @@ aarch64_sve_emit_masked_fp_pred (machine_mode data_mode, rtx pred) /* Emit a comparison CMP between OP0 and OP1, both of which have mode DATA_MODE, and return the result in a predicate of mode PRED_MODE. - Use TARGET as the target register if nonnull and convenient. */ + Use TARGET as the target register if nonnull and convenient. + + PRED_MODE can be either VNx16BI or the natural predicate mode for + DATA_MODE. */ static rtx aarch64_sve_emit_int_cmp (rtx target, machine_mode pred_mode, rtx_code cmp, machine_mode data_mode, rtx op1, rtx op2) { - insn_code icode = code_for_aarch64_pred_cmp (cmp, data_mode); + auto src_pred_mode = aarch64_sve_pred_mode (data_mode); + insn_code icode; + if (known_eq (GET_MODE_NUNITS (pred_mode), GET_MODE_NUNITS (data_mode))) + icode = code_for_aarch64_pred_cmp (cmp, data_mode); + else + icode = code_for_aarch64_pred_cmp_acle (cmp, data_mode); expand_operand ops[5]; create_output_operand (&ops[0], target, pred_mode); - create_input_operand (&ops[1], CONSTM1_RTX (pred_mode), pred_mode); + create_input_operand (&ops[1], CONSTM1_RTX (src_pred_mode), src_pred_mode); create_integer_operand (&ops[2], SVE_KNOWN_PTRUE); create_input_operand (&ops[3], op1, data_mode); create_input_operand (&ops[4], op2, data_mode); @@ -3979,15 +3987,14 @@ aarch64_sve_emit_int_cmp (rtx target, machine_mode pred_mode, rtx_code cmp, return ops[0].value; } -/* Use a comparison to convert integer vector SRC into MODE, which is - the corresponding SVE predicate mode. Use TARGET for the result - if it's nonnull and convenient. */ +/* Use a comparison to convert integer vector SRC into VNx16BI. + Use TARGET for the result if it's nonnull and convenient. */ rtx -aarch64_convert_sve_data_to_pred (rtx target, machine_mode mode, rtx src) +aarch64_convert_sve_data_to_pred (rtx target, rtx src) { machine_mode src_mode = GET_MODE (src); - return aarch64_sve_emit_int_cmp (target, mode, NE, src_mode, + return aarch64_sve_emit_int_cmp (target, VNx16BImode, NE, src_mode, src, CONST0_RTX (src_mode)); } @@ -6069,9 +6076,9 @@ aarch64_sve_move_pred_via_while (rtx target, machine_mode mode, unsigned int vl) { rtx limit = force_reg (DImode, gen_int_mode (vl, DImode)); - target = aarch64_target_reg (target, mode); - emit_insn (gen_while (UNSPEC_WHILELO, DImode, mode, - target, const0_rtx, limit)); + target = aarch64_target_reg (target, VNx16BImode); + emit_insn (gen_aarch64_sve_while_acle (UNSPEC_WHILELO, DImode, mode, + target, const0_rtx, limit)); return target; } @@ -6217,8 +6224,7 @@ aarch64_expand_sve_const_pred_trn (rtx target, rtx_vector_builder &builder, operands but permutes them as though they had mode MODE. */ machine_mode mode = aarch64_sve_pred_mode (permute_size).require (); target = aarch64_target_reg (target, GET_MODE (a)); - rtx type_reg = CONST0_RTX (mode); - emit_insn (gen_aarch64_sve_trn1_conv (mode, target, a, b, type_reg)); + emit_insn (gen_aarch64_sve_acle (UNSPEC_TRN1, mode, target, a, b)); return target; } @@ -6300,8 +6306,7 @@ aarch64_expand_sve_const_pred (rtx target, rtx_vector_builder &builder) for (unsigned int i = 0; i < builder.encoded_nelts (); ++i) int_builder.quick_push (INTVAL (builder.elt (i)) ? constm1_rtx : const0_rtx); - return aarch64_convert_sve_data_to_pred (target, VNx16BImode, - int_builder.build ()); + return aarch64_convert_sve_data_to_pred (target, int_builder.build ()); } /* Set DEST to immediate IMM. */ @@ -6753,6 +6758,27 @@ aarch64_split_sve_subreg_move (rtx dest, rtx ptrue, rtx src) dest, ptrue, src)); } +/* Set predicate register DEST such that every element has the scalar + boolean value in SRC, with any nonzero source counting as "true". + MODE is a MODE_VECTOR_BOOL that determines the element size; + DEST can have this mode or VNx16BImode. In the latter case, + the upper bits of each element are defined to be zero, as for + the .H, .S, and .D forms of PTRUE. */ + +void +aarch64_emit_sve_pred_vec_duplicate (machine_mode mode, rtx dest, rtx src) +{ + rtx tmp = gen_reg_rtx (DImode); + emit_insn (gen_ashldi3 (tmp, gen_lowpart (DImode, src), + gen_int_mode (63, DImode))); + if (GET_MODE (dest) == VNx16BImode) + emit_insn (gen_aarch64_sve_while_acle (UNSPEC_WHILELO, DImode, mode, + dest, const0_rtx, tmp)); + else + emit_insn (gen_while (UNSPEC_WHILELO, DImode, mode, + dest, const0_rtx, tmp)); +} + static bool aarch64_function_ok_for_sibcall (tree, tree exp) { diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index a4ae685..dc2be81 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -280,6 +280,7 @@ UNSPEC_PACIBSP UNSPEC_PRLG_STK UNSPEC_REV + UNSPEC_REV_PRED UNSPEC_SADALP UNSPEC_SCVTF UNSPEC_SET_LANE diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index 8533912..8f8237e 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -455,6 +455,7 @@ (define_mode_iterator VCVTFPM [V4HF V8HF V4SF]) ;; Iterators for single modes, for "@" patterns. +(define_mode_iterator VNx16BI_ONLY [VNx16BI]) (define_mode_iterator VNx16QI_ONLY [VNx16QI]) (define_mode_iterator VNx16SI_ONLY [VNx16SI]) (define_mode_iterator VNx8HI_ONLY [VNx8HI]) @@ -930,7 +931,6 @@ UNSPEC_UZP2Q ; Used in aarch64-sve.md. UNSPEC_ZIP1Q ; Used in aarch64-sve.md. UNSPEC_ZIP2Q ; Used in aarch64-sve.md. - UNSPEC_TRN1_CONV ; Used in aarch64-sve.md. UNSPEC_COND_CMPEQ_WIDE ; Used in aarch64-sve.md. UNSPEC_COND_CMPGE_WIDE ; Used in aarch64-sve.md. UNSPEC_COND_CMPGT_WIDE ; Used in aarch64-sve.md. @@ -1185,6 +1185,9 @@ UNSPEC_LUTI2 ; Used in aarch64-simd.md. UNSPEC_LUTI4 ; Used in aarch64-simd.md. + ;; All used in aarch64-sve.md + UNSPEC_PERMUTE_PRED + ;; All used in aarch64-sve2.md UNSPEC_ADDQV UNSPEC_ANDQV @@ -3877,6 +3880,8 @@ (define_int_iterator SVE_PITER [UNSPEC_PFIRST UNSPEC_PNEXT]) +(define_int_iterator PNEXT_ONLY [UNSPEC_PNEXT]) + (define_int_iterator MATMUL [UNSPEC_SMATMUL UNSPEC_UMATMUL UNSPEC_USMATMUL]) diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md index 32056da..4d5d57f 100644 --- a/gcc/config/aarch64/predicates.md +++ b/gcc/config/aarch64/predicates.md @@ -1078,3 +1078,9 @@ (define_predicate "aarch64_maskload_else_operand" (and (match_code "const_vector") (match_test "op == CONST0_RTX (GET_MODE (op))"))) + +;; Check for a VNx16BI predicate that is a canonical PTRUE for the given +;; predicate mode. +(define_special_predicate "aarch64_ptrue_all_operand" + (and (match_code "const_vector") + (match_test "aarch64_ptrue_all_mode (op) == mode"))) diff --git a/gcc/config/avr/avr-dimode.md b/gcc/config/avr/avr-dimode.md index 903bfbf..66ba5a9 100644 --- a/gcc/config/avr/avr-dimode.md +++ b/gcc/config/avr/avr-dimode.md @@ -101,10 +101,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8 ACC_A) - (plus:ALL8 (reg:ALL8 ACC_A) - (reg:ALL8 ACC_B))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*add<mode>3_insn" [(set (reg:ALL8 ACC_A) @@ -122,10 +120,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:DI ACC_A) - (plus:DI (reg:DI ACC_A) - (sign_extend:DI (reg:QI REG_X)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*adddi3_const8_insn" [(set (reg:DI ACC_A) @@ -146,12 +142,10 @@ (match_operand:ALL8 0 "const_operand" "n Ynn")))] "avr_have_dimode && !s8_operand (operands[0], VOIDmode)" - "#" - "&& reload_completed" - [(parallel [(set (reg:ALL8 ACC_A) - (plus:ALL8 (reg:ALL8 ACC_A) - (match_dup 0))) - (clobber (reg:CC REG_CC))])]) + "#" + "&& reload_completed" + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*add<mode>3_const_insn" [(set (reg:ALL8 ACC_A) @@ -211,10 +205,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8 ACC_A) - (minus:ALL8 (reg:ALL8 ACC_A) - (reg:ALL8 ACC_B))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sub<mode>3_insn" [(set (reg:ALL8 ACC_A) @@ -236,10 +228,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8 ACC_A) - (minus:ALL8 (reg:ALL8 ACC_A) - (match_dup 0))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sub<mode>3_const_insn" [(set (reg:ALL8 ACC_A) @@ -288,10 +278,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8S ACC_A) - (ss_addsub:ALL8S (reg:ALL8S ACC_A) - (reg:ALL8S ACC_B))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3_insn" [(set (reg:ALL8S ACC_A) @@ -309,10 +297,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8S ACC_A) - (ss_addsub:ALL8S (reg:ALL8S ACC_A) - (match_dup 0))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3_const_insn" [(set (reg:ALL8S ACC_A) @@ -361,10 +347,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8U ACC_A) - (us_addsub:ALL8U (reg:ALL8U ACC_A) - (reg:ALL8U ACC_B))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3_insn" [(set (reg:ALL8U ACC_A) @@ -382,10 +366,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8U ACC_A) - (us_addsub:ALL8U (reg:ALL8U ACC_A) - (match_operand:ALL8U 0 "const_operand" "n Ynn"))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3_const_insn" [(set (reg:ALL8U ACC_A) @@ -421,9 +403,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:DI ACC_A) - (neg:DI (reg:DI ACC_A))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*negdi2_insn" [(set (reg:DI ACC_A) @@ -500,7 +481,7 @@ "avr_have_dimode" "#" "&& reload_completed" - [(const_int 0)] + [(scratch)] { emit_insn (gen_compare_<mode>2 ()); emit_jump_insn (gen_conditional_jump (operands[0], operands[1])); @@ -529,7 +510,7 @@ "avr_have_dimode" "#" "&& reload_completed" - [(const_int 0)] + [(scratch)] { emit_insn (gen_compare_const8_di2 ()); emit_jump_insn (gen_conditional_jump (operands[0], operands[1])); @@ -556,7 +537,7 @@ && !s8_operand (operands[1], VOIDmode)" "#" "&& reload_completed" - [(const_int 0)] + [(scratch)] { emit_insn (gen_compare_const_<mode>2 (operands[1], operands[3])); emit_jump_insn (gen_conditional_jump (operands[0], operands[2])); @@ -629,10 +610,8 @@ "avr_have_dimode" "#" "&& reload_completed" - [(parallel [(set (reg:ALL8 ACC_A) - (di_shifts:ALL8 (reg:ALL8 ACC_A) - (reg:QI 16))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3_insn" [(set (reg:ALL8 ACC_A) @@ -674,14 +653,10 @@ (clobber (reg:HI REG_Z))] "avr_have_dimode && AVR_HAVE_MUL" - "#" - "&& reload_completed" - [(parallel [(set (reg:DI ACC_A) - (mult:DI (any_extend:DI (reg:SI 18)) - (any_extend:DI (reg:SI 22)))) - (clobber (reg:HI REG_X)) - (clobber (reg:HI REG_Z)) - (clobber (reg:CC REG_CC))])]) + "#" + "&& reload_completed" + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<extend_u>mulsidi3_insn" [(set (reg:DI ACC_A) diff --git a/gcc/config/avr/avr-fixed.md b/gcc/config/avr/avr-fixed.md index ce46beb..22061fc 100644 --- a/gcc/config/avr/avr-fixed.md +++ b/gcc/config/avr/avr-fixed.md @@ -62,10 +62,8 @@ "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (fract_convert:FIXED_A - (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fract<FIXED_B:mode><FIXED_A:mode>2" [(set (match_operand:FIXED_A 0 "register_operand" "=r") @@ -86,10 +84,8 @@ "<FIXED_B:MODE>mode != <FIXED_A:MODE>mode" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (unsigned_fract_convert:FIXED_A - (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fractuns<FIXED_B:mode><FIXED_A:mode>2" [(set (match_operand:FIXED_A 0 "register_operand" "=r") @@ -124,10 +120,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ss_addsub:ALL124S (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3" [(set (match_operand:ALL124S 0 "register_operand" "=??d,d") @@ -149,10 +143,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (us_addsub:ALL124U (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>3" [(set (match_operand:ALL124U 0 "register_operand" "=??r,d") @@ -189,9 +181,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ss_neg:QQ (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ssnegqq2" [(set (match_operand:QQ 0 "register_operand" "=r") @@ -207,9 +198,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ss_abs:QQ (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ssabsqq2" [(set (match_operand:QQ 0 "register_operand" "=r") @@ -241,9 +231,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL2S 24) - (ss_abs_neg:ALL2S (reg:ALL2S 24))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>2" [(set (reg:ALL2S 24) @@ -261,9 +250,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL4S 22) - (ss_abs_neg:ALL4S (reg:ALL4S 22))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code_stdname><mode>2" [(set (reg:ALL4S 22) @@ -296,10 +284,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:QQ (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulqq3_enh" [(set (match_operand:QQ 0 "register_operand" "=r") @@ -317,10 +303,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:UQQ (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*muluqq3_enh" [(set (match_operand:UQQ 0 "register_operand" "=r") @@ -377,12 +361,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:QQ 23) - (mult:QQ (reg:QQ 24) - (reg:QQ 25))) - (clobber (reg:QI 22)) - (clobber (reg:HI 24)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulqq3.call" [(set (reg:QQ 23) @@ -425,11 +405,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:ALL2QA 24) - (mult:ALL2QA (reg:ALL2QA 18) - (reg:ALL2QA 26))) - (clobber (reg:HI 22)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mul<mode>3.call" [(set (reg:ALL2QA 24) @@ -468,10 +445,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:ALL4A 24) - (mult:ALL4A (reg:ALL4A 16) - (reg:ALL4A 20))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mul<mode>3.call" [(set (reg:ALL4A 24) @@ -514,11 +489,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL1Q 24) - (usdiv:ALL1Q (reg:ALL1Q 25) - (reg:ALL1Q 22))) - (clobber (reg:QI 25)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code><mode>3.call" [(set (reg:ALL1Q 24) @@ -560,12 +532,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL2QA 24) - (usdiv:ALL2QA (reg:ALL2QA 26) - (reg:ALL2QA 22))) - (clobber (reg:HI 26)) - (clobber (reg:QI 21)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code><mode>3.call" [(set (reg:ALL2QA 24) @@ -608,12 +576,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL4A 22) - (usdiv:ALL4A (reg:ALL4A 24) - (reg:ALL4A 18))) - (clobber (reg:HI 26)) - (clobber (reg:HI 30)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<code><mode>3.call" [(set (reg:ALL4A 22) @@ -684,12 +648,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (unspec:ALL124QA [(match_dup 1) - (match_dup 2) - (const_int 0)] - UNSPEC_ROUND)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*round<mode>3_const" [(set (match_operand:ALL124QA 0 "register_operand" "=d") @@ -714,11 +674,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL1Q 24) - (unspec:ALL1Q [(reg:ALL1Q 22) - (reg:QI 24)] UNSPEC_ROUND)) - (clobber (reg:ALL1Q 22)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*round<mode>3.libgcc" [(set (reg:ALL1Q 24) @@ -740,11 +697,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL2QA 24) - (unspec:ALL2QA [(reg:ALL2QA 22) - (reg:QI 24)] UNSPEC_ROUND)) - (clobber (reg:ALL2QA 22)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*round<mode>3.libgcc" [(set (reg:ALL2QA 24) @@ -766,11 +720,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:ALL4QA 22) - (unspec:ALL4QA [(reg:ALL4QA 18) - (reg:QI 24)] UNSPEC_ROUND)) - (clobber (reg:ALL4QA 18)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*round<mode>3.libgcc" [(set (reg:ALL4QA 22) diff --git a/gcc/config/avr/avr-log.cc b/gcc/config/avr/avr-log.cc index fadb3ca..972ba6b 100644 --- a/gcc/config/avr/avr-log.cc +++ b/gcc/config/avr/avr-log.cc @@ -373,7 +373,6 @@ avr_log_set_avr_log (void) SET_DUMP_DETAIL (insn_addresses); SET_DUMP_DETAIL (legitimate_address_p); SET_DUMP_DETAIL (legitimize_address); - SET_DUMP_DETAIL (legitimize_reload_address); SET_DUMP_DETAIL (progmem); SET_DUMP_DETAIL (rtx_costs); diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 9aa00d3..8ba1945 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -146,7 +146,6 @@ extern void out_shift_with_cnt (const char *templ, rtx_insn *insn, extern enum reg_class avr_mode_code_base_reg_class (machine_mode, addr_space_t, rtx_code, rtx_code); extern bool avr_regno_mode_code_ok_for_base_p (int, machine_mode, addr_space_t, rtx_code, rtx_code); extern rtx avr_incoming_return_addr_rtx (void); -extern rtx avr_legitimize_reload_address (rtx*, machine_mode, int, int, int, int, rtx (*)(rtx,int)); extern bool avr_adiw_reg_p (rtx); extern bool avr_mem_flash_p (rtx); extern bool avr_mem_flashx_p (rtx); @@ -241,7 +240,6 @@ typedef struct unsigned insn_addresses :1; unsigned legitimate_address_p :1; unsigned legitimize_address :1; - unsigned legitimize_reload_address :1; unsigned progmem :1; unsigned rtx_costs :1; } avr_log_t; diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 2afea95..ae49d4d 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -453,13 +453,6 @@ avr_ld_regno_p (int regno) } -static bool -ra_in_progress () -{ - return avropt_lra_p ? lra_in_progress : reload_in_progress; -} - - /* Set `avr_arch' as specified by `-mmcu='. Return true on success. */ @@ -2347,8 +2340,8 @@ avr_legitimate_address_p (machine_mode mode, rtx x, bool strict) if (avr_log.legitimate_address_p) { avr_edump ("\n%?: ret=%d, mode=%m strict=%d " - "reload_completed=%d ra_in_progress=%d %s:", - ok, mode, strict, reload_completed, ra_in_progress (), + "reload_completed=%d lra_in_progress=%d %s:", + ok, mode, strict, reload_completed, lra_in_progress, reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS @@ -2418,88 +2411,6 @@ avr_legitimize_address (rtx x, rtx oldx, machine_mode mode) } -/* Implement `LEGITIMIZE_RELOAD_ADDRESS'. */ -/* This will allow register R26/27 to be used where it is no worse than normal - base pointers R28/29 or R30/31. For example, if base offset is greater - than 63 bytes or for R++ or --R addressing. */ - -rtx -avr_legitimize_reload_address (rtx *px, machine_mode mode, int opnum, - int type, int addr_type, int /*ind_levels*/, - rtx (*mk_memloc)(rtx,int)) -{ - rtx x = *px; - - if (avr_log.legitimize_reload_address) - avr_edump ("\n%?:%m %r\n", mode, x); - - if (1 && (GET_CODE (x) == POST_INC - || GET_CODE (x) == PRE_DEC)) - { - push_reload (XEXP (x, 0), XEXP (x, 0), &XEXP (x, 0), &XEXP (x, 0), - POINTER_REGS, GET_MODE (x), GET_MODE (x), 0, 0, - opnum, RELOAD_OTHER); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.1 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, XEXP (x, 0), XEXP (x, 0)); - - return x; - } - - if (GET_CODE (x) == PLUS - && REG_P (XEXP (x, 0)) - && reg_equiv_constant (REGNO (XEXP (x, 0))) == 0 - && CONST_INT_P (XEXP (x, 1)) - && INTVAL (XEXP (x, 1)) >= 1) - { - bool fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode); - - if (fit) - { - if (reg_equiv_address (REGNO (XEXP (x, 0))) != 0) - { - int regno = REGNO (XEXP (x, 0)); - rtx mem = mk_memloc (x, regno); - - push_reload (XEXP (mem, 0), NULL_RTX, &XEXP (mem, 0), NULL, - POINTER_REGS, Pmode, VOIDmode, 0, 0, - 1, (enum reload_type) addr_type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, XEXP (mem, 0), NULL_RTX); - - push_reload (mem, NULL_RTX, &XEXP (x, 0), NULL, - BASE_POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type) type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.2 = %R\n IN = %r\n OUT = %r\n", - BASE_POINTER_REGS, mem, NULL_RTX); - - return x; - } - } - else if (! (frame_pointer_needed - && XEXP (x, 0) == frame_pointer_rtx)) - { - push_reload (x, NULL_RTX, px, NULL, - POINTER_REGS, GET_MODE (x), VOIDmode, 0, 0, - opnum, (enum reload_type) type); - - if (avr_log.legitimize_reload_address) - avr_edump (" RCLASS.3 = %R\n IN = %r\n OUT = %r\n", - POINTER_REGS, x, NULL_RTX); - - return x; - } - } - - return NULL_RTX; -} - - /* Helper function to print assembler resp. track instruction sequence lengths. Always return "". @@ -12847,6 +12758,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code, return true; case SIGN_EXTEND: + if (GET_CODE (XEXP (x, 0)) == ASHIFT + && CONST_INT_P (XEXP (XEXP (x, 0), 1))) + { + // "*sext.ashift<QIPSI:mode><HISI:mode>2_split" + int m0 = GET_MODE_SIZE (GET_MODE (XEXP (x, 0))); + int m1 = GET_MODE_SIZE (mode); + *total = COSTS_N_INSNS (m0 * INTVAL (XEXP (XEXP (x, 0), 1)) + + m1 - m0); + return true; + } *total = COSTS_N_INSNS (n_bytes + 2 - GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))); *total += avr_operand_rtx_cost (XEXP (x, 0), GET_MODE (XEXP (x, 0)), @@ -13959,8 +13880,8 @@ extra_constraint_Q (rtx x) || xx == arg_pointer_rtx); if (avr_log.constraints) - avr_edump ("\n%?=%d reload_completed=%d ra_in_progress=%d\n %r\n", - ok, reload_completed, ra_in_progress (), x); + avr_edump ("\n%?=%d reload_completed=%d lra_in_progress=%d\n %r\n", + ok, reload_completed, lra_in_progress, x); } return ok; @@ -14165,17 +14086,6 @@ avr_hard_regno_mode_ok (unsigned int regno, machine_mode mode) if (GET_MODE_SIZE (mode) == 1) return true; - /* FIXME: Ideally, the following test is not needed. - However, it turned out that it can reduce the number - of spill fails. AVR and it's poor endowment with - address registers is extreme stress test for reload. */ - - if (GET_MODE_SIZE (mode) >= 4 - && regno + GET_MODE_SIZE (mode) >= REG_30 - // This problem only concerned the old reload. - && ! avropt_lra_p) - return false; - /* All modes larger than 8 bits should start in an even register. */ return !(regno & 1); @@ -14937,8 +14847,8 @@ avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict, if (avr_log.legitimate_address_p) { avr_edump ("\n%?: ret=%b, mode=%m strict=%d " - "reload_completed=%d ra_in_progress=%d %s:", - ok, mode, strict, reload_completed, ra_in_progress (), + "reload_completed=%d lra_in_progress=%d %s:", + ok, mode, strict, reload_completed, lra_in_progress, reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS @@ -16716,15 +16626,6 @@ avr_unwind_word_mode () return Pmode; } - -/* Implement `TARGET_LRA_P'. */ - -static bool -avr_use_lra_p () -{ - return avropt_lra_p; -} - /* Initialize the GCC target structure. */ @@ -16866,9 +16767,6 @@ avr_use_lra_p () #undef TARGET_CONVERT_TO_TYPE #define TARGET_CONVERT_TO_TYPE avr_convert_to_type -#undef TARGET_LRA_P -#define TARGET_LRA_P avr_use_lra_p - #undef TARGET_ADDR_SPACE_SUBSET_P #define TARGET_ADDR_SPACE_SUBSET_P avr_addr_space_subset_p diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index cb818c3..335f9fa5 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -309,12 +309,6 @@ enum reg_class { #define STATIC_CHAIN_REGNUM ((AVR_TINY) ? 18 :2) -#define RELOAD_ELIMINABLE_REGS { \ - { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ - { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \ - { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ - { FRAME_POINTER_REGNUM + 1, STACK_POINTER_REGNUM + 1 } } - #define ELIMINABLE_REGS \ { \ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ @@ -358,18 +352,6 @@ typedef struct avr_args #define MAX_REGS_PER_ADDRESS 1 -#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_L,WIN) \ - do { \ - rtx new_x = avr_legitimize_reload_address (&(X), MODE, OPNUM, TYPE, \ - ADDR_TYPE (TYPE), \ - IND_L, make_memloc); \ - if (new_x) \ - { \ - X = new_x; \ - goto WIN; \ - } \ - } while (0) - /* We increase branch costs after reload in order to keep basic-block reordering from introducing out-of-line jumps and to prefer fall-through edges instead. The default branch costs are 0, mainly because otherwise diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index f8bbdc7..60b1f60 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -574,9 +574,8 @@ && REG_Z == REGNO (XEXP (operands[0], 0))" "#" "&& reload_completed" - [(parallel [(set (reg:MOVMODE 22) - (match_dup 0)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*load_<mode>_libgcc" [(set (reg:MOVMODE 22) @@ -716,14 +715,8 @@ || avr_load_libgcc_insn_p (insn, ADDR_SPACE_FLASHX, true)" "#" "&& reload_completed" - [(parallel [(set (reg:MOVMODE REG_22) - (match_dup 0)) - (clobber (reg:QI REG_21)) - (clobber (reg:HI REG_Z)) - (clobber (reg:CC REG_CC))])] - { - operands[0] = SET_SRC (single_set (curr_insn)); - }) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fxload_<mode>_libgcc" [(set (reg:MOVMODE REG_22) @@ -853,9 +846,8 @@ || reg_or_0_operand (operands[1], <MODE>mode)" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (match_dup 1)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) ;; "movqi_insn" ;; "movqq_insn" "movuqq_insn" @@ -964,9 +956,8 @@ || reg_or_0_operand (operands[1], <MODE>mode)" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (match_dup 1)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mov<mode>" [(set (match_operand:ALL2 0 "nonimmediate_operand" "=r,r ,r,m ,d,*r,q,r") @@ -1137,9 +1128,8 @@ || const0_rtx == operands[1]" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (match_dup 1)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*movpsi" [(set (match_operand:PSI 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") @@ -1197,9 +1187,8 @@ || reg_or_0_operand (operands[1], <MODE>mode)" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (match_dup 1)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mov<mode>" [(set (match_operand:ALL4 0 "nonimmediate_operand" "=r,r ,r ,Qm ,!d,r") @@ -1245,9 +1234,8 @@ || reg_or_0_operand (operands[1], SFmode)" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (match_dup 1)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r") @@ -1326,16 +1314,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (mem:BLK (reg:HI REG_X)) - (mem:BLK (reg:HI REG_Z))) - (unspec [(match_dup 0)] - UNSPEC_CPYMEM) - (use (match_dup 1)) - (clobber (reg:HI REG_X)) - (clobber (reg:HI REG_Z)) - (clobber (reg:QI LPM_REGNO)) - (clobber (match_dup 2)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*cpymem_<mode>" [(set (mem:BLK (reg:HI REG_X)) @@ -1382,22 +1362,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (mem:BLK (reg:HI REG_X)) - (match_dup 2)) - (unspec [(match_dup 0)] - UNSPEC_CPYMEM) - (use (reg:QIHI 24)) - (clobber (reg:HI REG_X)) - (clobber (reg:HI REG_Z)) - (clobber (reg:QI LPM_REGNO)) - (clobber (reg:HI 24)) - (clobber (reg:QI 23)) - (clobber (mem:QI (match_dup 1))) - (clobber (reg:CC REG_CC))])] - { - rtx xset = XVECEXP (PATTERN (curr_insn), 0, 0); - operands[2] = SET_SRC (xset); - }) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*cpymemx_<mode>" [(set (mem:BLK (reg:HI REG_X)) @@ -1461,13 +1427,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (mem:BLK (match_dup 0)) - (const_int 0)) - (use (match_dup 1)) - (use (match_dup 2)) - (clobber (match_dup 3)) - (clobber (match_dup 4)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*clrmemqi" [(set (mem:BLK (match_operand:HI 0 "register_operand" "e")) @@ -1492,14 +1453,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (mem:BLK (match_dup 0)) - (const_int 0)) - (use (match_dup 1)) - (use (match_dup 2)) - (clobber (match_dup 3)) - (clobber (match_dup 4)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "adiw,*")]) @@ -1550,13 +1505,8 @@ "" "#" "&& reload_completed" - [(parallel - [(set (match_dup 0) - (unspec:HI [(mem:BLK (match_dup 1)) - (const_int 0) - (match_dup 2)] - UNSPEC_STRLEN)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*strlenhi" [(set (match_operand:HI 0 "register_operand" "=e") @@ -1581,10 +1531,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:ALL1 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*add<mode>3" [(set (match_operand:ALL1 0 "register_operand" "=r,d ,r ,r ,r ,r") @@ -1640,10 +1588,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (zero_extend:HI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*addhi3_zero_extend" [(set (match_operand:HI 0 "register_operand" "=r,*?r") @@ -1663,10 +1609,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (match_dup 1) - (zero_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*addhi3_zero_extend1" [(set (match_operand:HI 0 "register_operand" "=r") @@ -1684,10 +1628,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (zero_extend:HI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*addhi3_zero_extend.const" [(set (match_operand:HI 0 "register_operand" "=d") @@ -1723,11 +1665,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (ashift:HI (zero_extend:HI (match_dup 1)) - (const_int 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*addhi3_zero_extend.ashift1" [(set (match_operand:HI 0 "register_operand" "=r") @@ -1752,11 +1691,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (zero_extend:HI (match_dup 1)) - (zero_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) - + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*usum_widenqihi3" [(set (match_operand:HI 0 "register_operand" "=r") @@ -1774,10 +1710,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:HI (zero_extend:HI (match_dup 1)) - (zero_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*udiff_widenqihi3" [(set (match_operand:HI 0 "register_operand" "=r") @@ -1797,7 +1731,7 @@ return avr_out_addto_sp (operands, NULL); } "" - [(const_int 0)] + [(scratch)] { // Do not attempt to split this pattern. This FAIL is necessary // to prevent the splitter from matching *add<ALL2>3_split, splitting @@ -1909,11 +1843,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:ALL2 (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) ;; "*addhi3_clobber" ;; "*addhq3_clobber" "*adduhq3_clobber" @@ -1943,11 +1874,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:ALL4 (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*add<mode>3" [(set (match_operand:ALL4 0 "register_operand" "=??r,d ,r") @@ -1979,10 +1907,8 @@ && (<HISI:SIZE> > 2 || <CODE> == SIGN_EXTEND)" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HISI (any_extend:HISI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) ;; "*addhi3.sign_extend.qi" ;; "*addpsi3.zero_extend.qi" "*addpsi3.sign_extend.qi" @@ -2019,10 +1945,8 @@ "<HISI:SIZE> > <QIPSI:SIZE>" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:HISI (match_dup 1) - (any_extend:HISI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) ;; "*subhi3.zero_extend.qi" "*subhi3.sign_extend.qi" ;; "*subpsi3.zero_extend.qi" "*subpsi3.sign_extend.qi" @@ -2053,11 +1977,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3 )) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*addpsi3" [(set (match_operand:PSI 0 "register_operand" "=??r,d ,d,r") @@ -2079,10 +2000,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:PSI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*subpsi3" [(set (match_operand:PSI 0 "register_operand" "=r") @@ -2106,10 +2025,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:ALL1 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sub<mode>3" [(set (match_operand:ALL1 0 "register_operand" "=??r,d ,r ,r ,r ,r") @@ -2137,11 +2054,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:ALL2 (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sub<mode>3" [(set (match_operand:ALL2 0 "register_operand" "=??r,d ,*r") @@ -2167,11 +2081,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:ALL4 (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sub<mode>3" [(set (match_operand:ALL4 0 "register_operand" "=??r,d ,r") @@ -2209,10 +2120,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:QI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulqi3_enh" [(set (match_operand:QI 0 "register_operand" "=r") @@ -2243,10 +2152,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:QI 24) - (mult:QI (reg:QI 24) (reg:QI 22))) - (clobber (reg:QI 22)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulqi3_call" [(set (reg:QI 24) @@ -2269,12 +2176,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (truncate:QI - (lshiftrt:HI (mult:HI (any_extend:HI (match_dup 1)) - (any_extend:HI (match_dup 2))) - (const_int 8)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<extend_su>mulqi3_highpart" [(set (match_operand:QI 0 "register_operand" "=r") @@ -2361,21 +2264,21 @@ (const_int 0)))) (clobber (reg:CC REG_CC))])]) -;; *subqi3.lt0 *subqi3.ge0 -;; *subhi3.lt0 *subhi3.ge0 -;; *subpsi3.lt0 *subpsi3.ge0 -;; *subsi3.lt0 *subsi3.ge0 -(define_insn "*sub<QISI:mode>3.<code>0" - [(set (match_operand:QISI 0 "register_operand" "=r") - (minus:QISI (match_operand:QISI 1 "register_operand" "0") - (gelt:QISI (match_operand:QISI2 2 "register_operand" "r") - (const_int 0)))) - (clobber (reg:CC REG_CC))] - "reload_completed" - { - return avr_out_add_msb (insn, operands, <CODE>, nullptr); - } - [(set_attr "adjust_len" "add_<code>0")]) +;; *addqi3.lt0_split *addqi3.ge0_split +;; *addhi3.lt0_split *addhi3.ge0_split +;; *addpsi3.lt0_split *addpsi3.ge0_split +;; *addsi3.lt0_split *addsi3.ge0_split +(define_insn_and_split "*add<QISI:mode>3.<code>0_split" + [(set (match_operand:QISI 0 "register_operand" "=r") + (plus:QISI (gelt:QISI (match_operand:QISI2 1 "register_operand" "r") + (const_int 0)) + (match_operand:QISI 2 "register_operand" "0")))] + "" + "#" + "&& reload_completed" + ; *add<QISI:mode>3.<code>0 + [(scratch)] + { DONE_ADD_CCC }) ;; *addqi3.lt0 *addqi3.ge0 ;; *addhi3.lt0 *addhi3.ge0 @@ -2393,25 +2296,6 @@ } [(set_attr "adjust_len" "add_<code>0")]) -;; *addqi3.lt0_split *addqi3.ge0_split -;; *addhi3.lt0_split *addhi3.ge0_split -;; *addpsi3.lt0_split *addpsi3.ge0_split -;; *addsi3.lt0_split *addsi3.ge0_split -(define_insn_and_split "*add<QISI:mode>3.<code>0_split" - [(set (match_operand:QISI 0 "register_operand" "=r") - (plus:QISI (gelt:QISI (match_operand:QISI2 1 "register_operand" "r") - (const_int 0)) - (match_operand:QISI 2 "register_operand" "0")))] - "" - "#" - "&& reload_completed" - [; *add<QISI:mode>3.<code>0 - (parallel [(set (match_dup 0) - (plus:QISI (gelt:QISI (match_dup 1) - (const_int 0)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) - ;; *subqi3.lt0_split *subqi3.ge0_split ;; *subhi3.lt0_split *subhi3.ge0_split ;; *subpsi3.lt0_split *subpsi3.ge0_split @@ -2424,13 +2308,25 @@ "" "#" "&& reload_completed" - [; *sub<QISI:mode>3.<code>0 - (parallel [(set (match_dup 0) - (minus:QISI (match_dup 1) - (gelt:QISI (match_dup 2) - (const_int 0)))) - (clobber (reg:CC REG_CC))])]) + ; *sub<QISI:mode>3.<code>0 + [(scratch)] + { DONE_ADD_CCC }) +;; *subqi3.lt0 *subqi3.ge0 +;; *subhi3.lt0 *subhi3.ge0 +;; *subpsi3.lt0 *subpsi3.ge0 +;; *subsi3.lt0 *subsi3.ge0 +(define_insn "*sub<QISI:mode>3.<code>0" + [(set (match_operand:QISI 0 "register_operand" "=r") + (minus:QISI (match_operand:QISI 1 "register_operand" "0") + (gelt:QISI (match_operand:QISI2 2 "register_operand" "r") + (const_int 0)))) + (clobber (reg:CC REG_CC))] + "reload_completed" + { + return avr_out_add_msb (insn, operands, <CODE>, nullptr); + } + [(set_attr "adjust_len" "add_<code>0")]) (define_insn_and_split "*umulqihi3.call_split" [(set (reg:HI 24) @@ -2441,12 +2337,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (mult:HI (zero_extend:HI (reg:QI 22)) - (zero_extend:HI (reg:QI 24)))) - (clobber (reg:QI 21)) - (clobber (reg:HI 22)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*umulqihi3.call" [(set (reg:HI 24) @@ -2469,10 +2361,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (any_extend:HI (match_dup 1)) - (any_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "<extend_u>mulqihi3" [(set (match_operand:HI 0 "register_operand" "=r") @@ -2492,10 +2382,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (zero_extend:HI (match_dup 1)) - (sign_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*usmulqihi3" [(set (match_operand:HI 0 "register_operand" "=r") @@ -2517,10 +2405,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (sign_extend:HI (match_dup 1)) - (zero_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sumulqihi3" [(set (match_operand:HI 0 "register_operand" "=r") @@ -2542,10 +2428,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (not:HI (zero_extend:HI (not:QI (match_dup 1)))) - (sign_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*osmulqihi3" [(set (match_operand:HI 0 "register_operand" "=&r") @@ -2566,10 +2450,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (not:HI (zero_extend:HI (not:QI (match_dup 1)))) - (zero_extend:HI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*oumulqihi3" [(set (match_operand:HI 0 "register_operand" "=&r") @@ -2596,11 +2478,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:QI (mult:QI (match_dup 1) - (match_dup 2)) - (match_dup 3))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*maddqi4" [(set (match_operand:QI 0 "register_operand" "=r") @@ -2622,11 +2501,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:QI (match_dup 3) - (mult:QI (match_dup 1) - (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*msubqi4" [(set (match_operand:QI 0 "register_operand" "=r") @@ -2705,11 +2581,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (mult:HI (any_extend:HI (match_dup 1)) - (any_extend:HI (match_dup 2))) - (match_dup 3))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<extend_u>maddqihi4" [(set (match_operand:HI 0 "register_operand" "=r") @@ -2734,11 +2607,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:HI (match_dup 3) - (mult:HI (any_extend:HI (match_dup 1)) - (any_extend:HI (match_dup 2))))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<extend_u>msubqihi4" [(set (match_operand:HI 0 "register_operand" "=r") @@ -2765,11 +2635,8 @@ && <any_extend:CODE> != <any_extend2:CODE>" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (plus:HI (mult:HI (any_extend:HI (match_dup 1)) - (any_extend2:HI (match_dup 2))) - (match_dup 3))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<any_extend:extend_su><any_extend2:extend_su>msubqihi4" [(set (match_operand:HI 0 "register_operand" "=r") @@ -2800,11 +2667,8 @@ && <any_extend:CODE> != <any_extend2:CODE>" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (minus:HI (match_dup 3) - (mult:HI (any_extend:HI (match_dup 1)) - (any_extend2:HI (match_dup 2))))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<any_extend:extend_su><any_extend2:extend_su>msubqihi4" [(set (match_operand:HI 0 "register_operand" "=r") @@ -3072,16 +2936,14 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashift:HI (sign_extend:HI (match_dup 1)) - (const_int 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ashiftqihi2.signx.1" [(set (match_operand:HI 0 "register_operand" "=r,*r") (ashift:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "0,r")) (const_int 1))) - (clobber (reg:CC REG_CC)) ] + (clobber (reg:CC REG_CC))] "reload_completed" "@ lsl %A0\;sbc %B0,%B0 @@ -3142,6 +3004,41 @@ operands[2] = gen_int_mode (1 << INTVAL (operands[2]), QImode); }) +(define_insn_and_split "*sext.ashift<QIPSI:mode><HISI:mode>2_split" + [(set (match_operand:HISI 0 "register_operand" "=r") + (sign_extend:HISI (ashift:QIPSI (match_operand:QIPSI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "PKC03"))))] + "<HISI:SIZE> > <QIPSI:SIZE> + && IN_RANGE (INTVAL (operands[2]), 1, 2 + (<QIPSI:SIZE> <= 2))" + "#" + "&& reload_completed" + [(scratch)] + { DONE_ADD_CCC }) + +(define_insn "*sext.ashift<QIPSI:mode><HISI:mode>2" + [(set (match_operand:HISI 0 "register_operand" "=r") + (sign_extend:HISI (ashift:QIPSI (match_operand:QIPSI 1 "register_operand" "0") + (match_operand:QI 2 "const_int_operand" "PKC03")))) + (clobber (reg:CC REG_CC))] + "reload_completed + && <HISI:SIZE> > <QIPSI:SIZE> + && IN_RANGE (INTVAL (operands[2]), 1, 2 + (<QIPSI:SIZE> <= 2))" + { + const int regno = REGNO (operands[0]); + // The shift. + for (int s = 0; s < (int) INTVAL (operands[2]); ++s) + for (int b = 0; b < <QIPSI:SIZE>; ++b) + output_asm_insn (b == 0 ? "lsl %0" : "rol %0", + &all_regs_rtx[regno + b]); + // Sign-extend can use carry. + for (int b = <QIPSI:SIZE>; b < <HISI:SIZE>; ++b) + output_asm_insn ("sbc %0,%0", &all_regs_rtx[regno + b]); + return ""; + } + [(set (attr "length") + (plus (symbol_ref "<QIPSI:SIZE> * INTVAL (operands[2])") + (symbol_ref "<HISI:SIZE> - <QIPSI:SIZE>")))]) + ;****************************************************************************** ; mul HI: $1 = sign-/zero-/one-extend, $2 = reg ;****************************************************************************** @@ -3153,10 +3050,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (sign_extend:HI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulsqihi3" [(set (match_operand:HI 0 "register_operand" "=&r") @@ -3178,10 +3073,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (zero_extend:HI (match_dup 1)) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*muluqihi3" [(set (match_operand:HI 0 "register_operand" "=&r") @@ -3205,10 +3098,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (not:HI (zero_extend:HI (not:QI (match_dup 1)))) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*muloqihi3" [(set (match_operand:HI 0 "register_operand" "=&r") @@ -3277,10 +3168,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:HI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulhi3_enh" [(set (match_operand:HI 0 "register_operand" "=&r") @@ -3319,11 +3208,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (mult:HI (reg:HI 24) (reg:HI 22))) - (clobber (reg:HI 22)) - (clobber (reg:QI 21)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulhi3_call" [(set (reg:HI 24) @@ -3719,11 +3605,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (mult:SI (reg:SI 22) - (reg:SI 18))) - (clobber (reg:HI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn_and_split "*mulsi3_call_pr118012_split" [(set (reg:SI 22) @@ -3737,13 +3620,8 @@ && ! AVR_TINY" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (mult:SI (reg:SI 22) - (reg:SI 18))) - (clobber (reg:SI 18)) - (clobber (reg:HI 26)) - (clobber (reg:HI 30)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulsi3_call" [(set (reg:SI 22) @@ -3779,10 +3657,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (mult:SI (any_extend:SI (reg:HI 18)) - (any_extend:SI (reg:HI 26)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<extend_u>mulhisi3_call" [(set (reg:SI 22) @@ -3804,12 +3680,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (truncate:HI (lshiftrt:SI (mult:SI (any_extend:SI (reg:HI 18)) - (any_extend:SI (reg:HI 26))) - (const_int 16)))) - (clobber (reg:HI 22)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*<extend_su>mulhi3_highpart_call" [(set (reg:HI 24) @@ -3829,10 +3701,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (mult:SI (zero_extend:SI (reg:HI 18)) - (sign_extend:SI (reg:HI 26)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*usmulhisi3_call" [(set (reg:SI 22) @@ -3850,10 +3720,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (mult:SI (any_extend:SI (reg:HI 26)) - (reg:SI 18))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mul<extend_su>hisi3_call" [(set (reg:SI 22) @@ -3871,10 +3739,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (mult:SI (not:SI (zero_extend:SI (not:HI (reg:HI 26)))) - (reg:SI 18))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulohisi3_call" [(set (reg:SI 22) @@ -3925,11 +3791,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22))) - (set (reg:QI 25) (mod:QI (reg:QI 24) (reg:QI 22))) - (clobber (reg:QI 22)) - (clobber (reg:QI 23)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*divmodqi4_call" [(set (reg:QI 24) (div:QI (reg:QI 24) (reg:QI 22))) @@ -3969,10 +3832,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22))) - (set (reg:QI 25) (umod:QI (reg:QI 24) (reg:QI 22))) - (clobber (reg:QI 23)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*udivmodqi4_call" [(set (reg:QI 24) (udiv:QI (reg:QI 24) (reg:QI 22))) @@ -4013,11 +3874,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22))) - (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22))) - (clobber (reg:HI 26)) - (clobber (reg:QI 21)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*divmodhi4_call" [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22))) @@ -4059,11 +3917,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22))) - (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22))) - (clobber (reg:HI 26)) - (clobber (reg:QI 21)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*udivmodhi4_call" [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22))) @@ -4112,10 +3967,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (mult:PSI (zero_extend:PSI (match_dup 1)) - (zero_extend:PSI (match_dup 2)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*umulqihipsi3" [(set (match_operand:PSI 0 "register_operand" "=&r") @@ -4134,31 +3987,17 @@ (define_insn_and_split "*umulhiqipsi3_split" [(set (match_operand:PSI 0 "register_operand" "=&r") - (mult:PSI (zero_extend:PSI (match_operand:HI 2 "register_operand" "r")) - (zero_extend:PSI (match_operand:QI 1 "register_operand" "r"))))] + (mult:PSI (zero_extend:PSI (match_operand:HI 1 "register_operand" "r")) + (zero_extend:PSI (match_operand:QI 2 "register_operand" "r"))))] "AVR_HAVE_MUL" "#" "&& reload_completed" + ; "*umulqihipsi3" [(parallel [(set (match_dup 0) (mult:PSI (zero_extend:PSI (match_dup 2)) (zero_extend:PSI (match_dup 1)))) (clobber (reg:CC REG_CC))])]) -(define_insn "*umulhiqipsi3" - [(set (match_operand:PSI 0 "register_operand" "=&r") - (mult:PSI (zero_extend:PSI (match_operand:HI 2 "register_operand" "r")) - (zero_extend:PSI (match_operand:QI 1 "register_operand" "r")))) - (clobber (reg:CC REG_CC))] - "AVR_HAVE_MUL && reload_completed" - "mul %1,%A2 - movw %A0,r0 - mul %1,%B2 - add %B0,r0 - mov %C0,r1 - clr __zero_reg__ - adc %C0,__zero_reg__" - [(set_attr "length" "7")]) - (define_expand "mulsqipsi3" [(parallel [(set (match_operand:PSI 0 "pseudo_register_operand" "") (mult:PSI (sign_extend:PSI (match_operand:QI 1 "pseudo_register_operand" "")) @@ -4229,10 +4068,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:PSI 18) - (mult:PSI (sign_extend:PSI (reg:QI 25)) - (reg:PSI 22))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulsqipsi3.libgcc" [(set (reg:PSI 18) @@ -4253,13 +4090,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:PSI 22) - (mult:PSI (reg:PSI 22) - (reg:PSI 18))) - (clobber (reg:QI 21)) - (clobber (reg:QI 25)) - (clobber (reg:HI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*mulpsi3.libgcc" [(set (reg:PSI 22) @@ -4311,12 +4143,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:PSI 22) (div:PSI (reg:PSI 22) (reg:PSI 18))) - (set (reg:PSI 18) (mod:PSI (reg:PSI 22) (reg:PSI 18))) - (clobber (reg:QI 21)) - (clobber (reg:QI 25)) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*divmodpsi4_call" [(set (reg:PSI 22) (div:PSI (reg:PSI 22) (reg:PSI 18))) @@ -4360,12 +4188,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:PSI 22) (udiv:PSI (reg:PSI 22) (reg:PSI 18))) - (set (reg:PSI 18) (umod:PSI (reg:PSI 22) (reg:PSI 18))) - (clobber (reg:QI 21)) - (clobber (reg:QI 25)) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*udivmodpsi4_call" [(set (reg:PSI 22) (udiv:PSI (reg:PSI 22) (reg:PSI 18))) @@ -4411,11 +4235,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18))) - (set (reg:SI 22) (mod:SI (reg:SI 22) (reg:SI 18))) - (clobber (reg:HI 26)) - (clobber (reg:HI 30)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*divmodsi4_call" [(set (reg:SI 18) (div:SI (reg:SI 22) (reg:SI 18))) @@ -4458,11 +4279,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18))) - (set (reg:SI 22) (umod:SI (reg:SI 22) (reg:SI 18))) - (clobber (reg:HI 26)) - (clobber (reg:HI 30)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*udivmodsi4_call" [(set (reg:SI 18) (udiv:SI (reg:SI 22) (reg:SI 18))) @@ -4484,10 +4302,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (and:QI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*andqi3" [(set (match_operand:QI 0 "register_operand" "=??r,d,*l ,r") @@ -4511,11 +4327,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (and:HI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*andhi3" [(set (match_operand:HI 0 "register_operand" "=??r,d,d,r ,r ,r") @@ -4545,11 +4358,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (and:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*andpsi3" [(set (match_operand:PSI 0 "register_operand" "=??r,d,r ,r ,r") @@ -4580,11 +4390,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (and:SI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*andsi3" [(set (match_operand:SI 0 "register_operand" "=??r,d,r ,r ,r") @@ -4634,10 +4441,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ior:QI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*iorqi3" [(set (match_operand:QI 0 "register_operand" "=??r,d,*l") @@ -4659,11 +4464,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ior:HI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*iorhi3" [(set (match_operand:HI 0 "register_operand" "=??r,d,d,r ,r") @@ -4691,11 +4493,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ior:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*iorpsi3" [(set (match_operand:PSI 0 "register_operand" "=??r,d,r ,r") @@ -4723,11 +4522,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ior:SI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*iorsi3" [(set (match_operand:SI 0 "register_operand" "=??r,d,r ,r") @@ -4758,10 +4554,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (xor:QI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*xorqi3" [(set (match_operand:QI 0 "register_operand" "=r") @@ -4780,11 +4574,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (xor:HI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*xorhi3" [(set (match_operand:HI 0 "register_operand" "=??r,r ,d ,r") @@ -4810,11 +4601,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (xor:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*xorpsi3" [(set (match_operand:PSI 0 "register_operand" "=??r,r ,d ,r") @@ -4842,11 +4630,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (xor:SI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*xorsi3" [(set (match_operand:SI 0 "register_operand" "=??r,r ,d ,r") @@ -4918,7 +4703,7 @@ (clobber (reg:CC REG_CC))])] "optimize && reload_completed" - [(const_int 1)] + [(scratch)] { for (int i = 0; i < <SIZE>; i++) { @@ -5026,10 +4811,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:QI (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlqi3" [(set (match_operand:QI 0 "register_operand" "=r,r,r ,r ,r ,r ,r ,r") @@ -5099,10 +4882,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:HI (match_dup 1) - (const_int 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlhi2.1" [(set (match_operand:HI 0 "register_operand" "=r") @@ -5120,10 +4901,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:HI (match_dup 1) - (const_int 15))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlhi2.15" [(set (match_operand:HI 0 "register_operand" "=r") @@ -5141,10 +4920,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:PSI (match_dup 1) - (const_int 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlpsi2.1" [(set (match_operand:PSI 0 "register_operand" "=r") @@ -5162,10 +4939,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:PSI (match_dup 1) - (const_int 23))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlpsi2.23" [(set (match_operand:PSI 0 "register_operand" "=r") @@ -5183,10 +4958,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:SI (match_dup 1) - (const_int 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlsi2.1" [(set (match_operand:SI 0 "register_operand" "=r") @@ -5204,10 +4977,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (rotate:SI (match_dup 1) - (const_int 31))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*rotlsi2.31" [(set (match_operand:SI 0 "register_operand" "=r") @@ -5239,7 +5010,7 @@ && 0 == INTVAL (operands[2]) % 16" "#" "&& reload_completed" - [(const_int 0)] + [(scratch)] { avr_rotate_bytes (operands); DONE; @@ -5263,7 +5034,7 @@ && 0 == INTVAL (operands[2]) % 16))" "#" "&& reload_completed" - [(const_int 0)] + [(scratch)] { avr_rotate_bytes (operands); DONE; @@ -5273,41 +5044,6 @@ ;;<< << << << << << << << << << << << << << << << << << << << << << << << << << ;; arithmetic shift left -;; Work around PR120423: Transform left shift of a paradoxical subreg -;; into left shift of the zero-extended entity. -(define_split ; PR120423 - [(set (match_operand:HISI 0 "register_operand") - (ashift:HISI (subreg:HISI (match_operand:QIPSI 1 "nonimmediate_operand") - 0) - (match_operand:QI 2 "const_int_operand")))] - "!reload_completed - && !avropt_lra_p - && <HISI:SIZE> > <QIPSI:SIZE>" - [(set (match_dup 4) - (zero_extend:HISI (match_dup 5))) - (set (match_dup 0) - (ashift:HISI (match_dup 4) - (match_dup 2)))] - { - operands[4] = gen_reg_rtx (<HISI:MODE>mode); - operands[5] = force_reg (<QIPSI:MODE>mode, operands[1]); - }) - -;; Similar happens for PR116389. -(define_split ; PR116389 - [(set (match_operand:HISI 0 "register_operand") - (subreg:HISI (match_operand:QIPSI 1 "nonimmediate_operand") - 0))] - "!reload_completed - && !avropt_lra_p - && <HISI:SIZE> > <QIPSI:SIZE>" - [(set (match_dup 0) - (zero_extend:HISI (match_dup 2)))] - { - operands[2] = force_reg (<QIPSI:MODE>mode, operands[1]); - }) - - ;; "ashlqi3" ;; "ashlqq3" "ashluqq3" (define_expand "ashl<mode>3" @@ -5363,10 +5099,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashift:ALL1 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ashl<mode>3" [(set (match_operand:ALL1 0 "register_operand" "=r,r ,r ,r,r") @@ -5390,11 +5124,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashift:ALL2 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*,*")]) ;; "*ashlhi3" @@ -5506,11 +5237,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashift:ALL4 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*,*")]) (define_insn "*ashl<mode>3" @@ -5749,12 +5477,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashift:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*")]) (define_insn "*ashlpsi3" @@ -5808,10 +5532,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashiftrt:ALL1 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ashr<mode>3" [(set (match_operand:ALL1 0 "register_operand" "=r,r ,r ,r") @@ -5835,11 +5557,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashiftrt:ALL2 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*,*")]) ;; "*ashrhi3" @@ -5866,12 +5585,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashiftrt:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*")]) (define_insn "*ashrpsi3" @@ -5898,11 +5613,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (ashiftrt:ALL4 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*,*")]) (define_insn "*ashr<mode>3" @@ -6013,10 +5725,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (lshiftrt:ALL1 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*lshr<mode>3" [(set (match_operand:ALL1 0 "register_operand" "=r,r ,r ,r,r") @@ -6039,11 +5749,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (lshiftrt:ALL2 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*,*")]) (define_insn "*lshr<mode>3" @@ -6066,12 +5773,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (lshiftrt:PSI (match_dup 1) - (match_dup 2))) - (clobber (match_dup 3)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*")]) (define_insn "*lshrpsi3" @@ -6098,11 +5801,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (lshiftrt:ALL4 (match_dup 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,*,3op,*,*")]) (define_insn "*lshr<mode>3" @@ -6217,9 +5917,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (abs:QI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*absqi2" [(set (match_operand:QI 0 "register_operand" "=r") @@ -6237,9 +5936,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (abs:SF (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*abssf2" [(set (match_operand:SF 0 "register_operand" "=d,r") @@ -6260,9 +5958,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (neg:QI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*negqi2" [(set (match_operand:QI 0 "register_operand" "=r") @@ -6278,9 +5975,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (neg:HI (sign_extend:HI (match_dup 1)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*negqihi2" [(set (match_operand:HI 0 "register_operand" "=r") @@ -6296,9 +5992,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (neg:HI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*neghi2" [(set (match_operand:HI 0 "register_operand" "=r,&r") @@ -6316,9 +6011,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (neg:PSI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*negpsi2" [(set (match_operand:PSI 0 "register_operand" "=!d,r,&r") @@ -6337,10 +6031,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (neg:SI (match_dup 1))) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "*,*,mov,movw")]) (define_insn "*negsi2.libgcc" @@ -6371,9 +6063,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (neg:SF (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*negsf2" [(set (match_operand:SF 0 "register_operand" "=d,r") @@ -6394,9 +6085,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (not:QI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*one_cmplqi2" [(set (match_operand:QI 0 "register_operand" "=r") @@ -6412,9 +6102,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (not:HI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*one_cmplhi2" [(set (match_operand:HI 0 "register_operand" "=r") @@ -6431,9 +6120,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (not:PSI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*one_cmplpsi2" [(set (match_operand:PSI 0 "register_operand" "=r") @@ -6449,9 +6137,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (not:SI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r") @@ -6480,9 +6167,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extend:HI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extendqihi2" [(set (match_operand:HI 0 "register_operand" "=r,r") @@ -6501,9 +6187,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extend:PSI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extendqipsi2" [(set (match_operand:PSI 0 "register_operand" "=r,r") @@ -6522,9 +6207,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extend:SI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extendqisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -6543,9 +6227,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extend:PSI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extendhipsi2" [(set (match_operand:PSI 0 "register_operand" "=r,r") @@ -6564,9 +6247,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extend:SI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extendhisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -6585,9 +6267,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extend:SI (match_dup 1))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extendpsisi2" [(set (match_operand:SI 0 "register_operand" "=r") @@ -7032,10 +6713,11 @@ "#" "reload_completed" [(set (reg:CC REG_CC) - (compare:CC (match_dup 1) (match_dup 2))) + (compare:CC (match_dup 1) + (match_dup 2))) (set (pc) - (if_then_else (match_op_dup 0 - [(reg:CC REG_CC) (const_int 0)]) + (if_then_else (match_op_dup 0 [(reg:CC REG_CC) + (const_int 0)]) (label_ref (match_dup 3)) (pc)))]) @@ -7054,11 +6736,12 @@ "#" "reload_completed" [(parallel [(set (reg:CC REG_CC) - (compare:CC (match_dup 1) (match_dup 2))) + (compare:CC (match_dup 1) + (match_dup 2))) (clobber (match_dup 4))]) (set (pc) - (if_then_else (match_op_dup 0 - [(reg:CC REG_CC) (const_int 0)]) + (if_then_else (match_op_dup 0 [(reg:CC REG_CC) + (const_int 0)]) (label_ref (match_dup 3)) (pc)))] { @@ -7081,11 +6764,12 @@ "#" "reload_completed" [(parallel [(set (reg:CC REG_CC) - (compare:CC (match_dup 1) (match_dup 2))) + (compare:CC (match_dup 1) + (match_dup 2))) (clobber (match_dup 4))]) (set (pc) - (if_then_else (match_op_dup 0 - [(reg:CC REG_CC) (const_int 0)]) + (if_then_else (match_op_dup 0 [(reg:CC REG_CC) + (const_int 0)]) (label_ref (match_dup 3)) (pc)))] { @@ -7109,11 +6793,12 @@ "#" "reload_completed" [(parallel [(set (reg:CC REG_CC) - (compare:CC (match_dup 1) (match_dup 2))) + (compare:CC (match_dup 1) + (match_dup 2))) (clobber (match_dup 4))]) (set (pc) - (if_then_else (match_op_dup 0 - [(reg:CC REG_CC) (const_int 0)]) + (if_then_else (match_op_dup 0 [(reg:CC REG_CC) + (const_int 0)]) (label_ref (match_dup 3)) (pc)))] { @@ -7668,17 +7353,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (pc) - (if_then_else - (match_op_dup 0 - [(zero_extract:QIDI - (match_dup 1) - (const_int 1) - (match_dup 2)) - (const_int 0)]) - (label_ref (match_dup 3)) - (pc))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sbrx_branch<mode>" [(set (pc) @@ -7721,13 +7397,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (pc) - (if_then_else (match_op_dup 0 [(and:QISI (match_dup 1) - (match_dup 2)) - (const_int 0)]) - (label_ref (match_dup 3)) - (pc))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sbrx_and_branch<mode>" [(set (pc) @@ -7968,14 +7639,8 @@ "!AVR_HAVE_EIJMP_EICALL" "#" "&& reload_completed" - [(parallel [(set (pc) - (unspec:HI [(match_dup 0)] - UNSPEC_INDEX_JMP)) - (use (label_ref (match_dup 1))) - (clobber (match_dup 2)) - (clobber (const_int 0)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "rjmp,rjmp,jmp")]) (define_insn "*tablejump" @@ -8004,14 +7669,8 @@ "AVR_HAVE_EIJMP_EICALL" "#" "&& reload_completed" - [(parallel [(set (pc) - (unspec:HI [(reg:HI REG_Z)] - UNSPEC_INDEX_JMP)) - (use (label_ref (match_dup 0))) - (clobber (reg:HI REG_Z)) - (clobber (reg:QI 24)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "eijmp")]) @@ -8182,17 +7841,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (pc) - (if_then_else - (match_operator 0 "eqne_operator" - [(zero_extract:QIHI - (mem:QI (match_dup 1)) - (const_int 1) - (match_dup 2)) - (const_int 0)]) - (label_ref (match_dup 3)) - (pc))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sbix_branch" [(set (pc) @@ -8230,14 +7880,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (pc) - (if_then_else - (match_operator 0 "gelt_operator" - [(mem:QI (match_dup 1)) - (const_int 0)]) - (label_ref (match_dup 2)) - (pc))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sbix_branch_bit7" [(set (pc) @@ -8277,17 +7921,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (pc) - (if_then_else - (match_operator 0 "eqne_operator" - [(zero_extract:QIHI - (mem:QI (match_dup 1)) - (const_int 1) - (match_dup 2)) - (const_int 0)]) - (label_ref (match_dup 3)) - (pc))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sbix_branch_tmp" [(set (pc) @@ -8324,14 +7959,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (pc) - (if_then_else - (match_operator 0 "gelt_operator" - [(mem:QI (match_dup 1)) - (const_int 0)]) - (label_ref (match_dup 2)) - (pc))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sbix_branch_tmp_bit7" [(set (pc) @@ -8784,13 +8413,8 @@ "" "#" "&& reload_completed" - [(parallel [(unspec_volatile [(match_dup 0) - (const_int 1)] - UNSPECV_DELAY_CYCLES) - (set (match_dup 1) - (unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER)) - (clobber (match_dup 2)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*delay_cycles_1" [(unspec_volatile [(match_operand:QI 0 "const_int_operand" "n") @@ -8816,14 +8440,8 @@ "" "#" "&& reload_completed" - [(parallel [(unspec_volatile [(match_dup 0) - (const_int 2)] - UNSPECV_DELAY_CYCLES) - (set (match_dup 1) - (unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER)) - (clobber (match_dup 2)) - (clobber (reg:CC REG_CC))])] - "" + [(scratch)] + { DONE_ADD_CCC } [(set_attr "isa" "adiw,no_adiw")]) (define_insn "*delay_cycles_2" @@ -8853,15 +8471,8 @@ "" "#" "&& reload_completed" - [(parallel [(unspec_volatile [(match_dup 0) - (const_int 3)] - UNSPECV_DELAY_CYCLES) - (set (match_dup 1) - (unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER)) - (clobber (match_dup 2)) - (clobber (match_dup 3)) - (clobber (match_dup 4)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*delay_cycles_3" [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n") @@ -8896,16 +8507,8 @@ "" "#" "&& reload_completed" - [(parallel [(unspec_volatile [(match_dup 0) - (const_int 4)] - UNSPECV_DELAY_CYCLES) - (set (match_dup 1) - (unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER)) - (clobber (match_dup 2)) - (clobber (match_dup 3)) - (clobber (match_dup 4)) - (clobber (match_dup 5)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*delay_cycles_4" [(unspec_volatile [(match_operand:SI 0 "const_int_operand" "n") @@ -8942,12 +8545,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (unspec:QI [(match_dup 1) - (match_dup 2) - (match_dup 3)] - UNSPEC_INSERT_BITS)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*insert_bits" [(set (match_operand:QI 0 "register_operand" "=r ,d ,r") @@ -9127,12 +8726,13 @@ "#" "reload_completed" [(set (reg:CC REG_CC) - (compare:CC (match_dup 0) (const_int 0))) + (compare:CC (match_dup 0) + (const_int 0))) (set (pc) - (if_then_else (ge (reg:CC REG_CC) (const_int 0)) + (if_then_else (ge (reg:CC REG_CC) + (const_int 0)) (label_ref (match_dup 1)) - (pc)))] - "") + (pc)))]) (define_expand "flash_segment" [(parallel [(match_operand:QI 0 "register_operand" "") @@ -9235,9 +8835,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (parity:HI (reg:HI 24))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*parityhi2.libgcc" [(set (reg:HI 24) @@ -9253,9 +8852,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (zero_extend:HI (parity:QI (reg:QI 24)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*parityqihi2.libgcc" [(set (reg:HI 24) @@ -9271,9 +8869,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (truncate:HI (parity:SI (reg:SI 22)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*paritysihi2.libgcc" [(set (reg:HI 24) @@ -9329,9 +8926,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (popcount:HI (reg:HI 24))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*popcounthi2.libgcc" [(set (reg:HI 24) @@ -9347,9 +8943,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (truncate:HI (popcount:SI (reg:SI 22)))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*popcountsi2.libgcc" [(set (reg:HI 24) @@ -9365,9 +8960,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:QI 24) - (popcount:QI (reg:QI 24))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*popcountqi2.libgcc" [(set (reg:QI 24) @@ -9421,10 +9015,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (clz:HI (reg:HI 24))) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*clzhi2.libgcc" [(set (reg:HI 24) @@ -9442,10 +9034,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (truncate:HI (clz:SI (reg:SI 22)))) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*clzsihi2.libgcc" [(set (reg:HI 24) @@ -9490,10 +9080,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (ctz:HI (reg:HI 24))) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ctzhi2.libgcc" [(set (reg:HI 24) @@ -9512,11 +9100,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (truncate:HI (ctz:SI (reg:SI 22)))) - (clobber (reg:QI 22)) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ctzsihi2.libgcc" [(set (reg:HI 24) @@ -9562,10 +9147,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (ffs:HI (reg:HI 24))) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ffshi2.libgcc" [(set (reg:HI 24) @@ -9584,11 +9167,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:HI 24) - (truncate:HI (ffs:SI (reg:SI 22)))) - (clobber (reg:QI 22)) - (clobber (reg:QI 26)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*ffssihi2.libgcc" [(set (reg:HI 24) @@ -9633,9 +9213,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (reg:SI 22) - (bswap:SI (reg:SI 22))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*bswapsi2.libgcc" [(set (reg:SI 22) @@ -9742,11 +9321,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (unspec:HI [(match_dup 1) - (match_dup 2)] - UNSPEC_FMUL)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fmul_insn" [(set (match_operand:HI 0 "register_operand" "=r") @@ -9768,11 +9344,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:HI 22) - (unspec:HI [(reg:QI 24) - (reg:QI 25)] UNSPEC_FMUL)) - (clobber (reg:HI 24)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fmul.call" [(set (reg:HI 22) @@ -9814,11 +9387,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (unspec:HI [(match_dup 1) - (match_dup 2)] - UNSPEC_FMULS)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fmuls_insn" [(set (match_operand:HI 0 "register_operand" "=r") @@ -9840,11 +9410,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:HI 22) - (unspec:HI [(reg:QI 24) - (reg:QI 25)] UNSPEC_FMULS)) - (clobber (reg:HI 24)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fmuls.call" [(set (reg:HI 22) @@ -9886,11 +9453,8 @@ "AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (unspec:HI [(match_dup 1) - (match_dup 2)] - UNSPEC_FMULSU)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fmulsu_insn" [(set (match_operand:HI 0 "register_operand" "=r") @@ -9912,11 +9476,8 @@ "!AVR_HAVE_MUL" "#" "&& reload_completed" - [(parallel [(set (reg:HI 22) - (unspec:HI [(reg:QI 24) - (reg:QI 25)] UNSPEC_FMULSU)) - (clobber (reg:HI 24)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*fmulsu.call" [(set (reg:HI 22) @@ -10037,11 +9598,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (zero_extract:QI (match_dup 0) - (const_int 1) - (match_dup 1)) - (match_dup 2)) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*insv.reg" [(set (zero_extract:QI (match_operand:QI 0 "register_operand" "+r,d,d,l,l") @@ -10478,11 +10036,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (zero_extract:QI (not:QI (match_dup 1)) - (const_int 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*extzv.not" [(set (match_operand:QI 0 "register_operand" "=r") @@ -10619,11 +10174,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (and:QISI (any_shift:QISI (match_dup 1) - (match_dup 2)) - (match_dup 3))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*insv.any_shift.<mode>" [(set (match_operand:QISI 0 "register_operand" "=r") @@ -10686,11 +10238,8 @@ "" "#" "&& reload_completed" - [(parallel [(set (match_dup 0) - (sign_extract:QISI (match_dup 1) - (const_int 1) - (match_dup 2))) - (clobber (reg:CC REG_CC))])]) + [(scratch)] + { DONE_ADD_CCC }) (define_insn "*sextr.<QISI:mode>.<QISI2:mode>" [(set (match_operand:QISI 0 "register_operand" "=r") diff --git a/gcc/config/avr/avr.opt b/gcc/config/avr/avr.opt index 7f6f18c..2bed8ea 100644 --- a/gcc/config/avr/avr.opt +++ b/gcc/config/avr/avr.opt @@ -18,10 +18,6 @@ ; along with GCC; see the file COPYING3. If not see ; <http://www.gnu.org/licenses/>. -mlra -Target Var(avropt_lra_p) UInteger Init(1) Optimization Undocumented -Usa LRA for reload instead of the old reload framework. This option is experimental, on per default, and it may be removed in future versions of the compiler. - mcall-prologues Target Mask(CALL_PROLOGUES) Optimization Optimization. Use subroutines for function prologues and epilogues. diff --git a/gcc/config/avr/avr.opt.urls b/gcc/config/avr/avr.opt.urls index 87c26b2..fa560bc 100644 --- a/gcc/config/avr/avr.opt.urls +++ b/gcc/config/avr/avr.opt.urls @@ -1,7 +1,5 @@ ; Autogenerated by regenerate-opt-urls.py from gcc/config/avr/avr.opt and generated HTML -; skipping UrlSuffix for 'mlra' due to finding no URLs - mcall-prologues UrlSuffix(gcc/AVR-Options.html#index-mcall-prologues) diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 09aa9b1..12cec61 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -9574,8 +9574,9 @@ ix86_expand_set_or_cpymem (rtx dst, rtx src, rtx count_exp, rtx val_exp, case vector_loop: need_zero_guard = true; unroll_factor = 4; - /* Get the vector mode to move MOVE_MAX bytes. */ - nunits = MOVE_MAX / GET_MODE_SIZE (word_mode); + /* Get the vector mode to move STORE_MAX_PIECES/MOVE_MAX bytes. */ + nunits = issetmem ? STORE_MAX_PIECES : MOVE_MAX; + nunits /= GET_MODE_SIZE (word_mode); if (nunits > 1) { move_mode = mode_for_vector (word_mode, nunits).require (); diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index 53e86c8..9941e61 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -3085,21 +3085,63 @@ ix86_rpad_gate () && optimize_function_for_speed_p (cfun)); } +enum x86_cse_kind +{ + X86_CSE_CONST0_VECTOR, + X86_CSE_CONSTM1_VECTOR, + X86_CSE_VEC_DUP +}; + +struct redundant_load +{ + /* Bitmap of basic blocks with broadcast instructions. */ + auto_bitmap bbs; + /* Bitmap of broadcast instructions. */ + auto_bitmap insns; + /* The broadcast inner scalar. */ + rtx val; + /* The inner scalar mode. */ + machine_mode mode; + /* The instruction which sets the inner scalar. Nullptr if the inner + scalar is applied to the whole function, instead of within the same + block. */ + rtx_insn *def_insn; + /* The widest broadcast source. */ + rtx broadcast_source; + /* The widest broadcast register. */ + rtx broadcast_reg; + /* The basic block of the broadcast instruction. */ + basic_block bb; + /* The number of broadcast instructions with the same inner scalar. */ + unsigned HOST_WIDE_INT count; + /* The threshold of broadcast instructions with the same inner + scalar. */ + unsigned int threshold; + /* The widest broadcast size in bytes. */ + unsigned int size; + /* Load kind. */ + x86_cse_kind kind; +}; + /* Generate a vector set, DEST = SRC, at entry of the nearest dominator for basic block map BBS, which is in the fake loop that contains the whole function, so that there is only a single vector set in the - whole function. If not nullptr, INNER_SCALAR is the inner scalar of - SRC, as (reg:SI 99) in (vec_duplicate:V4SI (reg:SI 99)). */ + whole function. If not nullptr, LOAD is a pointer to the load. */ static void ix86_place_single_vector_set (rtx dest, rtx src, bitmap bbs, - rtx inner_scalar = nullptr) + redundant_load *load = nullptr) { basic_block bb = nearest_common_dominator_for_set (CDI_DOMINATORS, bbs); - while (bb->loop_father->latch - != EXIT_BLOCK_PTR_FOR_FN (cfun)) - bb = get_immediate_dominator (CDI_DOMINATORS, - bb->loop_father->header); + /* For X86_CSE_VEC_DUP, don't place the vector set outside of the loop + to avoid extra spills. */ + if (!load || load->kind != X86_CSE_VEC_DUP) + { + while (bb->loop_father->latch + != EXIT_BLOCK_PTR_FOR_FN (cfun)) + bb = get_immediate_dominator (CDI_DOMINATORS, + bb->loop_father->header); + } rtx set = gen_rtx_SET (dest, src); @@ -3141,8 +3183,14 @@ ix86_place_single_vector_set (rtx dest, rtx src, bitmap bbs, } } - if (inner_scalar) + if (load && load->kind == X86_CSE_VEC_DUP) { + /* Get the source from LOAD as (reg:SI 99) in + + (vec_duplicate:V4SI (reg:SI 99)) + + */ + rtx inner_scalar = load->val; /* Set the source in (vec_duplicate:V4SI (reg:SI 99)). */ rtx reg = XEXP (src, 0); if ((REG_P (inner_scalar) || MEM_P (inner_scalar)) @@ -3489,44 +3537,6 @@ replace_vector_const (machine_mode vector_mode, rtx vector_const, } } -enum x86_cse_kind -{ - X86_CSE_CONST0_VECTOR, - X86_CSE_CONSTM1_VECTOR, - X86_CSE_VEC_DUP -}; - -struct redundant_load -{ - /* Bitmap of basic blocks with broadcast instructions. */ - auto_bitmap bbs; - /* Bitmap of broadcast instructions. */ - auto_bitmap insns; - /* The broadcast inner scalar. */ - rtx val; - /* The inner scalar mode. */ - machine_mode mode; - /* The instruction which sets the inner scalar. Nullptr if the inner - scalar is applied to the whole function, instead of within the same - block. */ - rtx_insn *def_insn; - /* The widest broadcast source. */ - rtx broadcast_source; - /* The widest broadcast register. */ - rtx broadcast_reg; - /* The basic block of the broadcast instruction. */ - basic_block bb; - /* The number of broadcast instructions with the same inner scalar. */ - unsigned HOST_WIDE_INT count; - /* The threshold of broadcast instructions with the same inner - scalar. */ - unsigned int threshold; - /* The widest broadcast size in bytes. */ - unsigned int size; - /* Load kind. */ - x86_cse_kind kind; -}; - /* Return the inner scalar if OP is a broadcast, else return nullptr. */ static rtx @@ -3872,10 +3882,7 @@ remove_redundant_vector_load (void) else ix86_place_single_vector_set (load->broadcast_reg, load->broadcast_source, - load->bbs, - (load->kind == X86_CSE_VEC_DUP - ? load->val - : nullptr)); + load->bbs, load); } loop_optimizer_finalize (); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index a50475b..2b0dd66 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1618,10 +1618,8 @@ (compare (match_operand:QI 0 "nonimmediate_operand" "QBn") (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0)))] + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0)))] "ix86_match_ccmode (insn, CCmode)" "cmp{b}\t{%h1, %0|%0, %h1}" [(set_attr "addr" "gpr8") @@ -1632,10 +1630,8 @@ [(set (reg FLAGS_REG) (compare (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 0 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 0 "int248_register_operand" "Q")]) 0) (match_operand:QI 1 "const0_operand")))] "ix86_match_ccmode (insn, CCNOmode)" "test{b}\t%h0, %h0" @@ -1657,10 +1653,8 @@ [(set (reg FLAGS_REG) (compare (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 0 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 0 "int248_register_operand" "Q")]) 0) (match_operand:QI 1 "general_operand" "QnBn")))] "ix86_match_ccmode (insn, CCmode)" "cmp{b}\t{%1, %h0|%h0, %1}" @@ -1672,15 +1666,11 @@ [(set (reg FLAGS_REG) (compare (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 0 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 0 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0)))] + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0)))] "ix86_match_ccmode (insn, CCmode)" "cmp{b}\t{%h1, %h0|%h0, %h1}" [(set_attr "type" "icmp") @@ -3480,10 +3470,8 @@ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+Q")) (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))] + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "mov{b}\t{%h1, %0|%0, %h1}" [(set_attr "type" "imov") @@ -3566,10 +3554,8 @@ (define_insn "*extzvqi" [(set (match_operand:QI 0 "nonimmediate_operand" "=QBn,?R") (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q,Q") - (const_int 8) - (const_int 8)]) 0))] + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q,Q")]) 0))] "" { switch (get_attr_type (insn)) @@ -3690,10 +3676,8 @@ (match_operand 0 "int248_register_operand" "+Q") (const_int 8) (const_int 8)) - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]))] + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]))] "" "mov{b}\t{%h1, %h0|%h0, %h1}" [(set_attr "type" "imov") @@ -5260,10 +5244,8 @@ [(set (match_operand:SWI24 0 "register_operand" "=R") (sign_extend:SWI24 (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0)))] + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0)))] "" "movs{b<SWI24:imodesuffix>|x}\t{%h1, %0|%0, %h1}" [(set_attr "type" "imovx") @@ -7009,10 +6991,8 @@ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+Q,&Q")) (plus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q,Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q,Q")]) 0) (match_operand:QI 1 "nonimmediate_operand" "0,!qm"))) (clobber (reg:CC FLAGS_REG))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" @@ -7026,8 +7006,8 @@ [(set (strict_low_part (match_dup 0)) (plus:QI (subreg:QI - (match_op_dup 3 - [(match_dup 2) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0) (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "" @@ -7038,29 +7018,25 @@ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+&Q")) (plus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "#" "&& reload_completed" [(set (strict_low_part (match_dup 0)) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0)) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0)) (parallel [(set (strict_low_part (match_dup 0)) (plus:QI (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0) (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "" @@ -7475,10 +7451,8 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=QBn") (plus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0) (match_operand:QI 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] "" @@ -7491,29 +7465,25 @@ [(set (match_operand:QI 0 "register_operand" "=&Q") (plus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "" "#" "&& reload_completed" [(set (match_dup 0) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0)) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0)) (parallel [(set (match_dup 0) (plus:QI (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0) (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "" @@ -7543,10 +7513,8 @@ (subreg:SWI248 (plus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0) (match_operand:QI 2 "general_operand" "QnBn,QnBn")) 0)) (clobber (reg:CC FLAGS_REG))] "" @@ -7581,8 +7549,8 @@ (subreg:SWI248 (plus:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0)) (clobber (reg:CC FLAGS_REG))])] "" @@ -7602,15 +7570,11 @@ (subreg:SWI248 (plusminus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "<comm>0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "<comm>0,!Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q,Q") - (const_int 8) - (const_int 8)]) 0)) 0)) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q,Q")]) 0)) 0)) (clobber (reg:CC FLAGS_REG))] "" "@ @@ -7629,11 +7593,11 @@ (subreg:SWI248 (plusminus:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0)) 0)) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0)) 0)) (clobber (reg:CC FLAGS_REG))])] "" [(set_attr "type" "alu") @@ -8230,10 +8194,8 @@ (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,!qm") (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q,Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q,Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "@ @@ -8247,8 +8209,8 @@ (minus:QI (match_dup 0) (subreg:QI - (match_op_dup 3 - [(match_dup 2) (const_int 8) (const_int 8)]) 0))) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0))) (clobber (reg:CC FLAGS_REG))])] "" [(set_attr "type" "alu") @@ -8258,30 +8220,26 @@ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+&Q")) (minus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "#" "&& reload_completed" [(set (strict_low_part (match_dup 0)) (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0)) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0)) (parallel [(set (strict_low_part (match_dup 0)) (minus:QI (match_dup 0) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0))) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0))) (clobber (reg:CC FLAGS_REG))])] "" [(set_attr "type" "alu") @@ -8332,10 +8290,8 @@ (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0") (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "" "sub{b}\t{%h2, %0|%0, %h2}" @@ -8347,30 +8303,26 @@ [(set (match_operand:QI 0 "register_operand" "=&Q") (minus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "" "#" "&& reload_completed" [(set (match_dup 0) (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0)) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0)) (parallel [(set (match_dup 0) (minus:QI (match_dup 0) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0))) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0))) (clobber (reg:CC FLAGS_REG))])] "" [(set_attr "type" "alu") @@ -8385,10 +8337,8 @@ (subreg:SWI248 (minus:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0) (match_operand:QI 2 "general_operand" "QnBn,QnBn")) 0)) (clobber (reg:CC FLAGS_REG))] "" @@ -8407,8 +8357,8 @@ (subreg:SWI248 (minus:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0)) (clobber (reg:CC FLAGS_REG))])] "" @@ -12356,10 +12306,8 @@ (compare (and:QI (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 0 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 0 "int248_register_operand" "Q")]) 0) (match_operand:QI 1 "general_operand" "QnBn")) (const_int 0)))] "ix86_match_ccmode (insn, CCNOmode)" @@ -12373,15 +12321,11 @@ (compare (and:QI (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 0 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 0 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0)) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0)) (const_int 0)))] "ix86_match_ccmode (insn, CCNOmode)" "test{b}\t{%h1, %h0|%h0, %h1}" @@ -12970,10 +12914,8 @@ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+Q,&Q")) (any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q,Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q,Q")]) 0) (match_operand:QI 1 "nonimmediate_operand" "0,!qm"))) (clobber (reg:CC FLAGS_REG))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" @@ -12987,8 +12929,8 @@ [(set (strict_low_part (match_dup 0)) (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 2) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0) (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "" @@ -12999,29 +12941,25 @@ [(set (strict_low_part (match_operand:QI 0 "register_operand" "+&Q")) (any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)" "#" "&& reload_completed" [(set (strict_low_part (match_dup 0)) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0)) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0)) (parallel [(set (strict_low_part (match_dup 0)) (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0) (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "" @@ -13224,10 +13162,8 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=QBn") (any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0) (match_operand:QI 1 "nonimmediate_operand" "0"))) (clobber (reg:CC FLAGS_REG))] "" @@ -13240,29 +13176,25 @@ [(set (match_operand:QI 0 "register_operand" "=&Q") (any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q") - (const_int 8) - (const_int 8)]) 0))) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q")]) 0))) (clobber (reg:CC FLAGS_REG))] "" "#" "&& reload_completed" [(set (match_dup 0) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0)) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0)) (parallel [(set (match_dup 0) (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0) (match_dup 0))) (clobber (reg:CC FLAGS_REG))])] "" @@ -13292,10 +13224,8 @@ (subreg:SWI248 (any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0) (match_operand:QI 2 "general_operand" "QnBn,QnBn")) 0)) (clobber (reg:CC FLAGS_REG))] "" @@ -13314,8 +13244,8 @@ (subreg:SWI248 (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0)) (clobber (reg:CC FLAGS_REG))])] "" @@ -13329,10 +13259,8 @@ (match_operator 5 "compare_operator" [(any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0) (match_operand:QI 2 "general_operand" "QnBn,QnBn")) (const_int 0)])) (set (zero_extract:SWI248 @@ -13342,8 +13270,8 @@ (subreg:SWI248 (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0))] "ix86_match_ccmode (insn, CCNOmode)" "@ @@ -13359,9 +13287,9 @@ [(set (match_dup 4) (match_op_dup 5 [(any_logic:QI - (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (subreg:QI + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) (const_int 0)])) (set (zero_extract:SWI248 @@ -13369,8 +13297,8 @@ (subreg:SWI248 (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 1) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 1) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0))])] "" [(set_attr "addr" "gpr8") @@ -13386,15 +13314,11 @@ (subreg:SWI248 (any_logic:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "%0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "%0,!Q")]) 0) (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand" "Q,Q") - (const_int 8) - (const_int 8)]) 0)) 0)) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand" "Q,Q")]) 0)) 0)) (clobber (reg:CC FLAGS_REG))] "" "@ @@ -13413,11 +13337,11 @@ (subreg:SWI248 (any_logic:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (subreg:QI - (match_op_dup 4 - [(match_dup 2) (const_int 8) (const_int 8)]) 0)) 0)) + (zero_extract:SWI248 + (match_dup 2) (const_int 8) (const_int 8)) 0)) 0)) (clobber (reg:CC FLAGS_REG))])] "" [(set_attr "type" "alu") @@ -13429,12 +13353,10 @@ (match_operand 0 "int248_register_operand" "+Q,&Q") (const_int 8) (const_int 8)) - (match_operator:SWI248 3 "extract_operator" + (match_operator:SWI248 3 "extract_high_operator" [(any_logic (match_operand 1 "int248_register_operand" "%0,!Q") - (match_operand 2 "int248_register_operand" "Q,Q")) - (const_int 8) - (const_int 8)])) + (match_operand 2 "int248_register_operand" "Q,Q"))])) (clobber (reg:CC FLAGS_REG))] "GET_MODE (operands[1]) == GET_MODE (operands[2])" "@ @@ -13450,9 +13372,9 @@ (parallel [(set (zero_extract:SWI248 (match_dup 0) (const_int 8) (const_int 8)) - (match_op_dup 3 - [(any_logic (match_dup 4) (match_dup 2)) - (const_int 8) (const_int 8)])) + (zero_extract:SWI248 + (any_logic (match_dup 4) (match_dup 2)) + (const_int 8) (const_int 8))) (clobber (reg:CC FLAGS_REG))])] "operands[4] = gen_lowpart (GET_MODE (operands[1]), operands[0]);" [(set_attr "type" "alu") @@ -14697,10 +14619,8 @@ (subreg:SWI248 (neg:QI (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0)) 0)) + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0)) 0)) (clobber (reg:CC FLAGS_REG))] "" "@ @@ -14718,8 +14638,8 @@ (subreg:SWI248 (neg:QI (subreg:QI - (match_op_dup 2 - [(match_dup 0) (const_int 8) (const_int 8)]) 0)) 0)) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0)) 0)) (clobber (reg:CC FLAGS_REG))])] "" [(set_attr "type" "negnot") @@ -15351,13 +15271,9 @@ (match_operand 0 "int248_register_operand" "+Q,&Q") (const_int 8) (const_int 8)) - (subreg:SWI248 - (not:QI - (subreg:QI - (match_operator:SWI248 2 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0)) 0))] + (not:SWI248 + (match_operator:SWI248 2 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")])))] "" "@ not{b}\t%h0 @@ -15370,11 +15286,8 @@ (match_dup 1) (const_int 8) (const_int 8))) (set (zero_extract:SWI248 (match_dup 0) (const_int 8) (const_int 8)) - (subreg:SWI248 - (not:QI - (subreg:QI - (match_op_dup 2 - [(match_dup 0) (const_int 8) (const_int 8)]) 0)) 0))] + (not:SWI248 + (zero_extract:SWI248 (match_dup 0) (const_int 8) (const_int 8))))] "" [(set_attr "type" "negnot") (set_attr "mode" "QI")]) @@ -16721,10 +16634,8 @@ (subreg:SWI248 (ashift:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0) (match_operand:QI 2 "nonmemory_operand" "cI,cI")) 0)) (clobber (reg:CC FLAGS_REG))] "" @@ -16758,8 +16669,8 @@ (subreg:SWI248 (ashift:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0)) (clobber (reg:CC FLAGS_REG))])] "" @@ -18005,10 +17916,8 @@ (subreg:SWI248 (any_shiftrt:QI (subreg:QI - (match_operator:SWI248 3 "extract_operator" - [(match_operand 1 "int248_register_operand" "0,!Q") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 3 "extract_high_operator" + [(match_operand 1 "int248_register_operand" "0,!Q")]) 0) (match_operand:QI 2 "nonmemory_operand" "cI,cI")) 0)) (clobber (reg:CC FLAGS_REG))] "" @@ -18034,8 +17943,8 @@ (subreg:SWI248 (any_shiftrt:QI (subreg:QI - (match_op_dup 3 - [(match_dup 0) (const_int 8) (const_int 8)]) 0) + (zero_extract:SWI248 + (match_dup 0) (const_int 8) (const_int 8)) 0) (match_dup 2)) 0)) (clobber (reg:CC FLAGS_REG))])] "" @@ -28252,10 +28161,8 @@ (match_operator 1 "compare_operator" [(and:QI (subreg:QI - (match_operator:SWI248 4 "extract_operator" - [(match_operand 2 "int248_register_operand") - (const_int 8) - (const_int 8)]) 0) + (match_operator:SWI248 4 "extract_high_operator" + [(match_operand 2 "int248_register_operand")]) 0) (match_operand 3 "const_int_operand")) (const_int 0)]))] "! TARGET_PARTIAL_REG_STALL @@ -28267,9 +28174,9 @@ (match_op_dup 1 [(and:QI (subreg:QI - (match_op_dup 4 [(match_dup 2) - (const_int 8) - (const_int 8)]) 0) + (zero_extract:SWI248 (match_dup 2) + (const_int 8) + (const_int 8)) 0) (match_dup 3)) (const_int 0)])) (set (zero_extract:SWI248 (match_dup 2) @@ -28278,9 +28185,9 @@ (subreg:SWI248 (and:QI (subreg:QI - (match_op_dup 4 [(match_dup 2) - (const_int 8) - (const_int 8)]) 0) + (zero_extract:SWI248 (match_dup 2) + (const_int 8) + (const_int 8)) 0) (match_dup 3)) 0))])]) ;; Don't do logical operations with memory inputs. diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index b2d2eec..0f31090 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1740,8 +1740,12 @@ (define_predicate "compare_operator" (match_code "compare")) -(define_predicate "extract_operator" - (match_code "zero_extract,sign_extract")) +(define_predicate "extract_high_operator" + (match_code "zero_extract,sign_extract,ashiftrt,lshiftrt") +{ + return (const8_operand (XEXP (op, 1), VOIDmode) + && (BINARY_P (op) || const8_operand (XEXP (op, 2), VOIDmode))); +}) ;; Return true if OP is a memory operand, aligned to ;; less than its natural alignment. diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 0a9fcef..e0d8904 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -13867,9 +13867,9 @@ riscv_expand_xmode_usmul (rtx dest, rtx x, rtx y) riscv_emit_binary (MULT, mul, x, y); if (TARGET_64BIT) - emit_insn (gen_usmuldi3_highpart (mulhu, x, y)); + emit_insn (gen_umuldi3_highpart (mulhu, x, y)); else - emit_insn (gen_usmulsi3_highpart (mulhu, x, y)); + emit_insn (gen_umulsi3_highpart (mulhu, x, y)); riscv_emit_binary (NE, overflow_p, mulhu, CONST0_RTX (Xmode)); riscv_emit_unary (NEG, overflow_p, overflow_p); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3f76afd..cb4ff09 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2025-08-05 Jason Merrill <jason@redhat.com> + + PR c++/121068 + * constexpr.cc (cxx_eval_store_expression): Handle clobbers. + (potential_constant_expression_1): Handle clobbers more. + * decl.cc (build_clobber_this): Use INIT_EXPR for initial clobber. + * init.cc (build_new_1): Clobber on placement new. + (build_vec_init): Don't clean up after clobber. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/121351 + PR c++/119859 + * class.cc (add_method): Substitute outer template arguments + into constraints before comparing them if the declarations are + from different classes. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/120620 + * constexpr.cc (cxx_dynamic_cast_fn_p): Return true only + for synthesized __dynamic_cast. + 2025-08-01 Nathaniel Shead <nathanieloshead@gmail.com> PR c++/108080 diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index f5d20e5..14acb9c 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -1356,7 +1356,30 @@ add_method (tree type, tree method, bool via_using) if (!compparms (parms1, parms2)) continue; - if (!equivalently_constrained (fn, method)) + tree fn_constraints = get_constraints (fn); + tree method_constraints = get_constraints (method); + + if (fn_constraints && method_constraints + && DECL_CONTEXT (fn) != type + && !processing_template_decl) + { + if (TREE_CODE (fn) == TEMPLATE_DECL) + ++processing_template_decl; + if (tree ti = CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (fn))) + fn_constraints = tsubst_constraint_info (fn_constraints, + TI_ARGS (ti), + tf_warning_or_error, + fn); + if (tree ti = CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (method))) + method_constraints = tsubst_constraint_info (method_constraints, + TI_ARGS (ti), + tf_warning_or_error, + method); + if (TREE_CODE (fn) == TEMPLATE_DECL) + --processing_template_decl; + } + + if (!equivalent_constraints (fn_constraints, method_constraints)) { if (processing_template_decl) /* We can't check satisfaction in dependent context, wait until diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index be24ae2..65b91ec 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -3240,7 +3240,11 @@ cxx_dynamic_cast_fn_p (tree fndecl) { return (cxx_dialect >= cxx20 && id_equal (DECL_NAME (fndecl), "__dynamic_cast") - && CP_DECL_CONTEXT (fndecl) == abi_node); + && CP_DECL_CONTEXT (fndecl) == abi_node + /* Only consider implementation-detail __dynamic_cast calls that + correspond to a dynamic_cast, and ignore direct calls to + abi::__dynamic_cast. */ + && DECL_ARTIFICIAL (fndecl)); } /* Often, we have an expression in the form of address + offset, e.g. @@ -7448,12 +7452,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, tree init = TREE_OPERAND (t, 1); - if (TREE_CLOBBER_P (init) - && CLOBBER_KIND (init) < CLOBBER_OBJECT_END) - /* Only handle clobbers ending the lifetime of objects. - ??? We should probably set CONSTRUCTOR_NO_CLEARING. */ - return void_node; - /* First we figure out where we're storing to. */ tree target = TREE_OPERAND (t, 0); @@ -7640,11 +7638,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, } /* Handle explicit end-of-lifetime. */ - if (TREE_CLOBBER_P (init)) + if (TREE_CLOBBER_P (init) + && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END) { if (refs->is_empty ()) - ctx->global->destroy_value (object); - return void_node; + { + ctx->global->destroy_value (object); + return void_node; + } } type = TREE_TYPE (object); @@ -7781,6 +7782,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; } else if (!is_access_expr + || (TREE_CLOBBER_P (init) + && CLOBBER_KIND (init) >= CLOBBER_OBJECT_END) || (TREE_CODE (t) == MODIFY_EXPR && CLASS_TYPE_P (inner) && !type_has_non_deleted_trivial_default_ctor (inner))) @@ -7844,11 +7847,17 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, type = reftype; } + /* Change an "as-base" clobber to the real type; + we don't need to worry about padding in constexpr. */ + tree itype = initialized_type (init); + if (IS_FAKE_BASE_TYPE (itype)) + itype = TYPE_CONTEXT (itype); + /* 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. */ if (!empty_base && !(same_type_ignoring_top_level_qualifiers_p - (initialized_type (init), type))) + (itype, type))) { gcc_assert (is_empty_class (TREE_TYPE (target))); empty_base = true; @@ -7955,8 +7964,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, /* Don't share a CONSTRUCTOR that might be changed later. */ init = unshare_constructor (init); - gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (*valp), type))); + gcc_checking_assert (!*valp + || *valp == void_node + || (same_type_ignoring_top_level_qualifiers_p + (TREE_TYPE (*valp), type))); if (empty_base) { /* Just evaluate the initializer and return, since there's no actual data @@ -7969,6 +7980,22 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits; } } + else if (TREE_CLOBBER_P (init)) + { + if (AGGREGATE_TYPE_P (type)) + { + if (*valp) + CONSTRUCTOR_ELTS (*valp) = nullptr; + else + *valp = build_constructor (type, nullptr); + TREE_CONSTANT (*valp) = true; + TREE_SIDE_EFFECTS (*valp) = false; + CONSTRUCTOR_NO_CLEARING (*valp) = true; + CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits; + } + else + *valp = void_node; + } else if (*valp && TREE_CODE (*valp) == CONSTRUCTOR && TREE_CODE (init) == CONSTRUCTOR) { @@ -7993,6 +8020,9 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, && TREE_CODE (*valp) == CONSTRUCTOR && TYPE_READONLY (type)) { + tree target_type = TREE_TYPE (target); + if (IS_FAKE_BASE_TYPE (target_type)) + target_type = TYPE_CONTEXT (target_type); if (INDIRECT_REF_P (target) && (is_this_parameter (tree_strip_nop_conversions (TREE_OPERAND (target, 0))))) @@ -8000,7 +8030,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, constructor of a delegating constructor). Leave it up to the caller that set 'this' to set TREE_READONLY appropriately. */ gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (target), type) || empty_base); + (target_type, type) || empty_base); else TREE_READONLY (*valp) = true; } @@ -11304,6 +11334,13 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, && !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t)) && !NULLPTR_TYPE_P (TREE_TYPE (t))) { + if (TREE_CLOBBER_P (t)) + { + /* We should have caught any clobbers in INIT/MODIFY_EXPR. */ + gcc_checking_assert (false); + return true; + } + if (flags & tf_error) constexpr_error (loc, fundef_p, "lvalue-to-rvalue conversion of " "a volatile lvalue %qE with type %qT", t, @@ -12127,6 +12164,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } /* FALLTHRU */ case INIT_EXPR: + if (TREE_CLOBBER_P (TREE_OPERAND (t, 1))) + return true; return RECUR (TREE_OPERAND (t, 1), rval); case CONSTRUCTOR: diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index cb3ebff..8122fca 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -18440,6 +18440,8 @@ build_clobber_this (clobber_kind kind) } tree exprstmt = build2 (MODIFY_EXPR, void_type_node, thisref, clobber); + if (kind == CLOBBER_OBJECT_BEGIN) + TREE_SET_CODE (exprstmt, INIT_EXPR); if (vbases) exprstmt = build_if_in_charge (exprstmt); diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 09fb4f3..f19794c 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3557,9 +3557,19 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, alloc_expr = maybe_wrap_new_for_constexpr (alloc_expr, type, cookie_size); + bool std_placement = std_placement_new_fn_p (alloc_fn); + + /* For std placement new, clobber the object if the constructor won't do it + in start_preparsed_function. This is most important for activating an + array in a union (c++/121068), but should also help the optimizers. */ + const bool do_clobber + = (std_placement && !*init && flag_lifetime_dse > 1 + && (!CLASS_TYPE_P (elt_type) + || type_has_non_user_provided_default_constructor (elt_type))); + /* In the simple case, we can stop now. */ pointer_type = build_pointer_type (type); - if (!cookie_size && !is_initialized && !member_delete_p) + if (!cookie_size && !is_initialized && !member_delete_p && !do_clobber) return build_nop (pointer_type, alloc_expr); /* Store the result of the allocation call in a variable so that we can @@ -3593,8 +3603,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, So check for a null exception spec on the op new we just called. */ nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn)); - check_new - = flag_check_new || (nothrow && !std_placement_new_fn_p (alloc_fn)); + check_new = flag_check_new || (nothrow && !std_placement); if (cookie_size) { @@ -3649,6 +3658,29 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, /* Any further uses of alloc_node will want this type, too. */ alloc_node = fold_convert (non_const_pointer_type, alloc_node); + tree clobber_expr = NULL_TREE; + if (do_clobber) + { + tree clobber = build_clobber (elt_type, CLOBBER_OBJECT_BEGIN); + CONSTRUCTOR_IS_DIRECT_INIT (clobber) = true; + if (array_p) + { + /* Clobber each element rather than the array at once. */ + tree maxindex = cp_build_binary_op (input_location, + MINUS_EXPR, outer_nelts, + integer_one_node, + complain); + clobber_expr = build_vec_init (data_addr, maxindex, clobber, + /*valinit*/false, /*from_arr*/0, + complain, nullptr); + } + else + { + tree targ = cp_build_fold_indirect_ref (data_addr); + clobber_expr = cp_build_init_expr (targ, clobber); + } + } + /* Now initialize the allocated object. Note that we preevaluate the initialization expression, apart from the actual constructor call or assignment--we do this because we want to delay the allocation as long @@ -3877,6 +3909,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, if (init_expr) rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval); + if (clobber_expr) + rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), clobber_expr, rval); if (cookie_expr) rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval); @@ -4717,6 +4751,9 @@ build_vec_init (tree base, tree maxindex, tree init, the partially constructed array if an exception is thrown. But don't do this if we're assigning. */ if (flag_exceptions && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) + /* And don't clean up from clobbers, the actual initialization will + follow as a separate build_vec_init. */ + && !(init && TREE_CLOBBER_P (init)) && from_array != 2) { tree e; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 860f3f0..a8c54c7 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -42636,8 +42636,11 @@ cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc) to ( variable-list ) OpenMP 5.1: - from ( [present :] variable-list ) - to ( [present :] variable-list ) */ + from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list ) + + motion-modifier: + present | iterator (iterators-definition) */ static tree cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind, @@ -42646,23 +42649,113 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - bool present = false; - cp_token *token = cp_lexer_peek_token (parser->lexer); + int pos = 1; + int colon_pos = 0; + int iterator_length = 0; - if (token->type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (token->u.value), "present") == 0 - && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME) { - present = true; - cp_lexer_consume_token (parser->lexer); - cp_lexer_consume_token (parser->lexer); + const char *identifier = + IDENTIFIER_POINTER (cp_lexer_peek_nth_token (parser->lexer, + pos)->u.value); + if (cp_lexer_nth_token_is (parser->lexer, pos + 1, CPP_OPEN_PAREN)) + { + int n = cp_parser_skip_balanced_tokens (parser, pos + 1); + if (n != pos + 1) + { + if (strcmp (identifier, "iterator") == 0) + iterator_length = n - pos; + pos = n - 1; + } + } + if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) + pos += 2; + else + pos++; + if (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_COLON) + { + colon_pos = pos; + break; + } } + bool present = false; + tree iterators = NULL_TREE; + + for (int pos = 1; pos < colon_pos; ++pos) + { + cp_token *token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_COMMA) + { + cp_lexer_consume_token (parser->lexer); + continue; + } + const char *p = IDENTIFIER_POINTER (token->u.value); + if (strcmp ("present", p) == 0) + { + if (present) + { + cp_parser_error (parser, "too many %<present%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + present = true; + cp_lexer_consume_token (parser->lexer); + } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + cp_parser_error (parser, "too many %<iterator%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + pos += iterator_length - 1; + } + + else + { + error_at (token->location, + "%qs clause with modifier other than %<iterator%> " + "or %<present%>", + kind == OMP_CLAUSE_TO ? "to" : "from"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + } + + if (colon_pos) + cp_parser_require (parser, CPP_COLON, RT_COLON); + tree nl = cp_parser_omp_var_list_no_open (parser, kind, list, NULL, true); if (present) for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_MOTION_PRESENT (c) = 1; + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + + if (iterators) + for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_ITERATORS (c) = iterators; + return nl; } @@ -42696,16 +42789,34 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) int pos = 1; int map_kind_pos = 0; - while (cp_lexer_peek_nth_token (parser->lexer, pos)->type == CPP_NAME - || cp_lexer_peek_nth_token (parser->lexer, pos)->keyword == RID_DELETE) + int iterator_length = 0; + for (;;) { - if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COLON) + cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, pos); + if (!(tok->type == CPP_NAME || tok->keyword == RID_DELETE)) + break; + + cp_token *next_tok = cp_lexer_peek_nth_token (parser->lexer, pos + 1); + if (tok->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (tok->u.value), "iterator") == 0 + && next_tok->type == CPP_OPEN_PAREN) + { + int n = cp_parser_skip_balanced_tokens (parser, pos + 1); + if (n != pos + 1) + { + iterator_length = n - pos; + pos = n - 1; + next_tok = cp_lexer_peek_nth_token (parser->lexer, n); + } + } + + if (next_tok->type == CPP_COLON) { map_kind_pos = pos; break; } - if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_COMMA) + if (next_tok->type == CPP_COMMA) pos++; else if (cp_lexer_peek_nth_token (parser->lexer, pos + 1)->type == CPP_OPEN_PAREN) @@ -42718,6 +42829,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) bool present_modifier = false; bool mapper_modifier = false; tree mapper_name = NULL_TREE; + tree iterators = NULL_TREE; for (int pos = 1; pos < map_kind_pos; ++pos) { cp_token *tok = cp_lexer_peek_token (parser->lexer); @@ -42756,6 +42868,21 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) close_modifier = true; cp_lexer_consume_token (parser->lexer); } + else if (strcmp ("iterator", p) == 0) + { + if (iterators) + { + cp_parser_error (parser, "too many %<iterator%> modifiers"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + begin_scope (sk_omp, NULL); + iterators = cp_parser_omp_iterators (parser); + pos += iterator_length - 1; + } else if (strcmp ("mapper", p) == 0) { cp_lexer_consume_token (parser->lexer); @@ -42844,7 +42971,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) { cp_parser_error (parser, "%<map%> clause with map-type modifier " "other than %<always%>, %<close%>, " - "%<mapper%> or %<present%>"); + "%<iterator%>, %<mapper%> or %<present%>"); cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, @@ -42908,9 +43035,19 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list, bool declare_mapper_p) tree last_new = NULL_TREE; + if (iterators) + { + tree block = poplevel (1, 1, 0); + if (iterators == error_mark_node) + iterators = NULL_TREE; + else + TREE_VEC_ELT (iterators, 5) = block; + } + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) { OMP_CLAUSE_SET_MAP_KIND (c, kind); + OMP_CLAUSE_ITERATORS (c) = iterators; last_new = c; } diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index be79b50..0c7788d 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -7751,7 +7751,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* We've reached the end of a list of expanded nodes. Reset the group start pointer. */ if (c == grp_sentinel) - grp_start_p = NULL; + { + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc != grp_sentinel; + gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + grp_start_p = NULL; + } switch (OMP_CLAUSE_CODE (c)) { @@ -9003,6 +9010,13 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + if (OMP_CLAUSE_ITERATORS (c) + && cp_omp_finish_iterators (OMP_CLAUSE_ITERATORS (c))) + { + t = error_mark_node; + break; + } + /* FALLTHRU */ case OMP_CLAUSE__CACHE_: { using namespace omp_addr_tokenizer; @@ -9906,6 +9920,11 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); } + if (grp_start_p + && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p)) + for (tree gc = *grp_start_p; gc; gc = OMP_CLAUSE_CHAIN (gc)) + OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p); + if (reduction_seen < 0 && (ordered_seen || schedule_seen)) reduction_seen = -2; diff --git a/gcc/defaults.h b/gcc/defaults.h index 16f6dc2..f807ef6 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -1158,7 +1158,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif #ifndef MAX_FIXED_MODE_SIZE -#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode) +#define MAX_FIXED_MODE_SIZE MAX (BITS_PER_WORD * 2, 64) #endif /* Nonzero if structures and unions should be returned in memory. diff --git a/gcc/diagnostics/buffering.h b/gcc/diagnostics/buffering.h index c3ac070..9b86fee 100644 --- a/gcc/diagnostics/buffering.h +++ b/gcc/diagnostics/buffering.h @@ -36,7 +36,7 @@ class sink; A diagnostics::buffer can be: * flushed to the diagnostics::context, which issues - the diagnostics within the buffer to the output format + the diagnostics within the buffer to the output sinks and checks for limits such as -fmax-errors=, or * moved to another diagnostics::buffer, which moves the diagnostics @@ -45,13 +45,13 @@ class sink; source buffer, or * cleared, which discards any diagnostics within the buffer - without issuing them to the output format. + without issuing them to the output sinks. - Since a buffer needs to contain output-format-specific data, - it's not possible to change the output format of the + Since a buffer needs to contain sink-specific data, + it's not possible to change the output sink(s) of the diagnostics::context once any buffers are non-empty. - To simplify implementing output formats, it's not possible + To simplify implementing output sinks, it's not possible to change buffering on a diagnostics::context whilst within a diagnostic group. */ diff --git a/gcc/diagnostics/context.cc b/gcc/diagnostics/context.cc index 85f7d2a..a1441ca 100644 --- a/gcc/diagnostics/context.cc +++ b/gcc/diagnostics/context.cc @@ -170,7 +170,7 @@ context::initialize (int n_opts) m_text_callbacks.m_html_start_span = default_start_span_fn<to_html>; m_text_callbacks.m_end_diagnostic = default_text_finalizer; - m_option_mgr = nullptr; + m_option_id_mgr = nullptr; m_urlifier_stack = new auto_vec<urlifier_stack_node> (); m_last_location = UNKNOWN_LOCATION; m_client_aux_data = nullptr; @@ -337,8 +337,8 @@ context::finish () m_client_data_hooks = nullptr; } - delete m_option_mgr; - m_option_mgr = nullptr; + delete m_option_id_mgr; + m_option_id_mgr = nullptr; if (m_urlifier_stack) { @@ -465,11 +465,11 @@ context::set_original_argv (unique_argv original_argv) } void -context::set_option_manager (std::unique_ptr<option_manager> mgr, - unsigned lang_mask) +context::set_option_id_manager (std::unique_ptr<option_id_manager> mgr, + unsigned lang_mask) { - delete m_option_mgr; - m_option_mgr = mgr.release (); + delete m_option_id_mgr; + m_option_id_mgr = mgr.release (); m_lang_mask = lang_mask; } @@ -1682,6 +1682,12 @@ context::pop_nesting_level () } void +context::set_nesting_level (int new_level) +{ + m_diagnostic_groups.m_diagnostic_nesting_level = new_level; +} + +void sink::dump (FILE *out, int indent) const { fprintf (out, "%*sprinter:\n", indent, ""); diff --git a/gcc/diagnostics/context.h b/gcc/diagnostics/context.h index f47370b..b6ec85c 100644 --- a/gcc/diagnostics/context.h +++ b/gcc/diagnostics/context.h @@ -23,7 +23,10 @@ along with GCC; see the file COPYING3. If not see #include "lazily-created.h" #include "unique-argv.h" #include "diagnostics/option-classifier.h" +#include "diagnostics/option-id-manager.h" #include "diagnostics/context-options.h" +#include "diagnostics/source-printing-options.h" +#include "diagnostics/counters.h" namespace diagnostics { @@ -81,84 +84,6 @@ typedef void (*text_finalizer_fn) (text_sink &, const diagnostic_info *, enum kind); -/* Abstract base class for the diagnostic subsystem to make queries - about command-line options. */ - -class option_manager -{ -public: - virtual ~option_manager () {} - - /* Return 1 if option OPT_ID is enabled, 0 if it is disabled, - or -1 if it isn't a simple on-off switch - (or if the value is unknown, typically set later in target). */ - virtual int option_enabled_p (option_id opt_id) const = 0; - - /* Return malloced memory for the name of the option OPT_ID - which enabled a diagnostic, originally of type ORIG_DIAG_KIND but - possibly converted to DIAG_KIND by options such as -Werror. - May return NULL if no name is to be printed. - May be passed 0 as well as the index of a particular option. */ - virtual char *make_option_name (option_id opt_id, - enum kind orig_diag_kind, - enum kind diag_kind) const = 0; - - /* Return malloced memory for a URL describing the option that controls - a diagnostic. - May return NULL if no URL is available. - May be passed 0 as well as the index of a particular option. */ - virtual char *make_option_url (option_id opt_id) const = 0; -}; - -/* A bundle of options relating to printing the user's source code - (potentially with a margin, underlining, labels, etc). */ - -struct source_printing_options -{ - /* True if we should print the source line with a caret indicating - the location. - Corresponds to -fdiagnostics-show-caret. */ - bool enabled; - - /* Maximum width of the source line printed. */ - int max_width; - - /* Character used at the caret when printing source locations. */ - char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES]; - - /* When printing source code, should the characters at carets and ranges - be colorized? (assuming colorization is on at all). - This should be true for frontends that generate range information - (so that the ranges of code are colorized), - and false for frontends that merely specify points within the - source code (to avoid e.g. colorizing just the first character in - a token, which would look strange). */ - bool colorize_source_p; - - /* When printing source code, should labelled ranges be printed? - Corresponds to -fdiagnostics-show-labels. */ - bool show_labels_p; - - /* When printing source code, should there be a left-hand margin - showing line numbers? - Corresponds to -fdiagnostics-show-line-numbers. */ - bool show_line_numbers_p; - - /* If printing source code, what should the minimum width of the margin - be? Line numbers will be right-aligned, and padded to this width. - Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */ - int min_margin_width; - - /* Usable by plugins; if true, print a debugging ruler above the - source output. */ - bool show_ruler_p; - - /* When printing events in an inline path, should we print lines - visualizing links between related events (e.g. for CFG paths)? - Corresponds to -fdiagnostics-show-event-links. */ - bool show_event_links_p; -}; - /* A bundle of state for determining column numbers in diagnostics (tab stops, whether to start at 0 or 1, etc). Uses a file_cache to handle tabs. */ @@ -291,28 +216,6 @@ private: enum diagnostics_escape_format m_escape_format; }; -/* A collection of counters of diagnostics, per-kind - (e.g. "3 errors and 1 warning"), for use by both context - and by diagnostics::buffer. */ - -struct counters -{ - counters (); - - void dump (FILE *out, int indent) const; - void DEBUG_FUNCTION dump () const { dump (stderr, 0); } - - int get_count (enum kind kind) const - { - return m_count_for_kind[static_cast<size_t> (kind)]; - } - - void move_to (counters &dest); - void clear (); - - int m_count_for_kind[static_cast<size_t> (kind::last_diagnostic_kind)]; -}; - /* This class encapsulates the state of the diagnostics subsystem as a whole (either directly, or via owned objects of other classes, to avoid global variables). @@ -334,7 +237,7 @@ struct counters - an optional urlifier to inject URLs into formatted messages - counting the number of diagnostics reported of each kind (class diagnostics::counters) - - calling out to a option_manager to determine if + - calling out to a option_id_manager to determine if a particular warning is enabled or disabled - tracking pragmas that enable/disable warnings in a range of source code @@ -398,6 +301,7 @@ public: void push_nesting_level (); void pop_nesting_level (); + void set_nesting_level (int new_level); bool warning_enabled_at (location_t loc, option_id opt_id); @@ -546,32 +450,32 @@ public: /* Option-related member functions. */ inline bool option_enabled_p (option_id opt_id) const { - if (!m_option_mgr) + if (!m_option_id_mgr) return true; - return m_option_mgr->option_enabled_p (opt_id); + return m_option_id_mgr->option_enabled_p (opt_id); } inline char *make_option_name (option_id opt_id, enum kind orig_diag_kind, enum kind diag_kind) const { - if (!m_option_mgr) + if (!m_option_id_mgr) return nullptr; - return m_option_mgr->make_option_name (opt_id, - orig_diag_kind, - diag_kind); + return m_option_id_mgr->make_option_name (opt_id, + orig_diag_kind, + diag_kind); } inline char *make_option_url (option_id opt_id) const { - if (!m_option_mgr) + if (!m_option_id_mgr) return nullptr; - return m_option_mgr->make_option_url (opt_id); + return m_option_id_mgr->make_option_url (opt_id); } void - set_option_manager (std::unique_ptr<option_manager> mgr, - unsigned lang_mask); + set_option_id_manager (std::unique_ptr<option_id_manager> option_id_mgr, + unsigned lang_mask); unsigned get_lang_mask () const { @@ -808,7 +712,7 @@ private: /* Owned by the context; this would be a std::unique_ptr if context had a proper ctor. */ - option_manager *m_option_mgr; + option_id_manager *m_option_id_mgr; unsigned m_lang_mask; /* A stack of optional hooks for adding URLs to quoted text strings in diff --git a/gcc/diagnostics/counters.h b/gcc/diagnostics/counters.h new file mode 100644 index 0000000..42db3fe --- /dev/null +++ b/gcc/diagnostics/counters.h @@ -0,0 +1,51 @@ +/* Counts of per-kind diagnostics. + Copyright (C) 2000-2025 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_DIAGNOSTICS_COUNTERS_H +#define GCC_DIAGNOSTICS_COUNTERS_H + +#include "diagnostics/kinds.h" + +namespace diagnostics { + +/* A collection of counters of diagnostics, per-kind + (e.g. "3 errors and 1 warning"), for use by both diagnostics::context + and by diagnostics::buffer. */ + +struct counters +{ + counters (); + + void dump (FILE *out, int indent) const; + void DEBUG_FUNCTION dump () const { dump (stderr, 0); } + + int get_count (enum kind kind) const + { + return m_count_for_kind[static_cast<size_t> (kind)]; + } + + void move_to (counters &dest); + void clear (); + + int m_count_for_kind[static_cast<size_t> (kind::last_diagnostic_kind)]; +}; + +} // namespace diagnostics + +#endif /* ! GCC_DIAGNOSTICS_COUNTERS_H */ diff --git a/gcc/diagnostics/html-sink.cc b/gcc/diagnostics/html-sink.cc index 13d6309..934d8e2 100644 --- a/gcc/diagnostics/html-sink.cc +++ b/gcc/diagnostics/html-sink.cc @@ -1018,10 +1018,11 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, // Add any metadata as a suffix to the message if (diagnostic.m_metadata) - { - xp.add_text (" "); - xp.append (make_element_for_metadata (*diagnostic.m_metadata)); - } + if (auto e = make_element_for_metadata (*diagnostic.m_metadata)) + { + xp.add_text (" "); + xp.append (std::move (e)); + } // Add any option as a suffix to the message @@ -1234,6 +1235,9 @@ html_builder::make_element_for_metadata (const metadata &m) (make_metadata_element (std::move (label), std::move (url))); } + if (span_metadata->m_children.empty ()) + return nullptr; + return span_metadata; } diff --git a/gcc/diagnostics/lazy-paths.cc b/gcc/diagnostics/lazy-paths.cc index 4934651..f246eea 100644 --- a/gcc/diagnostics/lazy-paths.cc +++ b/gcc/diagnostics/lazy-paths.cc @@ -125,12 +125,12 @@ test_intraprocedural_path (pretty_printer *event_pp) "double `free'"); } -/* Implementation of diagnostics::option_manager for which all +/* Implementation of diagnostics::option_id_manager for which all options are disabled, for use in selftests. Note that this is *not* called for option_id (0), which means "always warn" */ -class all_warnings_disabled : public diagnostics::option_manager +class all_warnings_disabled : public diagnostics::option_id_manager { public: int option_enabled_p (diagnostics::option_id) const final override @@ -168,7 +168,7 @@ test_emission (pretty_printer *event_pp) is skipped. */ { test_context dc; - dc.set_option_manager (std::make_unique<all_warnings_disabled> (), 0); + dc.set_option_id_manager (std::make_unique<all_warnings_disabled> (), 0); test_rich_location rich_loc (*event_pp); ASSERT_FALSE (rich_loc.m_path.generated_p ()); diff --git a/gcc/diagnostics/option-id-manager.h b/gcc/diagnostics/option-id-manager.h new file mode 100644 index 0000000..08add5b --- /dev/null +++ b/gcc/diagnostics/option-id-manager.h @@ -0,0 +1,56 @@ +/* Hooks for giving client-specific meaning to option ids. + Copyright (C) 2000-2025 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_DIAGNOSTICS_OPTION_ID_MANAGER_H +#define GCC_DIAGNOSTICS_OPTION_ID_MANAGER_H + +namespace diagnostics { + +/* Abstract base class for the diagnostic subsystem to make queries + about command-line options. */ + +class option_id_manager +{ +public: + virtual ~option_id_manager () {} + + /* Return 1 if option OPT_ID is enabled, 0 if it is disabled, + or -1 if it isn't a simple on-off switch + (or if the value is unknown, typically set later in target). */ + virtual int option_enabled_p (option_id opt_id) const = 0; + + /* Return malloced memory for the name of the option OPT_ID + which enabled a diagnostic, originally of type ORIG_DIAG_KIND but + possibly converted to DIAG_KIND by options such as -Werror. + May return NULL if no name is to be printed. + May be passed 0 as well as the index of a particular option. */ + virtual char *make_option_name (option_id opt_id, + enum kind orig_diag_kind, + enum kind diag_kind) const = 0; + + /* Return malloced memory for a URL describing the option that controls + a diagnostic. + May return NULL if no URL is available. + May be passed 0 as well as the index of a particular option. */ + virtual char *make_option_url (option_id opt_id) const = 0; +}; + +} // namespace diagnostics + +#endif /* ! GCC_DIAGNOSTICS_OPTION_ID_MANAGER_H */ diff --git a/gcc/diagnostics/source-printing-options.h b/gcc/diagnostics/source-printing-options.h new file mode 100644 index 0000000..362b691 --- /dev/null +++ b/gcc/diagnostics/source-printing-options.h @@ -0,0 +1,76 @@ +/* Options relating to printing the user's source code. + Copyright (C) 2000-2025 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_DIAGNOSTICS_SOURCE_PRINTING_OPTIONS_H +#define GCC_DIAGNOSTICS_SOURCE_PRINTING_OPTIONS_H + +namespace diagnostics { + +/* A bundle of options relating to printing the user's source code + (potentially with a margin, underlining, labels, etc). */ + +struct source_printing_options +{ + /* True if we should print the source line with a caret indicating + the location. + Corresponds to -fdiagnostics-show-caret. */ + bool enabled; + + /* Maximum width of the source line printed. */ + int max_width; + + /* Character used at the caret when printing source locations. */ + char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES]; + + /* When printing source code, should the characters at carets and ranges + be colorized? (assuming colorization is on at all). + This should be true for frontends that generate range information + (so that the ranges of code are colorized), + and false for frontends that merely specify points within the + source code (to avoid e.g. colorizing just the first character in + a token, which would look strange). */ + bool colorize_source_p; + + /* When printing source code, should labelled ranges be printed? + Corresponds to -fdiagnostics-show-labels. */ + bool show_labels_p; + + /* When printing source code, should there be a left-hand margin + showing line numbers? + Corresponds to -fdiagnostics-show-line-numbers. */ + bool show_line_numbers_p; + + /* If printing source code, what should the minimum width of the margin + be? Line numbers will be right-aligned, and padded to this width. + Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */ + int min_margin_width; + + /* Usable by plugins; if true, print a debugging ruler above the + source output. */ + bool show_ruler_p; + + /* When printing events in an inline path, should we print lines + visualizing links between related events (e.g. for CFG paths)? + Corresponds to -fdiagnostics-show-event-links. */ + bool show_event_links_p; +}; + +} // namespace diagnostics + +#endif /* ! GCC_DIAGNOSTICS_SOURCE_PRINTING_OPTIONS_H */ diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index f3f1445..64c1217 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -1887,8 +1887,8 @@ Produce code conforming to version 20191213. In the absence of this configuration option the default version is 20191213. @item --enable-__cxa_atexit -Define if you want to use @code{__cxa_atexit}, rather than atexit, to -register C++ destructors for local statics and global objects. +Define if you want to use @code{__cxa_atexit}, rather than @code{atexit}, +to register C++ destructors for local statics and global objects. This is essential for fully standards-compliant handling of destructors, but requires @code{__cxa_atexit} in libc. This option is currently only available on systems with GNU libc. When enabled, this diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c1e708b..105a60d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -20612,18 +20612,22 @@ LTO output files. @opindex fdump-rtl-@var{pass} @item -d@var{letters} @itemx -fdump-rtl-@var{pass} -@itemx -fdump-rtl-@var{pass}=@var{filename} +@itemx -fdump-rtl-@var{pass}-@var{options} +@itemx -fdump-rtl-@var{pass}-@var{options}=@var{filename} Says to make debugging dumps during compilation at times specified by -@var{letters}. This is used for debugging the RTL-based passes of the +@var{letters} when using @option{-d} or by @var{pass} when using +@option{-fdump-rtl}. This is used for debugging the RTL-based passes of the compiler. Some @option{-d@var{letters}} switches have different meaning when @option{-E} is used for preprocessing. @xref{Preprocessor Options}, for information about preprocessor-specific dump options. -Debug dumps can be enabled with a @option{-fdump-rtl} switch or some -@option{-d} option @var{letters}. Here are the possible -letters for use in @var{pass} and @var{letters}, and their meanings: +The @samp{-@var{options}} form allows greater control over the details of the +dump. See @option{-fdump-tree}. + +Here are actual instances of command-line options following these patterns and +their meanings: @table @gcctabopt @@ -21150,8 +21154,7 @@ GraphViz to @file{@var{file}.@var{passid}.@var{pass}.dot}. Each function in the file is pretty-printed as a subgraph, so that GraphViz can render them all in a single plot. -This option currently only works for RTL dumps, and the RTL is always -dumped in slim form. +RTL is always dumped in slim form. @item vops Enable showing virtual operands for every statement. @item lineno diff --git a/gcc/doc/libgdiagnostics/topics/compatibility.rst b/gcc/doc/libgdiagnostics/topics/compatibility.rst index 0ca41a3..ccf1236 100644 --- a/gcc/doc/libgdiagnostics/topics/compatibility.rst +++ b/gcc/doc/libgdiagnostics/topics/compatibility.rst @@ -262,3 +262,12 @@ working with :type:`diagnostic_message_buffer`. * :func:`diagnostic_add_location_with_label_via_msg_buf` * :func:`diagnostic_execution_path_add_event_via_msg_buf` + +.. _LIBGDIAGNOSTICS_ABI_5: + +``LIBGDIAGNOSTICS_ABI_5`` +------------------------- + +``LIBGDIAGNOSTICS_ABI_5`` covers the addition of this function: + + * :func:`diagnostic_manager_set_debug_physical_locations` diff --git a/gcc/doc/libgdiagnostics/topics/physical-locations.rst b/gcc/doc/libgdiagnostics/topics/physical-locations.rst index be8e7eb..fcd81a0 100644 --- a/gcc/doc/libgdiagnostics/topics/physical-locations.rst +++ b/gcc/doc/libgdiagnostics/topics/physical-locations.rst @@ -304,3 +304,19 @@ This diagnostic has three locations .. code-block:: c #ifdef LIBDIAGNOSTICS_HAVE_diagnostic_message_buffer + +.. function:: void diagnostic_manager_set_debug_physical_locations (diagnostic_manager *mgr, \ + int value) + + Calling ``diagnostic_manager_set_debug_physical_locations (mgr, 1);`` + will lead to debugging information being printed to ``stderr`` when + creating :type:`diagnostic_physical_location` instances. + + The precise format of these messages is subject to change. + + This function was added in :ref:`LIBGDIAGNOSTICS_ABI_5`; you can + test for its presence using + + .. code-block:: c + + #ifdef LIBDIAGNOSTICS_HAVE_diagnostic_manager_set_debug_physical_locations diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 215552c..4d4e676 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1424,10 +1424,10 @@ the smaller of @var{computed} and @code{BIGGEST_ALIGNMENT} @defmac MAX_FIXED_MODE_SIZE An integer expression for the size in bits of the largest integer -machine mode that should actually be used. All integer machine modes of -this size or smaller can be used for structures and unions with the -appropriate sizes. If this macro is undefined, @code{GET_MODE_BITSIZE -(DImode)} is assumed. +machine mode that should actually be used by GCC internally. +All integer machine modes of this size or smaller can be used for +structures and unions with the appropriate sizes. If this macro is +undefined, @code{MAX (BITS_PER_WORD * 2, 64)} is assumed. @end defmac @defmac STACK_SAVEAREA_MODE (@var{save_level}) diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index b03ad4c..1a51ad5 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -1251,10 +1251,10 @@ the smaller of @var{computed} and @code{BIGGEST_ALIGNMENT} @defmac MAX_FIXED_MODE_SIZE An integer expression for the size in bits of the largest integer -machine mode that should actually be used. All integer machine modes of -this size or smaller can be used for structures and unions with the -appropriate sizes. If this macro is undefined, @code{GET_MODE_BITSIZE -(DImode)} is assumed. +machine mode that should actually be used by GCC internally. +All integer machine modes of this size or smaller can be used for +structures and unions with the appropriate sizes. If this macro is +undefined, @code{MAX (BITS_PER_WORD * 2, 64)} is assumed. @end defmac @defmac STACK_SAVEAREA_MODE (@var{save_level}) diff --git a/gcc/dump-context.h b/gcc/dump-context.h index 9c52f03..336cb23 100644 --- a/gcc/dump-context.h +++ b/gcc/dump-context.h @@ -267,7 +267,7 @@ extern void verify_dumped_text (const location &loc, void verify_item (const location &loc, const optinfo_item *item, - enum optinfo_item_kind expected_kind, + enum optinfo_item::kind expected_kind, location_t expected_location, const char *expected_text); @@ -275,7 +275,7 @@ verify_item (const location &loc, #define ASSERT_IS_TEXT(ITEM, EXPECTED_TEXT) \ SELFTEST_BEGIN_STMT \ - verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TEXT, \ + verify_item (SELFTEST_LOCATION, (ITEM), optinfo_item::kind::text, \ UNKNOWN_LOCATION, (EXPECTED_TEXT)); \ SELFTEST_END_STMT @@ -283,7 +283,7 @@ verify_item (const location &loc, #define ASSERT_IS_TREE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ SELFTEST_BEGIN_STMT \ - verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_TREE, \ + verify_item (SELFTEST_LOCATION, (ITEM), optinfo_item::kind::tree, \ (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ SELFTEST_END_STMT @@ -291,7 +291,7 @@ verify_item (const location &loc, #define ASSERT_IS_GIMPLE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ SELFTEST_BEGIN_STMT \ - verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_GIMPLE, \ + verify_item (SELFTEST_LOCATION, (ITEM), optinfo_item::kind::gimple, \ (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ SELFTEST_END_STMT @@ -299,7 +299,7 @@ verify_item (const location &loc, #define ASSERT_IS_SYMTAB_NODE(ITEM, EXPECTED_LOCATION, EXPECTED_TEXT) \ SELFTEST_BEGIN_STMT \ - verify_item (SELFTEST_LOCATION, (ITEM), OPTINFO_ITEM_KIND_SYMTAB_NODE, \ + verify_item (SELFTEST_LOCATION, (ITEM), optinfo_item::kind::symtab_node, \ (EXPECTED_LOCATION), (EXPECTED_TEXT)); \ SELFTEST_END_STMT diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc index ebee8e5..bca8b38 100644 --- a/gcc/dumpfile.cc +++ b/gcc/dumpfile.cc @@ -636,8 +636,8 @@ make_item_for_dump_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags) pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags); pp_newline (&pp); - std::unique_ptr<optinfo_item> item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE, + auto item + = std::make_unique<optinfo_item> (optinfo_item::kind::gimple, gimple_location (stmt), xstrdup (pp_formatted_text (&pp))); return item; @@ -684,8 +684,8 @@ make_item_for_dump_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags) pp_needs_newline (&pp) = true; pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags); - std::unique_ptr<optinfo_item> item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE, + auto item + = std::make_unique<optinfo_item> (optinfo_item::kind::gimple, gimple_location (stmt), xstrdup (pp_formatted_text (&pp))); return item; @@ -738,8 +738,8 @@ make_item_for_dump_generic_expr (tree node, dump_flags_t dump_flags) if (EXPR_HAS_LOCATION (node)) loc = EXPR_LOCATION (node); - std::unique_ptr<optinfo_item> item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TREE, loc, + auto item + = std::make_unique<optinfo_item> (optinfo_item::kind::tree, loc, xstrdup (pp_formatted_text (&pp))); return item; } @@ -783,8 +783,8 @@ static std::unique_ptr<optinfo_item> make_item_for_dump_symtab_node (symtab_node *node) { location_t loc = DECL_SOURCE_LOCATION (node->decl); - std::unique_ptr<optinfo_item> item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc, + auto item + = std::make_unique<optinfo_item> (optinfo_item::kind::symtab_node, loc, xstrdup (node->dump_name ())); return item; } @@ -1011,8 +1011,9 @@ emit_any_pending_textual_chunks () return; char *formatted_text = xstrdup (pp_formatted_text (pp)); - std::unique_ptr<optinfo_item> item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, + auto item + = std::make_unique<optinfo_item> (optinfo_item::kind::text, + UNKNOWN_LOCATION, formatted_text); pp->emit_item (std::move (item), m_optinfo); @@ -1084,7 +1085,8 @@ make_item_for_dump_dec (const poly_int<N, C> &value) } auto item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, + = std::make_unique<optinfo_item> (optinfo_item::kind::text, + UNKNOWN_LOCATION, xstrdup (pp_formatted_text (&pp))); return item; } @@ -1162,8 +1164,9 @@ dump_context::begin_scope (const char *name, pretty_printer pp; pp_printf (&pp, "%s %s %s", "===", name, "==="); pp_newline (&pp); - std::unique_ptr<optinfo_item> item - = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION, + auto item + = std::make_unique<optinfo_item> (optinfo_item::kind::text, + UNKNOWN_LOCATION, xstrdup (pp_formatted_text (&pp))); emit_item (*item.get (), MSG_NOTE); @@ -1172,7 +1175,7 @@ dump_context::begin_scope (const char *name, optinfo &info = begin_next_optinfo (dump_metadata_t (MSG_NOTE, impl_location), user_location); - info.m_kind = OPTINFO_KIND_SCOPE; + info.m_kind = optinfo::kind::scope; info.add_item (std::move (item)); end_any_optinfo (); } @@ -1221,7 +1224,7 @@ dump_context::begin_next_optinfo (const dump_metadata_t &metadata, end_any_optinfo (); gcc_assert (m_pending == NULL); dump_location_t loc (user_loc, metadata.get_impl_location ()); - m_pending = new optinfo (loc, OPTINFO_KIND_NOTE, current_pass); + m_pending = new optinfo (loc, optinfo::kind::note, current_pass); m_pending->handle_dump_file_kind (metadata.get_dump_flags ()); return *m_pending; } @@ -2265,7 +2268,7 @@ verify_dumped_text (const location &loc, void verify_item (const location &loc, const optinfo_item *item, - enum optinfo_item_kind expected_kind, + enum optinfo_item::kind expected_kind, location_t expected_location, const char *expected_text) { @@ -2324,7 +2327,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 1); ASSERT_IS_TEXT (info->get_item (0), "int: 42 str: foo"); ASSERT_IMPL_LOCATION_EQ (info->get_impl_location (), @@ -2345,7 +2348,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 2); ASSERT_IS_TEXT (info->get_item (0), "tree: "); ASSERT_IS_TREE (info->get_item (1), UNKNOWN_LOCATION, "0"); @@ -2367,7 +2370,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 2); ASSERT_IS_TEXT (info->get_item (0), "gimple: "); ASSERT_IS_GIMPLE (info->get_item (1), stmt_loc, "return;"); @@ -2389,7 +2392,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 2); ASSERT_IS_TEXT (info->get_item (0), "gimple: "); ASSERT_IS_GIMPLE (info->get_item (1), stmt_loc, "return;\n"); @@ -2411,7 +2414,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 2); ASSERT_IS_TEXT (info->get_item (0), "node: "); ASSERT_IS_SYMTAB_NODE (info->get_item (1), decl_loc, "test_decl/1"); @@ -2441,7 +2444,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 8); ASSERT_IS_TEXT (info->get_item (0), "before "); ASSERT_IS_TREE (info->get_item (1), UNKNOWN_LOCATION, "0"); @@ -2471,7 +2474,7 @@ test_capture_of_dump_calls (const line_table_case &case_) optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); ASSERT_EQ (info->get_location_t (), stmt_loc); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 2); ASSERT_IS_TEXT (info->get_item (0), "test of tree: "); ASSERT_IS_TREE (info->get_item (1), UNKNOWN_LOCATION, "0"); @@ -2494,7 +2497,7 @@ test_capture_of_dump_calls (const line_table_case &case_) optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); ASSERT_EQ (info->get_location_t (), stmt_loc); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 1); ASSERT_IS_TREE (info->get_item (0), UNKNOWN_LOCATION, "1"); ASSERT_IMPL_LOCATION_EQ (info->get_impl_location (), @@ -2598,7 +2601,7 @@ test_capture_of_dump_calls (const line_table_case &case_) { optinfo *info = tmp.get_pending_optinfo (); ASSERT_TRUE (info != NULL); - ASSERT_EQ (info->get_kind (), OPTINFO_KIND_NOTE); + ASSERT_EQ (info->get_kind (), optinfo::kind::note); ASSERT_EQ (info->num_items (), 1); ASSERT_IS_SYMTAB_NODE (info->get_item (0), decl_loc, "test_decl/1"); ASSERT_IMPL_LOCATION_EQ (info->get_impl_location (), @@ -2727,7 +2730,7 @@ test_capture_of_dump_calls (const line_table_case &case_) temp_dump_context tmp (true, true, MSG_ALL_KINDS); dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, "test"); ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (), - OPTINFO_KIND_SUCCESS); + optinfo::kind::success); } /* MSG_MISSED_OPTIMIZATION. */ @@ -2735,7 +2738,7 @@ test_capture_of_dump_calls (const line_table_case &case_) temp_dump_context tmp (true, true, MSG_ALL_KINDS); dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc, "test"); ASSERT_EQ (tmp.get_pending_optinfo ()->get_kind (), - OPTINFO_KIND_FAILURE); + optinfo::kind::failure); } } diff --git a/gcc/explow.cc b/gcc/explow.cc index 7799a98..8f8ca7f 100644 --- a/gcc/explow.cc +++ b/gcc/explow.cc @@ -854,6 +854,18 @@ promote_function_mode (const_tree type, machine_mode mode, int *punsignedp, switch (TREE_CODE (type)) { + case BITINT_TYPE: + if (TYPE_MODE (type) == BLKmode) + return mode; + + struct bitint_info info; + bool ok; + ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info); + gcc_assert (ok); + + if (!info.extended) + return mode; + /* FALLTHRU */ case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case REAL_TYPE: case OFFSET_TYPE: case FIXED_POINT_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: @@ -893,6 +905,18 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, machine_mode mode, switch (code) { + case BITINT_TYPE: + if (TYPE_MODE (type) == BLKmode) + return mode; + + struct bitint_info info; + bool ok; + ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info); + gcc_assert (ok); + + if (!info.extended) + return mode; + /* FALLTHRU */ case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case REAL_TYPE: case OFFSET_TYPE: case FIXED_POINT_TYPE: /* Values of these types always have scalar mode. */ diff --git a/gcc/expr.cc b/gcc/expr.cc index 3f2b121..3d2b253 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -76,6 +76,10 @@ along with GCC; see the file COPYING3. If not see the same indirect address eventually. */ int cse_not_expected; +/* Cache of the "extended" flag in the target's _BitInt description + for use during expand. */ +int bitint_extended = -1; + static bool block_move_libcall_safe_for_call_parm (void); static bool emit_block_move_via_pattern (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT, unsigned HOST_WIDE_INT, @@ -11280,6 +11284,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, when reading from SSA_NAMEs of vars. */ #define EXTEND_BITINT(expr) \ ((TREE_CODE (type) == BITINT_TYPE \ + && !bitint_extended \ && reduce_bit_field \ && mode != BLKmode \ && modifier != EXPAND_MEMORY \ @@ -11291,6 +11296,13 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, type = TREE_TYPE (exp); mode = TYPE_MODE (type); unsignedp = TYPE_UNSIGNED (type); + if (TREE_CODE (type) == BITINT_TYPE && bitint_extended == -1) + { + struct bitint_info info; + bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info); + gcc_assert (ok); + bitint_extended = info.extended; + } treeop0 = treeop1 = treeop2 = NULL_TREE; if (!VL_EXP_CLASS_P (exp)) @@ -388,4 +388,8 @@ extern void expand_crc_table_based (rtx, rtx, rtx, rtx, machine_mode); extern void expand_reversed_crc_table_based (rtx, rtx, rtx, rtx, machine_mode, void (*) (rtx *)); +/* Cache of the "extended" flag in the target's _BitInt description + for use during expand. */ +extern int bitint_extended; + #endif /* GCC_EXPR_H */ diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d75d64f..20e4a76 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,68 @@ +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * trans-stmt.cc (trans_associate_var): Remove overwrite of + the polymorphic associate variable's array descriptor offset. + +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * trans-array.cc (trans_array_constructor): Remove the update of + the array descriptor upper bound after array constructor + expansion. + +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * trans-array.cc (gfc_conv_expr_descriptor): Remove + isolated initialization of the span field before passing to + the function that will do the initialization. + +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * trans-decl.cc (gfc_trans_deferred_vars): Don't default + initialize the span of local pointer arrays. + +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * trans-stmt.cc (trans_associate_var): Remove overwrite of the + span field of the associate variable's array descriptor. + +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * trans-expr.cc (gfc_trans_pointer_assignment): Remove overwrite + of the span after assignment of the array descriptor in the + polymorphic function result to non-polymorphic pointer case. + +2025-08-05 Mikael Morin <mikael@gcc.gnu.org> + + * trans.h (gfc_se): Remove field use_offset. + * trans-expr.cc (gfc_conv_intrinsic_to_class): Remove use_offset + initialization. + (gfc_conv_procedure_call): Likewise. + * trans-stmt.cc (trans_associate_var): Likewise. + +2025-08-05 Mikael Morin <mikael@gcc.gnu.org> + + * trans-array.cc (gfc_alloc_allocatable_for_assignment): Use the + offset setter instead of generating a write to the offset. + (gfc_conv_array_parameter): Use the offset setter instead of + generating a write to the value returned by the offset getter. + * trans-expr.cc (gfc_trans_alloc_subarray_assign): Likewise. + +2025-08-05 Mikael Morin <mikael@gcc.gnu.org> + + * trans-array.cc (gfc_conv_descriptor_data_addr): Remove. + * trans-array.h (gfc_conv_descriptor_data_addr): Remove. + * trans-decl.cc (gfc_trans_deferred_vars): Use + gfc_conv_descriptor_data_get. + +2025-08-05 Mikael Morin <mikael@gcc.gnu.org> + + * trans.cc (gfc_finalize_tree_expr): Use the data setter instead + of writing to the value returned by the data getter. + * trans-decl.cc (gfc_trans_deferred_vars): Likewise. + * trans-stmt.cc (trans_associate_var): Use the data setter + instead of writing to the value dereferenced from the data + address. + 2025-08-01 Mikael Morin <mikael@gcc.gnu.org> * trans-decl.cc (gfc_trans_deferred_vars): Fix closing brace in diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 990aaaf..7e6437b 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -284,16 +284,6 @@ gfc_conv_descriptor_data_set (stmtblock_t *block, tree desc, tree value) } -/* This provides address access to the data field. This should only be - used by array allocation, passing this on to the runtime. */ - -tree -gfc_conv_descriptor_data_addr (tree desc) -{ - tree field = gfc_get_descriptor_field (desc, DATA_FIELD); - return gfc_build_addr_expr (NULL_TREE, field); -} - static tree gfc_conv_descriptor_offset (tree desc) { @@ -3115,7 +3105,6 @@ trans_array_constructor (gfc_ss * ss, locus * where) gfc_array_index_type, offsetvar, gfc_index_one_node); tmp = gfc_evaluate_now (tmp, &outer_loop->pre); - gfc_conv_descriptor_ubound_set (&loop->pre, desc, gfc_rank_cst[0], tmp); if (*loop_ubound0 && VAR_P (*loop_ubound0)) gfc_add_modify (&outer_loop->pre, *loop_ubound0, tmp); else @@ -8509,14 +8498,6 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) else gcc_assert (se->ss == ss); - if (!is_pointer_array (se->expr)) - { - tmp = gfc_get_element_type (TREE_TYPE (se->expr)); - tmp = fold_convert (gfc_array_index_type, - size_in_bytes (tmp)); - gfc_conv_descriptor_span_set (&se->pre, se->expr, tmp); - } - se->expr = gfc_build_addr_expr (NULL_TREE, se->expr); gfc_conv_expr (se, expr); @@ -9588,9 +9569,8 @@ gfc_conv_array_parameter (gfc_se *se, gfc_expr *expr, bool g77, new_field = gfc_conv_descriptor_dtype (new_desc); gfc_add_modify (&se->pre, new_field, old_field); - old_field = gfc_conv_descriptor_offset (old_desc); - new_field = gfc_conv_descriptor_offset (new_desc); - gfc_add_modify (&se->pre, new_field, old_field); + old_field = gfc_conv_descriptor_offset_get (old_desc); + gfc_conv_descriptor_offset_set (&se->pre, new_desc, old_field); for (int i = 0; i < expr->rank; i++) { @@ -11760,8 +11740,8 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, gfc_index_zero_node); } - tmp = gfc_conv_descriptor_offset (desc); - gfc_add_modify (&loop_pre_block, tmp, gfc_index_zero_node); + gfc_conv_descriptor_offset_set (&loop_pre_block, desc, + gfc_index_zero_node); tmp = fold_build2_loc (input_location, EQ_EXPR, logical_type_node, array1, diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h index 29098fd..345a975 100644 --- a/gcc/fortran/trans-array.h +++ b/gcc/fortran/trans-array.h @@ -173,7 +173,6 @@ void gfc_get_descriptor_offsets_for_info (const_tree, tree *, tree *, tree *, tr tree *, tree *, tree *, tree *); tree gfc_conv_descriptor_data_get (tree); -tree gfc_conv_descriptor_data_addr (tree); tree gfc_conv_descriptor_offset_get (tree); tree gfc_conv_descriptor_span_get (tree); tree gfc_conv_descriptor_dtype (tree); diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 3b49b18..8992dbc 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -4936,20 +4936,6 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) } } - if (sym->attr.pointer && sym->attr.dimension - && sym->attr.save == SAVE_NONE - && !sym->attr.use_assoc - && !sym->attr.host_assoc - && !sym->attr.dummy - && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (sym->backend_decl))) - { - gfc_init_block (&tmpblock); - gfc_conv_descriptor_span_set (&tmpblock, sym->backend_decl, - build_int_cst (gfc_array_index_type, 0)); - gfc_add_init_cleanup (block, gfc_finish_block (&tmpblock), - NULL_TREE); - } - if (sym->ts.type == BT_CLASS && (sym->attr.save || flag_max_stack_var_size == 0) && CLASS_DATA (sym)->attr.allocatable) @@ -5148,18 +5134,31 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) se.descriptor_only = 1; gfc_conv_expr (&se, e); descriptor = se.expr; - se.expr = gfc_conv_descriptor_data_addr (se.expr); - se.expr = build_fold_indirect_ref_loc (input_location, se.expr); + se.expr = gfc_conv_descriptor_data_get (se.expr); } gfc_free_expr (e); if (!sym->attr.dummy || sym->attr.intent == INTENT_OUT) { /* Nullify when entering the scope. */ - tmp = fold_build2_loc (input_location, MODIFY_EXPR, - TREE_TYPE (se.expr), se.expr, - fold_convert (TREE_TYPE (se.expr), - null_pointer_node)); + if (sym->ts.type == BT_CLASS + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension)) + { + stmtblock_t nullify; + gfc_init_block (&nullify); + gfc_conv_descriptor_data_set (&nullify, descriptor, + null_pointer_node); + tmp = gfc_finish_block (&nullify); + } + else + { + tree typed_null = fold_convert (TREE_TYPE (se.expr), + null_pointer_node); + tmp = fold_build2_loc (input_location, MODIFY_EXPR, + TREE_TYPE (se.expr), se.expr, + typed_null); + } if (sym->attr.optional) { tree present = gfc_conv_expr_present (sym); diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index ec24084..69952b3 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -1168,7 +1168,6 @@ gfc_conv_intrinsic_to_class (gfc_se *parmse, gfc_expr *e, else { parmse->ss = ss; - parmse->use_offset = 1; gfc_conv_expr_descriptor (parmse, e); /* Array references with vector subscripts and non-variable expressions @@ -7542,7 +7541,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, || CLASS_DATA (fsym)->attr.codimension)) { /* Pass a class array. */ - parmse.use_offset = 1; gfc_conv_expr_descriptor (&parmse, e); bool defer_to_dealloc_blk = false; @@ -9583,8 +9581,8 @@ gfc_trans_alloc_subarray_assign (tree dest, gfc_component * cm, /* Shift the lbound and ubound of temporaries to being unity, rather than zero, based. Always calculate the offset. */ + gfc_conv_descriptor_offset_set (&block, dest, gfc_index_zero_node); offset = gfc_conv_descriptor_offset_get (dest); - gfc_add_modify (&block, offset, gfc_index_zero_node); tmp2 =gfc_create_var (gfc_array_index_type, NULL); for (n = 0; n < expr->rank; n++) @@ -11148,11 +11146,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) { rse.expr = gfc_class_data_get (rse.expr); gfc_add_modify (&lse.pre, desc, rse.expr); - /* Set the lhs span. */ - tmp = TREE_TYPE (rse.expr); - tmp = TYPE_SIZE_UNIT (gfc_get_element_type (tmp)); - tmp = fold_convert (gfc_array_index_type, tmp); - gfc_conv_descriptor_span_set (&lse.pre, desc, tmp); } else { diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc index b4ddf75..f4e6c57 100644 --- a/gcc/fortran/trans-stmt.cc +++ b/gcc/fortran/trans-stmt.cc @@ -1876,9 +1876,6 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) bool class_target; bool unlimited; tree desc; - tree offset; - tree dim; - int n; tree charlen; bool need_len_assign; bool whole_array = true; @@ -2116,7 +2113,6 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) if (sym->assoc->variable || cst_array_ctor) { se.direct_byref = 1; - se.use_offset = 1; se.expr = desc; GFC_DECL_PTR_ARRAY_P (sym->backend_decl) = 1; } @@ -2183,16 +2179,6 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) dim, gfc_index_one_node); } - /* If this is a subreference array pointer associate name use the - associate variable element size for the value of 'span'. */ - if (sym->attr.subref_array_pointer && !se.direct_byref) - { - gcc_assert (e->expr_type == EXPR_VARIABLE); - tmp = gfc_get_array_span (se.expr, e); - - gfc_conv_descriptor_span_set (&se.pre, desc, tmp); - } - if (e->expr_type == EXPR_FUNCTION && sym->ts.type == BT_DERIVED && sym->ts.u.derived @@ -2303,21 +2289,6 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) desc = gfc_class_data_get (se.expr); - /* Set the offset. */ - offset = gfc_index_zero_node; - for (n = 0; n < e->rank; n++) - { - dim = gfc_rank_cst[n]; - tmp = fold_build2_loc (input_location, MULT_EXPR, - gfc_array_index_type, - gfc_conv_descriptor_stride_get (desc, dim), - gfc_conv_descriptor_lbound_get (desc, dim)); - offset = fold_build2_loc (input_location, MINUS_EXPR, - gfc_array_index_type, - offset, tmp); - } - gfc_conv_descriptor_offset_set (&se.pre, desc, offset); - if (need_len_assign) { if (e->symtree @@ -2494,9 +2465,10 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) { tmp = sym->backend_decl; if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp))) - tmp = gfc_conv_descriptor_data_get (tmp); - gfc_add_modify (&se.pre, tmp, fold_convert (TREE_TYPE (tmp), - null_pointer_node)); + gfc_conv_descriptor_data_set (&se.pre, tmp, null_pointer_node); + else + gfc_add_modify (&se.pre, tmp, + fold_convert (TREE_TYPE (tmp), null_pointer_node)); } lhs = gfc_lval_expr_from_sym (sym); diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc index 13fd5ad..47396c3 100644 --- a/gcc/fortran/trans.cc +++ b/gcc/fortran/trans.cc @@ -1740,7 +1740,7 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, gfc_call_free (data_ptr), build_empty_stmt (input_location)); gfc_add_expr_to_block (&se->loop->post, tmp); - gfc_add_modify (&se->loop->post, data_ptr, data_null); + gfc_conv_descriptor_data_set (&se->loop->post, desc, data_null); } else { @@ -1754,7 +1754,7 @@ gfc_finalize_tree_expr (gfc_se *se, gfc_symbol *derived, gfc_call_free (data_ptr), build_empty_stmt (input_location)); gfc_add_expr_to_block (&se->finalblock, tmp); - gfc_add_modify (&se->finalblock, data_ptr, data_null); + gfc_conv_descriptor_data_set (&se->finalblock, desc, data_null); } } } diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 40680e9..5554184 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -105,10 +105,6 @@ typedef struct gfc_se /* If set, will pass subref descriptors without a temporary. */ unsigned force_no_tmp:1; - /* Unconditionally calculate offset for array segments and constant - arrays in gfc_conv_expr_descriptor. */ - unsigned use_offset:1; - unsigned want_coarray:1; /* Scalarization parameters. */ diff --git a/gcc/function.cc b/gcc/function.cc index 2b77bbd..5a054a9 100644 --- a/gcc/function.cc +++ b/gcc/function.cc @@ -4965,6 +4965,10 @@ prepare_function_start (void) /* Indicate we have no need of a frame pointer yet. */ frame_pointer_needed = 0; + + /* Reset the cache of the "extended" flag in the target's + _BitInt info struct. */ + bitint_extended = -1; } void diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc index 4e20b4c..6929cd0 100644 --- a/gcc/gimple-pretty-print.cc +++ b/gcc/gimple-pretty-print.cc @@ -1837,6 +1837,12 @@ dump_gimple_omp_target (pretty_printer *pp, const gomp_target *gs, default: gcc_unreachable (); } + if (gimple_omp_target_iterator_loops (gs)) + { + pp_string (pp, "// Expanded iterator loops for #pragma omp target\n"); + dump_gimple_seq (pp, gimple_omp_target_iterator_loops (gs), spc, flags); + pp_newline (pp); + } if (flags & TDF_RAW) { dump_gimple_fmt (pp, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs, diff --git a/gcc/gimple-warn-recursion.cc b/gcc/gimple-warn-recursion.cc index e6a0c4c..d061e7e 100644 --- a/gcc/gimple-warn-recursion.cc +++ b/gcc/gimple-warn-recursion.cc @@ -190,6 +190,7 @@ pass_warn_recursion::execute (function *func) if (find_function_exit (entry_bb) || m_calls->length () == 0) return 0; + auto_diagnostic_group d; if (warning_at (DECL_SOURCE_LOCATION (func->decl), OPT_Winfinite_recursion, "infinite recursion detected")) diff --git a/gcc/gimple.cc b/gcc/gimple.cc index 41908d4..102e21f 100644 --- a/gcc/gimple.cc +++ b/gcc/gimple.cc @@ -1295,10 +1295,13 @@ gimple_build_omp_interop (tree clauses) BODY is the sequence of statements that will be executed. KIND is the kind of the region. - CLAUSES are any of the construct's clauses. */ + CLAUSES are any of the construct's clauses. + ITERATOR_LOOPS is an optional sequence containing constructed loops + for OpenMP iterators. */ gomp_target * -gimple_build_omp_target (gimple_seq body, int kind, tree clauses) +gimple_build_omp_target (gimple_seq body, int kind, tree clauses, + gimple_seq iterator_loops) { gomp_target *p = as_a <gomp_target *> (gimple_alloc (GIMPLE_OMP_TARGET, 0)); @@ -1306,6 +1309,7 @@ gimple_build_omp_target (gimple_seq body, int kind, tree clauses) gimple_omp_set_body (p, body); gimple_omp_target_set_clauses (p, clauses); gimple_omp_target_set_kind (p, kind); + gimple_omp_target_set_iterator_loops (p, iterator_loops); return p; } diff --git a/gcc/gimple.def b/gcc/gimple.def index 54248a8..3e1e13e 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -393,7 +393,7 @@ DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE_LAYOUT) DATA_ARG is a vec of 3 local variables in the parent function containing data to be mapped to CHILD_FN. This is used to implement the MAP clauses. */ -DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_PARALLEL_LAYOUT) +DEFGSCODE(GIMPLE_OMP_TARGET, "gimple_omp_target", GSS_OMP_TARGET) /* GIMPLE_OMP_TEAMS <BODY, CLAUSES, CHILD_FN, DATA_ARG> represents #pragma omp teams diff --git a/gcc/gimple.h b/gcc/gimple.h index 5c970ce..da32651 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -682,11 +682,14 @@ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) }; /* GIMPLE_OMP_TARGET */ -struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) +struct GTY((tag("GSS_OMP_TARGET"))) gomp_target : public gimple_statement_omp_parallel_layout { - /* No extra fields; adds invariant: - stmt->code == GIMPLE_OMP_TARGET. */ + /* [ WORD 1-10 ] : base class */ + + /* [ WORD 11 ] + Iterator loops. */ + gimple_seq iterator_loops; }; /* GIMPLE_OMP_TASK */ @@ -1607,7 +1610,7 @@ gomp_scan *gimple_build_omp_scan (gimple_seq, tree); gomp_sections *gimple_build_omp_sections (gimple_seq, tree); gimple *gimple_build_omp_sections_switch (void); gomp_single *gimple_build_omp_single (gimple_seq, tree); -gomp_target *gimple_build_omp_target (gimple_seq, int, tree); +gomp_target *gimple_build_omp_target (gimple_seq, int, tree, gimple_seq = NULL); gomp_teams *gimple_build_omp_teams (gimple_seq, tree); gomp_atomic_load *gimple_build_omp_atomic_load (tree, tree, enum omp_memory_order); @@ -6380,6 +6383,38 @@ gimple_omp_target_set_data_arg (gomp_target *omp_target_stmt, } +/* Return the Gimple sequence used to store loops for OpenMP iterators used + by OMP_TARGET_STMT. */ + +inline gimple_seq +gimple_omp_target_iterator_loops (const gomp_target *omp_target_stmt) +{ + return omp_target_stmt->iterator_loops; +} + + +/* Return a pointer to the Gimple sequence used to store loops for OpenMP + iterators used by OMP_TARGET GS. */ + +inline gimple_seq * +gimple_omp_target_iterator_loops_ptr (gimple *gs) +{ + gomp_target *omp_target_stmt = as_a <gomp_target *> (gs); + return &omp_target_stmt->iterator_loops; +} + + +/* Set ITERATOR_LOOPS to be the Gimple sequence used to store loops + constructed for OpenMP iterators in OMP_TARGET_STMT. */ + +inline void +gimple_omp_target_set_iterator_loops (gomp_target *omp_target_stmt, + gimple_seq iterator_loops) +{ + omp_target_stmt->iterator_loops = iterator_loops; +} + + /* Return the clauses associated with OMP_TEAMS GS. */ inline tree diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index fbf47dd..ca1fa21 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -9891,6 +9891,373 @@ build_omp_iterator_loop (tree it, gimple_seq *pre_p, tree *last_bind) return p; } + +/* Callback for walk_tree to find a VAR_DECL (stored in DATA) in the + tree TP. */ + +static tree +find_var_decl (tree *tp, int *, void *data) +{ + if (*tp == (tree) data) + return *tp; + + return NULL_TREE; +} + +/* Returns an element-by-element copy of OMP iterator tree IT. */ + +static tree +copy_omp_iterator (tree it, int elem_count = -1) +{ + if (elem_count < 0) + elem_count = TREE_VEC_LENGTH (it); + tree new_it = make_tree_vec (elem_count); + for (int i = 0; i < TREE_VEC_LENGTH (it); i++) + TREE_VEC_ELT (new_it, i) = TREE_VEC_ELT (it, i); + + return new_it; +} + +/* Helper function for walk_tree in remap_omp_iterator_var. */ + +static tree +remap_omp_iterator_var_1 (tree *tp, int *, void *data) +{ + tree old_var = ((tree *) data)[0]; + tree new_var = ((tree *) data)[1]; + + if (*tp == old_var) + *tp = new_var; + return NULL_TREE; +} + +/* Replace instances of OLD_VAR in TP with NEW_VAR. */ + +static void +remap_omp_iterator_var (tree *tp, tree old_var, tree new_var) +{ + tree vars[2] = { old_var, new_var }; + walk_tree (tp, remap_omp_iterator_var_1, vars, NULL); +} + +/* Scan through all clauses using OpenMP iterators in LIST_P. If any + clauses have iterators with variables that are not used by the clause + decl or size, issue a warning and replace the iterator with a copy with + the unused variables removed. */ + +static void +remove_unused_omp_iterator_vars (tree *list_p) +{ + auto_vec< vec<tree> > iter_vars; + auto_vec<tree> new_iterators; + + for (tree c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (!OMP_CLAUSE_HAS_ITERATORS (c)) + continue; + auto_vec<tree> vars; + bool need_new_iterators = false; + for (tree it = OMP_CLAUSE_ITERATORS (c); it; it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + tree t = walk_tree (&OMP_CLAUSE_DECL (c), find_var_decl, var, NULL); + if (t == NULL_TREE) + t = walk_tree (&OMP_CLAUSE_SIZE (c), find_var_decl, var, NULL); + if (t == NULL_TREE) + { + need_new_iterators = true; + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_TO + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FROM)) + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM) + warning_at (OMP_CLAUSE_LOCATION (c), OPT_Wopenmp, + "iterator variable %qE not used in clause " + "expression", DECL_NAME (var)); + } + else + vars.safe_push (var); + } + if (!need_new_iterators) + continue; + if (need_new_iterators && vars.is_empty ()) + { + /* No iteration variables are used in the clause - remove the + iterator from the clause. */ + OMP_CLAUSE_ITERATORS (c) = NULL_TREE; + continue; + } + + /* If a new iterator has been created for the current set of used + iterator variables, then use that as the iterator. Otherwise, + create a new iterator for the current iterator variable set. */ + unsigned i; + for (i = 0; i < iter_vars.length (); i++) + { + if (vars.length () != iter_vars[i].length ()) + continue; + bool identical_p = true; + for (unsigned j = 0; j < vars.length () && identical_p; j++) + identical_p = vars[j] == iter_vars[i][j]; + + if (identical_p) + break; + } + if (i < iter_vars.length ()) + OMP_CLAUSE_ITERATORS (c) = new_iterators[i]; + else + { + tree new_iters = NULL_TREE; + tree *new_iters_p = &new_iters; + tree new_vars = NULL_TREE; + tree *new_vars_p = &new_vars; + i = 0; + for (tree it = OMP_CLAUSE_ITERATORS (c); it && i < vars.length(); + it = TREE_CHAIN (it)) + { + tree var = TREE_VEC_ELT (it, 0); + if (var == vars[i]) + { + *new_iters_p = copy_omp_iterator (it); + *new_vars_p = build_decl (OMP_CLAUSE_LOCATION (c), VAR_DECL, + DECL_NAME (var), TREE_TYPE (var)); + DECL_ARTIFICIAL (*new_vars_p) = 1; + DECL_CONTEXT (*new_vars_p) = DECL_CONTEXT (var); + TREE_VEC_ELT (*new_iters_p, 0) = *new_vars_p; + new_iters_p = &TREE_CHAIN (*new_iters_p); + new_vars_p = &DECL_CHAIN (*new_vars_p); + i++; + } + } + tree new_block = make_node (BLOCK); + BLOCK_VARS (new_block) = new_vars; + TREE_VEC_ELT (new_iters, 5) = new_block; + new_iterators.safe_push (new_iters); + iter_vars.safe_push (vars.copy ()); + OMP_CLAUSE_ITERATORS (c) = new_iters; + } + + /* Remap clause to use the new variables. */ + i = 0; + for (tree it = OMP_CLAUSE_ITERATORS (c); it; it = TREE_CHAIN (it)) + { + tree old_var = vars[i++]; + tree new_var = TREE_VEC_ELT (it, 0); + remap_omp_iterator_var (&OMP_CLAUSE_DECL (c), old_var, new_var); + remap_omp_iterator_var (&OMP_CLAUSE_SIZE (c), old_var, new_var); + } + } + + for (unsigned i = 0; i < iter_vars.length (); i++) + iter_vars[i].release (); +} + +struct iterator_loop_info_t +{ + tree bind; + tree count; + tree index; + tree body_label; + auto_vec<tree> clauses; +}; + +typedef hash_map<tree, iterator_loop_info_t> iterator_loop_info_map_t; + +/* Builds a loop to expand any OpenMP iterators in the clauses in LIST_P, + reusing any previously built loops if they use the same set of iterators. + Generated Gimple statements are placed into LOOPS_SEQ_P. The clause + iterators are updated with information on how and where to insert code into + the loop body. */ + +static void +build_omp_iterators_loops (tree *list_p, gimple_seq *loops_seq_p) +{ + iterator_loop_info_map_t loops; + + for (tree c = *list_p; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (!OMP_CLAUSE_HAS_ITERATORS (c)) + continue; + + bool built_p; + iterator_loop_info_t &loop + = loops.get_or_insert (OMP_CLAUSE_ITERATORS (c), &built_p); + + if (!built_p) + { + loop.count = compute_omp_iterator_count (OMP_CLAUSE_ITERATORS (c), + loops_seq_p); + if (!loop.count) + continue; + if (integer_zerop (loop.count)) + warning_at (OMP_CLAUSE_LOCATION (c), OPT_Wopenmp, + "iteration count is zero"); + + loop.bind = NULL_TREE; + tree *body = build_omp_iterator_loop (OMP_CLAUSE_ITERATORS (c), + loops_seq_p, &loop.bind); + + loop.index = create_tmp_var (sizetype); + SET_EXPR_LOCATION (loop.bind, OMP_CLAUSE_LOCATION (c)); + + /* BEFORE LOOP: */ + /* idx = -1; */ + /* This should be initialized to before the individual elements, + as idx is pre-incremented in the loop body. */ + gimple *assign = gimple_build_assign (loop.index, size_int (-1)); + gimple_seq_add_stmt (loops_seq_p, assign); + + /* IN LOOP BODY: */ + /* Create a label so we can find this point later. */ + loop.body_label = create_artificial_label (OMP_CLAUSE_LOCATION (c)); + tree tem = build1 (LABEL_EXPR, void_type_node, loop.body_label); + append_to_statement_list_force (tem, body); + + /* idx += 2; */ + tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, + void_type_node, loop.index, + size_binop (PLUS_EXPR, loop.index, size_int (2))); + append_to_statement_list_force (tem, body); + } + + /* Create array to hold expanded values. */ + tree last_count_2 = size_binop (MULT_EXPR, loop.count, size_int (2)); + tree arr_length = size_binop (PLUS_EXPR, last_count_2, size_int (1)); + tree elems = NULL_TREE; + if (TREE_CONSTANT (arr_length)) + { + tree type = build_array_type (ptr_type_node, + build_index_type (arr_length)); + elems = create_tmp_var_raw (type, "omp_iter_data"); + TREE_ADDRESSABLE (elems) = 1; + gimple_add_tmp_var (elems); + } + else + { + /* Handle dynamic sizes. */ + sorry ("dynamic iterator sizes not implemented yet"); + } + + /* BEFORE LOOP: */ + /* elems[0] = count; */ + tree lhs = build4 (ARRAY_REF, ptr_type_node, elems, size_int (0), + NULL_TREE, NULL_TREE); + tree tem = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, + void_type_node, lhs, loop.count); + gimplify_and_add (tem, loops_seq_p); + + /* Make a copy of the iterator with extra info at the end. */ + int elem_count = TREE_VEC_LENGTH (OMP_CLAUSE_ITERATORS (c)); + tree new_iterator = copy_omp_iterator (OMP_CLAUSE_ITERATORS (c), + elem_count + 3); + TREE_VEC_ELT (new_iterator, elem_count) = loop.body_label; + TREE_VEC_ELT (new_iterator, elem_count + 1) = elems; + TREE_VEC_ELT (new_iterator, elem_count + 2) = loop.index; + TREE_CHAIN (new_iterator) = TREE_CHAIN (OMP_CLAUSE_ITERATORS (c)); + OMP_CLAUSE_ITERATORS (c) = new_iterator; + + loop.clauses.safe_push (c); + } + + /* Now gimplify and add all the loops that were built. */ + for (hash_map<tree, iterator_loop_info_t>::iterator it = loops.begin (); + it != loops.end (); ++it) + gimplify_and_add ((*it).second.bind, loops_seq_p); +} + +/* Helper function for enter_omp_iterator_loop_context. */ + +static gimple_seq * +enter_omp_iterator_loop_context_1 (tree iterator, gimple_seq *loops_seq_p) +{ + /* Drill into the nested bind expressions to get to the loop body. */ + for (gimple_stmt_iterator gsi = gsi_start (*loops_seq_p); + !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + switch (gimple_code (stmt)) + { + case GIMPLE_BIND: + { + gbind *bind_stmt = as_a<gbind *> (stmt); + gimple_push_bind_expr (bind_stmt); + gimple_seq *bind_body_p = gimple_bind_body_ptr (bind_stmt); + gimple_seq *seq = + enter_omp_iterator_loop_context_1 (iterator, bind_body_p); + if (seq) + return seq; + gimple_pop_bind_expr (); + } + break; + case GIMPLE_TRY: + { + gimple_seq *try_eval_p = gimple_try_eval_ptr (stmt); + gimple_seq *seq = + enter_omp_iterator_loop_context_1 (iterator, try_eval_p); + if (seq) + return seq; + } + break; + case GIMPLE_LABEL: + { + glabel *label_stmt = as_a<glabel *> (stmt); + tree label = gimple_label_label (label_stmt); + if (label == TREE_VEC_ELT (iterator, 6)) + return loops_seq_p; + } + break; + default: + break; + } + } + + return NULL; +} + +/* Enter the Gimplification context in LOOPS_SEQ_P for the iterator loop + associated with OpenMP clause C. Returns the gimple_seq for the loop body + if C has OpenMP iterators, or ALT_SEQ_P if not. */ + +static gimple_seq * +enter_omp_iterator_loop_context (tree c, gimple_seq *loops_seq_p, + gimple_seq *alt_seq_p) +{ + if (!OMP_CLAUSE_HAS_ITERATORS (c)) + return alt_seq_p; + + push_gimplify_context (); + + gimple_seq *seq = enter_omp_iterator_loop_context_1 (OMP_CLAUSE_ITERATORS (c), + loops_seq_p); + gcc_assert (seq); + return seq; +} + +/* Enter the Gimplification context in STMT for the iterator loop associated + with OpenMP clause C. Returns the gimple_seq for the loop body if C has + OpenMP iterators, or ALT_SEQ_P if not. */ + +gimple_seq * +enter_omp_iterator_loop_context (tree c, gomp_target *stmt, + gimple_seq *alt_seq_p) +{ + gimple_seq *loops_seq_p = gimple_omp_target_iterator_loops_ptr (stmt); + return enter_omp_iterator_loop_context (c, loops_seq_p, alt_seq_p); +} + +/* Exit the Gimplification context for the OpenMP clause C. */ + +void +exit_omp_iterator_loop_context (tree c) +{ + if (!OMP_CLAUSE_HAS_ITERATORS (c)) + return; + while (!gimplify_ctxp->bind_expr_stack.is_empty ()) + gimple_pop_bind_expr (); + pop_gimplify_context (NULL); +} + /* If *LIST_P contains any OpenMP depend clauses with iterators, lower all the depend clauses by populating corresponding depend array. Returns 0 if there are no such depend clauses, or @@ -13217,7 +13584,8 @@ omp_instantiate_implicit_mappers (splay_tree_node n, void *data) static void gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, enum omp_region_type region_type, - enum tree_code code) + enum tree_code code, + gimple_seq *loops_seq_p = NULL) { using namespace omp_addr_tokenizer; struct gimplify_omp_ctx *ctx, *outer_ctx; @@ -13988,23 +14356,24 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, if (OMP_CLAUSE_SIZE (c) == NULL_TREE) OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl) : TYPE_SIZE_UNIT (TREE_TYPE (decl)); - if (gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, - NULL, is_gimple_val, fb_rvalue) == GS_ERROR) + gimple_seq *seq_p; + seq_p = enter_omp_iterator_loop_context (c, loops_seq_p, pre_p); + if (gimplify_expr (&OMP_CLAUSE_SIZE (c), seq_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) { remove = true; + exit_omp_iterator_loop_context (c); break; } if (!DECL_P (decl)) { - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, - NULL, is_gimple_lvalue, fb_lvalue) - == GS_ERROR) - { - remove = true; - break; - } + if (gimplify_expr (&OMP_CLAUSE_DECL (c), seq_p, NULL, + is_gimple_lvalue, fb_lvalue) == GS_ERROR) + remove = true; + exit_omp_iterator_loop_context (c); break; } + exit_omp_iterator_loop_context (c); goto do_notice; case OMP_CLAUSE__MAPPER_BINDING_: @@ -15035,7 +15404,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) static void gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, - enum tree_code code) + enum tree_code code, + gimple_seq *loops_seq_p = NULL) { struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; tree *orig_list_p = list_p; @@ -15406,12 +15776,14 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, : TYPE_SIZE_UNIT (TREE_TYPE (decl)); } gimplify_omp_ctxp = ctx->outer_context; - if (gimplify_expr (&OMP_CLAUSE_SIZE (c), pre_p, NULL, + gimple_seq *seq_p; + seq_p = enter_omp_iterator_loop_context (c, loops_seq_p, pre_p); + if (gimplify_expr (&OMP_CLAUSE_SIZE (c), seq_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) { gimplify_omp_ctxp = ctx; remove = true; - break; + goto end_adjust_omp_map_clause; } else if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER || (OMP_CLAUSE_MAP_KIND (c) @@ -15420,7 +15792,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST) { OMP_CLAUSE_SIZE (c) - = get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), pre_p, NULL, + = get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), seq_p, NULL, false); if ((ctx->region_type & ORT_TARGET) != 0) omp_add_variable (ctx, OMP_CLAUSE_SIZE (c), @@ -15461,7 +15833,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, && (code == OMP_TARGET_EXIT_DATA || code == OACC_EXIT_DATA)) { remove = true; - break; + goto end_adjust_omp_map_clause; } /* If we have a DECL_VALUE_EXPR (e.g. this is a class member and/or a variable captured in a lambda closure), look through that now @@ -15477,7 +15849,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, decl = OMP_CLAUSE_DECL (c) = DECL_VALUE_EXPR (decl); if (TREE_CODE (decl) == TARGET_EXPR) { - if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, + if (gimplify_expr (&OMP_CLAUSE_DECL (c), seq_p, NULL, is_gimple_lvalue, fb_lvalue) == GS_ERROR) remove = true; } @@ -15564,19 +15936,19 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, /* If we have e.g. map(struct: *var), don't gimplify the argument since omp-low.cc wants to see the decl itself. */ if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT) - break; + goto end_adjust_omp_map_clause; /* We've already partly gimplified this in gimplify_scan_omp_clauses. Don't do any more. */ if (code == OMP_TARGET && OMP_CLAUSE_MAP_IN_REDUCTION (c)) - break; + goto end_adjust_omp_map_clause; gimplify_omp_ctxp = ctx->outer_context; - if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, + if (gimplify_expr (pd, seq_p, NULL, is_gimple_lvalue, fb_lvalue) == GS_ERROR) remove = true; gimplify_omp_ctxp = ctx; - break; + goto end_adjust_omp_map_clause; } if ((code == OMP_TARGET @@ -15709,6 +16081,8 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, == GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION))) move_attach = true; +end_adjust_omp_map_clause: + exit_omp_iterator_loop_context (c); break; case OMP_CLAUSE_TO: @@ -18347,11 +18721,18 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) gcc_unreachable (); } + gimple_seq iterator_loops_seq = NULL; + if (TREE_CODE (expr) == OMP_TARGET) + { + remove_unused_omp_iterator_vars (&OMP_CLAUSES (expr)); + build_omp_iterators_loops (&OMP_CLAUSES (expr), &iterator_loops_seq); + } + bool save_in_omp_construct = in_omp_construct; if ((ort & ORT_ACC) == 0) in_omp_construct = false; gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort, - TREE_CODE (expr)); + TREE_CODE (expr), &iterator_loops_seq); if (TREE_CODE (expr) == OMP_TARGET) optimize_target_teams (expr, pre_p); if ((ort & (ORT_TARGET | ORT_TARGET_DATA)) != 0 @@ -18390,7 +18771,7 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) else gimplify_and_add (OMP_BODY (expr), &body); gimplify_adjust_omp_clauses (pre_p, body, &OMP_CLAUSES (expr), - TREE_CODE (expr)); + TREE_CODE (expr), &iterator_loops_seq); in_omp_construct = save_in_omp_construct; switch (TREE_CODE (expr)) @@ -18433,7 +18814,7 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) break; case OMP_TARGET: stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION, - OMP_CLAUSES (expr)); + OMP_CLAUSES (expr), iterator_loops_seq); break; case OMP_TARGET_DATA: /* Put use_device_{ptr,addr} clauses last, as map clauses are supposed @@ -18508,10 +18889,16 @@ gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) default: gcc_unreachable (); } + + gimple_seq iterator_loops_seq = NULL; + remove_unused_omp_iterator_vars (&OMP_STANDALONE_CLAUSES (expr)); + build_omp_iterators_loops (&OMP_STANDALONE_CLAUSES (expr), + &iterator_loops_seq); + gimplify_scan_omp_clauses (&OMP_STANDALONE_CLAUSES (expr), pre_p, - ort, TREE_CODE (expr)); + ort, TREE_CODE (expr), &iterator_loops_seq); gimplify_adjust_omp_clauses (pre_p, NULL, &OMP_STANDALONE_CLAUSES (expr), - TREE_CODE (expr)); + TREE_CODE (expr), &iterator_loops_seq); if (TREE_CODE (expr) == OACC_UPDATE && omp_find_clause (OMP_STANDALONE_CLAUSES (expr), OMP_CLAUSE_IF_PRESENT)) @@ -18575,7 +18962,8 @@ gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) gcc_unreachable (); } } - stmt = gimple_build_omp_target (NULL, kind, OMP_STANDALONE_CLAUSES (expr)); + stmt = gimple_build_omp_target (NULL, kind, OMP_STANDALONE_CLAUSES (expr), + iterator_loops_seq); gimplify_seq_add_stmt (pre_p, stmt); *expr_p = NULL_TREE; diff --git a/gcc/gimplify.h b/gcc/gimplify.h index b66ceb3..80c335e 100644 --- a/gcc/gimplify.h +++ b/gcc/gimplify.h @@ -79,6 +79,10 @@ extern enum gimplify_status gimplify_expr (tree *, gimple_seq *, gimple_seq *, extern tree omp_get_construct_context (void); int omp_has_novariants (void); +extern gimple_seq *enter_omp_iterator_loop_context (tree, gomp_target *, + gimple_seq * = NULL); +extern void exit_omp_iterator_loop_context (tree); + extern void gimplify_type_sizes (tree, gimple_seq *); extern void gimplify_one_sizepos (tree *, gimple_seq *); extern gbind *gimplify_body (tree, bool); diff --git a/gcc/gsstruct.def b/gcc/gsstruct.def index bfe0901..34adc86 100644 --- a/gcc/gsstruct.def +++ b/gcc/gsstruct.def @@ -44,6 +44,7 @@ DEFGSSTRUCT(GSS_OMP, gimple_statement_omp, false) DEFGSSTRUCT(GSS_OMP_CRITICAL, gomp_critical, false) DEFGSSTRUCT(GSS_OMP_FOR, gomp_for, false) DEFGSSTRUCT(GSS_OMP_PARALLEL_LAYOUT, gimple_statement_omp_parallel_layout, false) +DEFGSSTRUCT(GSS_OMP_TARGET, gomp_target, false) DEFGSSTRUCT(GSS_OMP_TASK, gomp_task, false) DEFGSSTRUCT(GSS_OMP_SECTIONS, gomp_sections, false) DEFGSSTRUCT(GSS_OMP_SINGLE_LAYOUT, gimple_statement_omp_single_layout, false) diff --git a/gcc/libgdiagnostics++.h b/gcc/libgdiagnostics++.h index c955d56..fc20398 100644 --- a/gcc/libgdiagnostics++.h +++ b/gcc/libgdiagnostics++.h @@ -477,6 +477,9 @@ public: void take_global_graph (graph g); + void + set_debug_physical_locations (bool value); + diagnostic_manager *m_inner; bool m_owned; }; @@ -926,6 +929,13 @@ manager::take_global_graph (graph g) g.m_owned = false; } +inline void +manager::set_debug_physical_locations (bool value) +{ + diagnostic_manager_set_debug_physical_locations (m_inner, + value ? 1 : 0); +} + // class graph inline void diff --git a/gcc/libgdiagnostics-private.h b/gcc/libgdiagnostics-private.h index 0e90f87..4186c67 100644 --- a/gcc/libgdiagnostics-private.h +++ b/gcc/libgdiagnostics-private.h @@ -58,6 +58,13 @@ private_diagnostic_execution_path_add_event_3 (diagnostic_execution_path *path, LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (5) LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (6); +/* Entrypoint added in LIBGDIAGNOSTICS_ABI_5. */ + +extern void +private_diagnostic_set_nesting_level (diagnostic *diag, + int nesting_level) + LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1); + } // extern "C" #endif /* LIBGDIAGNOSTICS_PRIVATE_H */ diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc index 7351d336..784e281 100644 --- a/gcc/libgdiagnostics.cc +++ b/gcc/libgdiagnostics.cc @@ -639,7 +639,8 @@ struct diagnostic_manager public: diagnostic_manager () : m_current_diag (nullptr), - m_prev_diag_logical_loc (nullptr) + m_prev_diag_logical_loc (nullptr), + m_debug_physical_locations (false) { linemap_init (&m_line_table, BUILTINS_LOCATION); m_line_table.m_reallocator = xrealloc; @@ -747,6 +748,9 @@ public: new_location_from_file_and_line (const diagnostic_file *file, diagnostic_line_num_t line_num) { + if (m_debug_physical_locations) + fprintf (stderr, "new_location_from_file_and_line (%s, %i)", + file->get_name (), line_num); ensure_linemap_for_file_and_line (file, line_num); location_t loc = linemap_position_for_column (&m_line_table, 0); return new_location (loc); @@ -757,6 +761,9 @@ public: diagnostic_line_num_t line_num, diagnostic_column_num_t column_num) { + if (m_debug_physical_locations) + fprintf (stderr, "new_location_from_file_line_column (%s, %i, %i)", + file->get_name (), line_num, column_num); ensure_linemap_for_file_and_line (file, line_num); location_t loc = linemap_position_for_column (&m_line_table, column_num); return new_location (loc); @@ -767,12 +774,23 @@ public: const diagnostic_physical_location *loc_start, const diagnostic_physical_location *loc_end) { + if (m_debug_physical_locations) + fprintf (stderr, "new_location_from_range (%p, %p, %p)", + (const void *)loc_caret, + (const void *)loc_start, + (const void *)loc_end); return new_location (m_line_table.make_location (as_location_t (loc_caret), as_location_t (loc_start), as_location_t (loc_end))); } + void + set_debug_physical_locations (bool value) + { + m_debug_physical_locations = value; + } + const diagnostic_logical_location * new_logical_location (enum diagnostic_logical_location_kind_t kind, const diagnostic_logical_location *parent, @@ -874,11 +892,17 @@ private: linemap_add (&m_line_table, LC_ENTER, false, file->get_name (), 0); else { - line_map *map - = const_cast<line_map *> - (linemap_add (&m_line_table, LC_RENAME_VERBATIM, false, - file->get_name (), 0)); - ((line_map_ordinary *)map)->included_from = UNKNOWN_LOCATION; + line_map_ordinary *last_map + = LINEMAPS_LAST_ORDINARY_MAP (&m_line_table); + if (last_map->to_file != file->get_name () + || linenum < last_map->to_line) + { + line_map *map + = const_cast<line_map *> + (linemap_add (&m_line_table, LC_RENAME_VERBATIM, false, + file->get_name (), 0)); + ((line_map_ordinary *)map)->included_from = UNKNOWN_LOCATION; + } } linemap_line_start (&m_line_table, linenum, 100); } @@ -888,11 +912,19 @@ private: { if (loc == UNKNOWN_LOCATION) return nullptr; + if (m_debug_physical_locations) + fprintf (stderr, ": new_location (%lx)", loc); if (diagnostic_physical_location **slot = m_location_t_map.get (loc)) - return *slot; + { + if (m_debug_physical_locations) + fprintf (stderr, ": cache hit: %p\n", (const void *)*slot); + return *slot; + } diagnostic_physical_location *phys_loc = new diagnostic_physical_location (this, loc); m_location_t_map.put (loc, phys_loc); + if (m_debug_physical_locations) + fprintf (stderr, ": cache miss: %p\n", (const void *)phys_loc); return phys_loc; } @@ -909,6 +941,7 @@ private: const diagnostic *m_current_diag; const diagnostic_logical_location *m_prev_diag_logical_loc; std::unique_ptr<diagnostics::changes::change_set> m_change_set; + bool m_debug_physical_locations; }; class impl_rich_location : public rich_location @@ -1221,7 +1254,8 @@ public: m_level (level), m_rich_loc (diag_mgr.get_line_table ()), m_logical_loc (nullptr), - m_path (nullptr) + m_path (nullptr), + m_nesting_level (0) { m_metadata.set_lazy_digraphs (&m_graphs); } @@ -1325,6 +1359,9 @@ public: return m_graphs; } + int get_nesting_level () const { return m_nesting_level; } + void set_nesting_level (int value) { m_nesting_level = value; } + private: diagnostic_manager &m_diag_mgr; enum diagnostic_level m_level; @@ -1335,6 +1372,7 @@ private: std::vector<std::unique_ptr<range_label>> m_labels; std::vector<std::unique_ptr<impl_rule>> m_rules; std::unique_ptr<diagnostic_execution_path> m_path; + int m_nesting_level; }; static enum diagnostics::kind @@ -1624,8 +1662,9 @@ GCC_DIAGNOSTIC_PUSH_IGNORED(-Wsuggest-attribute=format) GCC_DIAGNOSTIC_POP info.m_metadata = diag.get_metadata (); info.m_x_data = &diag; + m_dc.set_nesting_level (diag.get_nesting_level ()); diagnostic_report_diagnostic (&m_dc, &info); - + m_dc.set_nesting_level (0); m_dc.end_group (); } @@ -2972,3 +3011,23 @@ private_diagnostic_execution_path_add_event_3 (diagnostic_execution_path *path, return as_diagnostic_event_id (result); } + +/* Public entrypoint. */ + +void +diagnostic_manager_set_debug_physical_locations (diagnostic_manager *mgr, + int value) +{ + FAIL_IF_NULL (mgr); + mgr->set_debug_physical_locations (value); +} + +/* Private entrypoint. */ + +void +private_diagnostic_set_nesting_level (diagnostic *diag, + int nesting_level) +{ + FAIL_IF_NULL (diag); + diag->set_nesting_level (nesting_level); +} diff --git a/gcc/libgdiagnostics.h b/gcc/libgdiagnostics.h index c202feb..0ae56f0 100644 --- a/gcc/libgdiagnostics.h +++ b/gcc/libgdiagnostics.h @@ -1115,6 +1115,16 @@ diagnostic_node_set_label_via_msg_buf (diagnostic_node *node, LIBGDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1) LIBGDIAGNOSTICS_PARAM_CAN_BE_NULL (2); +/* If non-zero, print debugging information to stderr when + creating diagnostic_physical_location instances. + + Added in LIBGDIAGNOSTICS_ABI_5. */ +#define LIBDIAGNOSTICS_HAVE_diagnostic_manager_set_debug_physical_locations + +extern void +diagnostic_manager_set_debug_physical_locations (diagnostic_manager *mgr, + int value); + /* DEFERRED: - thread-safety - plural forms diff --git a/gcc/libgdiagnostics.map b/gcc/libgdiagnostics.map index 91f3951..0400ca7 100644 --- a/gcc/libgdiagnostics.map +++ b/gcc/libgdiagnostics.map @@ -141,3 +141,11 @@ LIBGDIAGNOSTICS_ABI_4 { # Private hook used by sarif-replay private_diagnostic_execution_path_add_event_3; } LIBGDIAGNOSTICS_ABI_3; + +LIBGDIAGNOSTICS_ABI_5 { + global: + diagnostic_manager_set_debug_physical_locations; + + # Private hook used by sarif-replay + private_diagnostic_set_nesting_level; +} LIBGDIAGNOSTICS_ABI_4; diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc index 1e4a74f..e8fc6d0 100644 --- a/gcc/libsarifreplay.cc +++ b/gcc/libsarifreplay.cc @@ -1408,10 +1408,22 @@ sarif_replayer::handle_result_obj (const json::object &result_obj, rule_obj)); if (!msg_buf.m_inner) return status::err_invalid_sarif; + auto note (m_output_mgr.begin_diagnostic (DIAGNOSTIC_LEVEL_NOTE)); note.set_location (physical_loc); note.set_logical_location (logical_loc); add_any_annotations (note, annotations); + + /* Look for "nestingLevel" property, as per + "P3358R0 SARIF for Structured Diagnostics" + https://wg21.link/P3358R0 */ + if (auto nesting_level + = maybe_get_property_bag_value<json::integer_number> + (*location_obj, + "nestingLevel")) + private_diagnostic_set_nesting_level (note.m_inner, + nesting_level->get ()); + notes.push_back ({std::move (note), std::move (msg_buf)}); } else diff --git a/gcc/libsarifreplay.h b/gcc/libsarifreplay.h index fb66014..313a905 100644 --- a/gcc/libsarifreplay.h +++ b/gcc/libsarifreplay.h @@ -31,6 +31,7 @@ struct replay_options bool m_echo_file; bool m_json_comments; bool m_verbose; + bool m_debug_physical_locations; enum diagnostic_colorize m_diagnostics_colorize; }; diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc index cb293f2..03fca97 100644 --- a/gcc/lto-wrapper.cc +++ b/gcc/lto-wrapper.cc @@ -2265,13 +2265,14 @@ cont: obstack_free (&argv_obstack, NULL); } -/* Concrete implementation of diagnostic_option_manager for LTO. */ +/* Concrete implementation of diagnostics::option_id_manager for LTO. */ -class lto_diagnostic_option_manager : public gcc_diagnostic_option_manager +class lto_diagnostic_option_id_manager + : public gcc_diagnostic_option_id_manager { public: - lto_diagnostic_option_manager () - : gcc_diagnostic_option_manager (0 /* lang_mask */) + lto_diagnostic_option_id_manager () + : gcc_diagnostic_option_id_manager (0 /* lang_mask */) { } int option_enabled_p (diagnostics::option_id) const final override @@ -2307,8 +2308,8 @@ main (int argc, char *argv[]) diagnostic_initialize (global_dc, 0); diagnostic_color_init (global_dc); diagnostic_urls_init (global_dc); - global_dc->set_option_manager - (::make_unique<lto_diagnostic_option_manager> (), 0); + global_dc->set_option_id_manager + (::make_unique<lto_diagnostic_option_id_manager> (), 0); if (atexit (lto_wrapper_cleanup) != 0) fatal_error (input_location, "%<atexit%> failed"); diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index e1036ad..9d80a35 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -12651,6 +12651,63 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) } } + /* Set EXPR as the hostaddr expression that should result from the clause C + in the target statement STMT. Returns the tree that should be + passed as the hostaddr (a pointer to the array containing the expanded + hostaddrs and sizes of the clause). */ + +static tree +lower_omp_map_iterator_expr (tree expr, tree c, gomp_target *stmt) +{ + if (!OMP_CLAUSE_HAS_ITERATORS (c)) + return expr; + + tree iterator = OMP_CLAUSE_ITERATORS (c); + tree elems = TREE_VEC_ELT (iterator, 7); + tree index = TREE_VEC_ELT (iterator, 8); + gimple_seq *loop_body_p = enter_omp_iterator_loop_context (c, stmt); + + /* IN LOOP BODY: */ + /* elems[idx] = <expr>; */ + tree lhs = build4 (ARRAY_REF, ptr_type_node, elems, index, + NULL_TREE, NULL_TREE); + tree mod_expr = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, + void_type_node, lhs, expr); + gimplify_and_add (mod_expr, loop_body_p); + exit_omp_iterator_loop_context (c); + + return build_fold_addr_expr_with_type (elems, ptr_type_node); +} + +/* Set SIZE as the size expression that should result from the clause C + in the target statement STMT. Returns the tree that should be + passed as the clause size (a size_int with the value SIZE_MAX, indicating + that the clause uses an iterator). */ + +static tree +lower_omp_map_iterator_size (tree size, tree c, gomp_target *stmt) +{ + if (!OMP_CLAUSE_HAS_ITERATORS (c)) + return size; + + tree iterator = OMP_CLAUSE_ITERATORS (c); + tree elems = TREE_VEC_ELT (iterator, 7); + tree index = TREE_VEC_ELT (iterator, 8); + gimple_seq *loop_body_p = enter_omp_iterator_loop_context (c, stmt); + + /* IN LOOP BODY: */ + /* elems[idx+1] = <size>; */ + tree lhs = build4 (ARRAY_REF, ptr_type_node, elems, + size_binop (PLUS_EXPR, index, size_int (1)), + NULL_TREE, NULL_TREE); + tree mod_expr = build2_loc (OMP_CLAUSE_LOCATION (c), MODIFY_EXPR, + void_type_node, lhs, size); + gimplify_and_add (mod_expr, loop_body_p); + exit_omp_iterator_loop_context (c); + + return size_int (SIZE_MAX); +} + /* Lower the GIMPLE_OMP_TARGET in the current statement in GSI_P. CTX holds context information for the directive. */ @@ -12820,6 +12877,11 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) deep_map_cnt = extra; } + if (deep_map_cnt + && OMP_CLAUSE_HAS_ITERATORS (c)) + sorry ("iterators used together with deep mapping are not " + "supported yet"); + if (!DECL_P (var)) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP @@ -13234,6 +13296,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) *p = build_fold_indirect_ref (nd); } v = build_fold_addr_expr_with_type (v, ptr_type_node); + v = lower_omp_map_iterator_expr (v, c, stmt); gimplify_assign (x, v, &ilist); nc = NULL_TREE; } @@ -13307,12 +13370,17 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE) { gcc_assert (offloaded); - tree avar - = create_tmp_var (TREE_TYPE (TREE_TYPE (x))); - mark_addressable (avar); - gimplify_assign (avar, build_fold_addr_expr (var), &ilist); - talign = DECL_ALIGN_UNIT (avar); + tree avar = build_fold_addr_expr (var); + if (!OMP_CLAUSE_ITERATORS (c)) + { + tree tmp = create_tmp_var (TREE_TYPE (TREE_TYPE (x))); + mark_addressable (tmp); + gimplify_assign (tmp, avar, &ilist); + avar = tmp; + } + talign = TYPE_ALIGN_UNIT (TREE_TYPE (TREE_TYPE (x))); avar = build_fold_addr_expr (avar); + avar = lower_omp_map_iterator_expr (avar, c, stmt); gimplify_assign (x, avar, &ilist); } else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) @@ -13392,6 +13460,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (s == NULL_TREE) s = TYPE_SIZE_UNIT (TREE_TYPE (ovar)); s = fold_convert (size_type_node, s); + s = lower_omp_map_iterator_size (s, c, stmt); purpose = size_int (map_idx++); CONSTRUCTOR_APPEND_ELT (vsize, purpose, s); if (TREE_CODE (s) != INTEGER_CST) @@ -14324,6 +14393,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_omp_set_body (stmt, new_body); } + gsi_insert_seq_before (gsi_p, gimple_omp_target_iterator_loops (stmt), + GSI_SAME_STMT); + gimple_omp_target_set_iterator_loops (stmt, NULL); bind = gimple_build_bind (NULL, NULL, tgt_bind ? gimple_bind_block (tgt_bind) : NULL_TREE); diff --git a/gcc/opt-problem.cc b/gcc/opt-problem.cc index 8324feb..e0c7601 100644 --- a/gcc/opt-problem.cc +++ b/gcc/opt-problem.cc @@ -42,7 +42,7 @@ along with GCC; see the file COPYING3. If not see opt_problem::opt_problem (const dump_location_t &loc, const char *fmt, va_list *ap) -: m_optinfo (loc, OPTINFO_KIND_FAILURE, current_pass) +: m_optinfo (loc, optinfo::kind::failure, current_pass) { /* We shouldn't be bothering to construct these objects if dumping isn't enabled. */ diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc index 28c8a98..ae686a9 100644 --- a/gcc/optinfo-emit-json.cc +++ b/gcc/optinfo-emit-json.cc @@ -143,7 +143,7 @@ optrecord_json_writer::add_record (const optinfo *optinfo) add_record (obj); /* Potentially push the scope. */ - if (optinfo->get_kind () == OPTINFO_KIND_SCOPE) + if (optinfo->get_kind () == optinfo::kind::scope) { json::array *children = new json::array (); obj->set ("children", children); @@ -334,7 +334,7 @@ optrecord_json_writer::optinfo_to_json (const optinfo *optinfo) obj->set ("impl_location", impl_location_to_json (optinfo->get_impl_location ())); - const char *kind_str = optinfo_kind_to_string (optinfo->get_kind ()); + const char *kind_str = optinfo::kind_to_string (optinfo->get_kind ()); obj->set_string ("kind", kind_str); json::array *message = new json::array (); obj->set ("message", message); @@ -345,12 +345,12 @@ optrecord_json_writer::optinfo_to_json (const optinfo *optinfo) { default: gcc_unreachable (); - case OPTINFO_ITEM_KIND_TEXT: + case optinfo_item::kind::text: { message->append_string (item->get_text ()); } break; - case OPTINFO_ITEM_KIND_TREE: + case optinfo_item::kind::tree: { json::object *json_item = new json::object (); json_item->set_string ("expr", item->get_text ()); @@ -363,7 +363,7 @@ optrecord_json_writer::optinfo_to_json (const optinfo *optinfo) message->append (json_item); } break; - case OPTINFO_ITEM_KIND_GIMPLE: + case optinfo_item::kind::gimple: { json::object *json_item = new json::object (); json_item->set_string ("stmt", item->get_text ()); @@ -376,7 +376,7 @@ optrecord_json_writer::optinfo_to_json (const optinfo *optinfo) message->append (json_item); } break; - case OPTINFO_ITEM_KIND_SYMTAB_NODE: + case optinfo_item::kind::symtab_node: { json::object *json_item = new json::object (); json_item->set_string ("symtab_node", item->get_text ()); diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc index 51e9fd6..dd5a551 100644 --- a/gcc/optinfo.cc +++ b/gcc/optinfo.cc @@ -36,9 +36,9 @@ along with GCC; see the file COPYING3. If not see /* optinfo_item's ctor. Takes ownership of TEXT. */ -optinfo_item::optinfo_item (enum optinfo_item_kind kind, location_t location, +optinfo_item::optinfo_item (enum kind kind_, location_t location, char *text) -: m_kind (kind), m_location (location), m_text (text) +: m_kind (kind_), m_location (location), m_text (text) { } @@ -52,19 +52,19 @@ optinfo_item::~optinfo_item () /* Get a string from KIND. */ const char * -optinfo_kind_to_string (enum optinfo_kind kind) +optinfo::kind_to_string (enum kind kind_) { - switch (kind) + switch (kind_) { default: gcc_unreachable (); - case OPTINFO_KIND_SUCCESS: + case kind::success: return "success"; - case OPTINFO_KIND_FAILURE: + case kind::failure: return "failure"; - case OPTINFO_KIND_NOTE: + case kind::note: return "note"; - case OPTINFO_KIND_SCOPE: + case kind::scope: return "scope"; } } @@ -91,19 +91,19 @@ optinfo::add_item (std::unique_ptr<optinfo_item> item) /* Get MSG_* flags corresponding to KIND. */ -static dump_flags_t -optinfo_kind_to_dump_flag (enum optinfo_kind kind) +dump_flags_t +optinfo::kind_to_dump_flag (enum kind kind_) { - switch (kind) + switch (kind_) { default: gcc_unreachable (); - case OPTINFO_KIND_SUCCESS: + case kind::success: return MSG_OPTIMIZED_LOCATIONS; - case OPTINFO_KIND_FAILURE: + case kind::failure: return MSG_MISSED_OPTIMIZATION; - case OPTINFO_KIND_NOTE: - case OPTINFO_KIND_SCOPE: + case kind::note: + case kind::scope: return MSG_NOTE; } } @@ -114,7 +114,7 @@ optinfo_kind_to_dump_flag (enum optinfo_kind kind) void optinfo::emit_for_opt_problem () const { - dump_flags_t dump_kind = optinfo_kind_to_dump_flag (get_kind ()); + dump_flags_t dump_kind = kind_to_dump_flag (get_kind ()); dump_kind |= MSG_PRIORITY_REEMITTED; /* Re-emit to "immediate" destinations, without creating a new optinfo. */ @@ -134,14 +134,14 @@ void optinfo::handle_dump_file_kind (dump_flags_t dump_kind) { /* Any optinfo for a "scope" should have been emitted separately. */ - gcc_assert (m_kind != OPTINFO_KIND_SCOPE); + gcc_assert (m_kind != kind::scope); if (dump_kind & MSG_OPTIMIZED_LOCATIONS) - m_kind = OPTINFO_KIND_SUCCESS; + m_kind = kind::success; else if (dump_kind & MSG_MISSED_OPTIMIZATION) - m_kind = OPTINFO_KIND_FAILURE; + m_kind = kind::failure; else if (dump_kind & MSG_NOTE) - m_kind = OPTINFO_KIND_NOTE; + m_kind = kind::note; } /* Return true if any of the active optinfo destinations make use diff --git a/gcc/optinfo.h b/gcc/optinfo.h index 1e0fb22..ca9457f 100644 --- a/gcc/optinfo.h +++ b/gcc/optinfo.h @@ -74,18 +74,6 @@ class optinfo_item; extern bool optinfo_wants_inlining_info_p (); -/* The various kinds of optinfo. */ - -enum optinfo_kind -{ - OPTINFO_KIND_SUCCESS, - OPTINFO_KIND_FAILURE, - OPTINFO_KIND_NOTE, - OPTINFO_KIND_SCOPE -}; - -extern const char *optinfo_kind_to_string (enum optinfo_kind kind); - class dump_context; /* A bundle of information describing part of an optimization. */ @@ -95,10 +83,19 @@ class optinfo friend class dump_context; public: + /* The various kinds of optinfo. */ + enum class kind + { + success, + failure, + note, + scope + }; + optinfo (const dump_location_t &loc, - enum optinfo_kind kind, + enum kind kind_, opt_pass *pass) - : m_loc (loc), m_kind (kind), m_pass (pass), m_items () + : m_loc (loc), m_kind (kind_), m_pass (pass), m_items () {} ~optinfo (); @@ -111,7 +108,7 @@ class optinfo const dump_impl_location_t & get_impl_location () const { return m_loc.get_impl_location (); } - enum optinfo_kind get_kind () const { return m_kind; } + enum kind get_kind () const { return m_kind; } opt_pass *get_pass () const { return m_pass; } unsigned int num_items () const { return m_items.length (); } const optinfo_item *get_item (unsigned int i) const { return m_items[i]; } @@ -123,6 +120,9 @@ class optinfo void emit_for_opt_problem () const; + static const char *kind_to_string (enum kind k); + static dump_flags_t kind_to_dump_flag (enum kind k); + private: /* Pre-canned ways of manipulating the optinfo, for use by friend class dump_context. */ @@ -130,37 +130,36 @@ class optinfo private: dump_location_t m_loc; - enum optinfo_kind m_kind; + enum kind m_kind; opt_pass *m_pass; auto_vec <optinfo_item *> m_items; }; -/* An enum for discriminating between different kinds of optinfo_item. */ - -enum optinfo_item_kind -{ - OPTINFO_ITEM_KIND_TEXT, - OPTINFO_ITEM_KIND_TREE, - OPTINFO_ITEM_KIND_GIMPLE, - OPTINFO_ITEM_KIND_SYMTAB_NODE -}; - /* An item within an optinfo. */ class optinfo_item { public: - optinfo_item (enum optinfo_item_kind kind, location_t location, + /* An enum for discriminating between different kinds of optinfo_item. */ + enum class kind + { + text, + tree, + gimple, + symtab_node + }; + + optinfo_item (enum kind kind_, location_t location, char *text); ~optinfo_item (); - enum optinfo_item_kind get_kind () const { return m_kind; } + enum kind get_kind () const { return m_kind; } location_t get_location () const { return m_location; } const char *get_text () const { return m_text; } private: /* Metadata (e.g. for optimization records). */ - enum optinfo_item_kind m_kind; + enum kind m_kind; location_t m_location; /* The textual form of the item, owned by the item. */ diff --git a/gcc/opts-common.cc b/gcc/opts-common.cc index 91cad49..e6d7f4d 100644 --- a/gcc/opts-common.cc +++ b/gcc/opts-common.cc @@ -1876,7 +1876,7 @@ option_enabled (int opt_idx, unsigned lang_mask, void *opts) } int -compiler_diagnostic_option_manager:: +compiler_diagnostic_option_id_manager:: option_enabled_p (diagnostics::option_id opt_id) const { return option_enabled (opt_id.m_idx, m_lang_mask, m_opts); diff --git a/gcc/opts-diagnostic.h b/gcc/opts-diagnostic.h index 4fa4ea8..25ade86 100644 --- a/gcc/opts-diagnostic.h +++ b/gcc/opts-diagnostic.h @@ -20,30 +20,31 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_OPTS_DIAGNOSTIC_H #define GCC_OPTS_DIAGNOSTIC_H -/* Abstract subclass of diagnostics::option_manager for gcc options. */ +/* Abstract subclass of diagnostics::option_id_manager for gcc options. */ -class gcc_diagnostic_option_manager : public diagnostics::option_manager +class gcc_diagnostic_option_id_manager : public diagnostics::option_id_manager { public: char *make_option_url (diagnostics::option_id option_id) const final override; protected: - gcc_diagnostic_option_manager (unsigned lang_mask) + gcc_diagnostic_option_id_manager (unsigned lang_mask) : m_lang_mask (lang_mask) {} unsigned m_lang_mask; }; -/* Concrete implementation of diagnostic_option_manager for compiler. */ +/* Concrete implementation of diagnostics::option_id_manager for compiler. */ -class compiler_diagnostic_option_manager : public gcc_diagnostic_option_manager +class compiler_diagnostic_option_id_manager + : public gcc_diagnostic_option_id_manager { public: - compiler_diagnostic_option_manager (const diagnostics::context &context, - unsigned lang_mask, - void *opts) - : gcc_diagnostic_option_manager (lang_mask), + compiler_diagnostic_option_id_manager (const diagnostics::context &context, + unsigned lang_mask, + void *opts) + : gcc_diagnostic_option_id_manager (lang_mask), m_context (context), m_opts (opts) { diff --git a/gcc/opts.cc b/gcc/opts.cc index c21e66b..b6d25bf 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -3744,7 +3744,7 @@ enable_warning_as_error (const char *arg, int value, unsigned int lang_mask, as -Werror. */ char * -compiler_diagnostic_option_manager:: +compiler_diagnostic_option_id_manager:: make_option_name (diagnostics::option_id option_id, enum diagnostics::kind orig_diag_kind, enum diagnostics::kind diag_kind) const @@ -3823,7 +3823,7 @@ get_option_url_suffix (int option_index, unsigned lang_mask) which enabled a diagnostic. */ char * -gcc_diagnostic_option_manager:: +gcc_diagnostic_option_id_manager:: make_option_url (diagnostics::option_id option_id) const { if (option_id.m_idx) diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog index f103c7e..f960ef2 100644 --- a/gcc/rust/ChangeLog +++ b/gcc/rust/ChangeLog @@ -1,3 +1,2391 @@ +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * Make-lang.in (rust-readonly-check2.cc): + Add read-only check on HIR + * checks/errors/rust-readonly-check2.cc (ReadonlyChecker): + Add read-only check on HIR + * checks/errors/rust-readonly-check2.h (ReadonlyChecker): + Add read-only check on HIR + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk): + Call base class's accept_vis method + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk): + Add check before calling `get_trait_ref()` + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-macro-builtins-helpers.cc + (try_extract_string_literal_from_fragment): Perform static_cast + to AST::LiteralExpr only after it's verified that an AST::Expr + is a literal. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * util/rust-attribute-values.h + (Attributes::RUSTC_ARGS_REQUIRED_CONST): New constexpr variable. + * util/rust-attributes.cc (__definitions): New entry for + RUSTC_ARGS_REQUIRED_CONST. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast.cc (AttributeParser::parse_meta_item_inner): + Handle removal of AttributeParser-specific functions. + (AttributeParser::parse_path_meta_item): Likewise. + (AttributeParser::parse_meta_item_seq): Likewise. + (AttributeParser::parse_meta_item_lit): Likewise. + (AttributeParser::parse_literal): Remove function. + (AttributeParser::parse_simple_path): Likewise. + (AttributeParser::parse_simple_path_segment): Likewise. + (AttributeParser::peek_token): Likewise. + (AttributeParser::skip_token): Likewise. + * ast/rust-macro.h (AttributeParser::parse_simple_path): + Likewise. + (AttributeParser::parse_simple_path_segment): Likewise. + (AttributeParser::parse_literal): Likewise. + (AttributeParser::peek_token): Likewise. + (AttributeParser::skip_token): Likewise. + * parse/rust-parse.h (Parser): Make AttributeParser a friend + class. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): Add proper handling + of the node. + * rust-backend.h (lookup_field): Declare it. + * rust-gcc.cc (lookup_field): Add forked implementation from gcc/c/. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast.cc (AttributeParser::parse_path_meta_item): Catch + parse_expr returning nullptr and remove defunct comment. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * Make-lang.in (GRS_OBJS): Add entries. + * parse/rust-parse-impl.h: Adjust header comment. + (Parser::parse_lifetime_params_objs): Fix bug and add comment. + (Parser::unexpected_token): Likewise. + * parse/rust-parse.h: Remove inclusion of "rust-parse-impl.h". + * parse/rust-parse-impl-lexer.cc: New file. + * parse/rust-parse-impl-macro.cc: New file. + * parse/rust-parse-impl-proc-macro.cc: New file. + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * hir/rust-ast-lower-implitem.cc (ASTLowerTraitItem::visit): + Fix object copying issue causing pointer inconsistency + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.cc (AttributeParser::parse_path_meta_item): Parse + expression instead of literal. Update variant name. + (MetaItemPathLit::to_attribute): Remove function. + (AttributeParser::parse_path_meta_item): Update name. + (MetaItemPathLit::check_cfg_predicate): Likewise. + (MetaItemPathExpr::check_cfg_predicate): Likewise. + (MetaItemPathLit::accept_vis): Likewise. + (MetaItemPathExpr::accept_vis): Likewise. + * ast/rust-ast-collector.h: Update prototype and adapt code to new + expression. + * ast/rust-ast-collector.cc: Update code to expr. + * ast/rust-ast-full-decls.h (class MetaItemPathLit): Likewise. + (class MetaItemPathExpr): Likewise. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast-visitor.h: Likewise. + * ast/rust-ast.h (class MetaItemPathLit): Rename class from here... + (class MetaItemPathExpr): ... to here. + * ast/rust-expr.h (class MetaItemPathLit): Rename class from here... + (class MetaItemPathExpr): ...to here. + * expand/rust-derive.h: Update class name. + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): Likewise. + * expand/rust-expand-visitor.h: Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Likewise. + * hir/rust-ast-lower-base.h: Likewise. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Likewise. + * resolve/rust-ast-resolve-base.h: Likewise. + * resolve/rust-early-name-resolver.cc (EarlyNameResolver::visit): + Likewise. + * resolve/rust-early-name-resolver.h: Likewise. + * util/rust-attributes.cc (AttributeChecker::visit): Likewise. + * util/rust-attributes.h: Likewise. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc (SubstitutionRef::infer_substitions): remove debug + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-type-util.cc (unify_site_and): improve debug + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-autoderef.cc: remove useless assertion + * typecheck/rust-coercion.cc (TypeCoercionRules::coerce_unsafe_ptr): refactor + (TypeCoercionRules::coerce_borrowed_pointer): remove FIXME this is fine + * typecheck/rust-hir-inherent-impl-overlap.h: use types_compatable + * typecheck/rust-hir-path-probe.cc (PathProbeType::PathProbeType): remove const + (PathProbeType::Probe): likewise + (PathProbeImplTrait::PathProbeImplTrait): likewise + (PathProbeImplTrait::Probe): likewise + * typecheck/rust-hir-path-probe.h: likewise + * typecheck/rust-hir-type-check-base.cc (walk_types_to_constrain): likewise + * typecheck/rust-hir-type-check-base.h: likewise + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): use types_compatable + * typecheck/rust-hir-type-check.h: remove const + * typecheck/rust-typecheck-context.cc (TypeCheckContext::insert_associated_impl_mapping): + likewise + (TypeCheckContext::lookup_associated_impl_mapping_for_self): remove can_Eq + * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::is_equal): likewise + * typecheck/rust-tyty-subst.cc (SubstitutionArg::get_tyty): remove const version + * typecheck/rust-tyty-subst.h: likewise + * typecheck/rust-tyty.cc (BaseType::get_root): likewise + * typecheck/rust-tyty.h: likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc: track the const generic + * typecheck/rust-tyty.cc (ConstType::is_equal): finish the is_equal + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-hir-dump.cc (Dump::Dump): Initialize flag. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-ast-lower-pattern.cc (ASTLoweringPattern::ASTLoweringPattern): + flag was not initialized in the constructor. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-ast-lower-implitem.cc (ASTLowerTraitItem::visit): Remove + use after move. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-macro-builtins-helpers.cc: Remove use after move. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * ast/rust-ast-collector.cc: Add support for the 2 new classes. + * ast/rust-ast-collector.h: Header file update for above. + * ast/rust-ast-full-decls.h: Add forward decls for the 2 new classes. + * ast/rust-ast-visitor.cc: Add visit support for the 2 new classes. + * ast/rust-ast-visitor.h: Header file update for above. + * ast/rust-pattern.cc: Implementation of certain methods for the 2 new classes. + * ast/rust-pattern.h: Define the 2 new classes. Update SlicePattern to be able to hold + 2 kinds of items - SlicePatternItemsNoRest or SlicePatternItemsRest. + * expand/rust-cfg-strip.cc: Add support for the 2 new classes. + * expand/rust-cfg-strip.h: Header file update for above. + * expand/rust-derive.h: Add visits for the 2 new classes. + * hir/rust-ast-lower-base.cc: Add visits for the 2 new classes. + * hir/rust-ast-lower-base.h: Header file update for above. + * hir/rust-ast-lower-pattern.cc: Update lowering of SlicePattern to support + SlicePatternItemsNoRest. + * parse/rust-parse-impl.h (parse_slice_pattern()): Add support for parsing DOT_DOT into + respective SlicePatternItems. + * resolve/rust-ast-resolve-base.cc: Add visits for the 2 new classes. + * resolve/rust-ast-resolve-base.h: Header file update for above. + * resolve/rust-ast-resolve-pattern.cc: Update SlicePattern resolution to support new + classes. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-subst.cc: fix check for total arguments + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): create infer variable + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-hir-dump.cc (Dump::visit): check for expression + * hir/tree/rust-hir.cc (AnonConst::as_string): likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): check for value + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): formatting + * typecheck/rust-tyty-variance-analysis-private.h: likewise + * typecheck/rust-tyty.cc (VariantDef::clone): likewise + (VariantDef::monomorphized_clone): likewise + * typecheck/rust-tyty.h: likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc: useful debug + * backend/rust-compile-stmt.cc (CompileStmt::visit): likewise + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): fold the capacity into ConstType + * hir/tree/rust-hir-generic-param.h: make const + * hir/tree/rust-hir-path.h: take into account const arguments now + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::resolve_literal): needs const + * typecheck/rust-hir-type-check-base.h: add error handling for const supported locations + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): const type the arrays + * typecheck/rust-hir-type-check-implitem.cc (TypeCheckTopLevelExternItem::visit): update + (TypeCheckImplItem::visit): likewise + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): likewise + (TypeCheckItem::resolve_impl_block_substitutions): likewise + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): wrap up const type + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise + (TypeResolveGenericParam::visit): likewise + (TypeResolveGenericParam::apply_trait_bounds): remove HIR::Generic from Param + * typecheck/rust-hir-type-check.cc (TraitItemReference::get_type_from_fn): cleanup + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::SubstitutionParamMapping): + handle const generics + (SubstitutionParamMapping::get_type_representation): likewise + (SubstitutionParamMapping::param_has_default_ty): likewise + (SubstitutionParamMapping::get_default_ty): likewise + (SubstitutionRef::infer_substitions): likewise + * typecheck/rust-tyty-subst.h: likewise + * typecheck/rust-tyty-util.cc (TyVar::get_implicit_const_infer_var): new helper + * typecheck/rust-tyty-util.h (class ConstType): likewise + * typecheck/rust-tyty.cc (BaseType::is_concrete): check for array const concrete + (ArrayType::as_string): update to const + (ArrayType::handle_substitions): likewise + (ParamType::ParamType): likewise + (ParamType::get_generic_param): likewise + (ParamType::clone): likewise + (ConstType::ConstType): likewise + (ConstType::set_value): likewise + (ConstType::clone): likewise + (ConstType::get_generic_param): likewise + (generate_tree_str): new helper to pretty print gimple + (ConstType::get_name): uses the generate_tree_str + (ConstType::handle_substitions): handle const infer's + * typecheck/rust-tyty.h (RUST_TYTY): likewise + * typecheck/rust-unify.cc (UnifyRules::expect_array): likewise + (UnifyRules::expect_const): likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): error_mark_node for const types + * backend/rust-compile-type.h: boilerplate + * checks/errors/borrowck/rust-bir-fact-collector.h: likewise + * checks/errors/borrowck/rust-bir-place.h: likewise + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::check_base_type_privacy): + likewise + * typecheck/rust-substitution-mapper.cc (SubstMapperInternal::visit): likewise + * typecheck/rust-substitution-mapper.h: likewise + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::assemble_marker_builtins): likewise + * typecheck/rust-tyty-call.h: likewise + * typecheck/rust-tyty-cmp.h (class ConstCmp): likewise + * typecheck/rust-tyty-variance-analysis-private.h: likewise + * typecheck/rust-tyty-visitor.h: likewise + * typecheck/rust-tyty.cc (TypeKindFormat::to_string): likewise + (BaseType::is_unit): likewise + (BaseType::has_substitutions_defined): likewise + (BaseType::needs_generic_substitutions): likewise + (ConstType::ConstType): likewise + (ConstType::accept_vis): likewise + (ConstType::as_string): likewise + (ConstType::can_eq): likewise + (ConstType::clone): likewise + (ConstType::get_symbol): likewise + (ConstType::get_generic_param): likewise + (ConstType::can_resolve): likewise + (ConstType::resolve): likewise + (ConstType::get_name): likewise + (ConstType::is_equal): likewise + (ConstType::handle_substitions): likewise + * typecheck/rust-tyty.h (enum TypeKind): new tyty_kind + (class ConstType): new type + * typecheck/rust-unify.cc (UnifyRules::go): Handle a const type unify + (UnifyRules::expect_inference_variable): likewise + (UnifyRules::expect_adt): likewise + (UnifyRules::expect_str): likewise + (UnifyRules::expect_reference): likewise + (UnifyRules::expect_pointer): likewise + (UnifyRules::expect_param): likewise + (UnifyRules::expect_array): likewise + (UnifyRules::expect_slice): likewise + (UnifyRules::expect_fndef): likewise + (UnifyRules::expect_fnptr): likewise + (UnifyRules::expect_tuple): likewise + (UnifyRules::expect_bool): likewise + (UnifyRules::expect_char): likewise + (UnifyRules::expect_int): likewise + (UnifyRules::expect_uint): likewise + (UnifyRules::expect_float): likewise + (UnifyRules::expect_isize): likewise + (UnifyRules::expect_usize): likewise + (UnifyRules::expect_placeholder): likewise + (UnifyRules::expect_projection): likewise + (UnifyRules::expect_dyn): likewise + (UnifyRules::expect_closure): likewise + (UnifyRules::expect_const): likewise + * typecheck/rust-unify.h: new expect_const_type handler + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-intrinsic.cc (sizeof_handler): refactor types + (op_with_overflow_inner): likewise + (uninit_handler): likewise + (move_val_init_handler): likewise + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): likewise + * typecheck/rust-hir-trait-resolve.cc: likewise + * typecheck/rust-hir-type-check-base.cc: likewise + * typecheck/rust-hir-type-check-item.cc: likewise + * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::is_equal): likewise + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::get_param_ty): likewise + (SubstitutionArg::get_param_mapping): likewise + (SubstitutionRef::prepare_higher_ranked_bounds): likewise + (SubstitutionRef::monomorphize): likewise + * typecheck/rust-tyty-subst.h (class BaseGeneric): new generic base + * typecheck/rust-tyty.cc (VariantDef::clone): likewise + (VariantDef::monomorphized_clone): refactor + (ADTType::is_equal): likewise + (FnType::is_equal): likewise + (ParamType::ParamType): likewise + * typecheck/rust-tyty.h (class ParamType): likewise + (class BaseGeneric): new base class impl + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty.cc (ADTType::is_equal): let param::is_eq do this + (FnType::is_equal): remove whitespace + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-base.cc: check for type param + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::SubstitutionParamMapping): + return HIR::GenericParam base class + (SubstitutionParamMapping::get_generic_param): likewise + (SubstitutionParamMapping::get_type_representation): new helper + (SubstitutionParamMapping::param_has_default_ty): check for param type + (SubstitutionParamMapping::get_default_ty): likewise + * typecheck/rust-tyty-subst.h: get the locus from the subst HIR::GenericParam now + * typecheck/rust-tyty-variance-analysis.cc (GenericTyPerCrateCtx::debug_print_solutions): + likwise + (GenericTyVisitorCtx::process_type): likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): check for ADTType instead of assert + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * checks/lints/rust-lint-unused-var.cc (check_decl): + Do not warn about unused `self` parameter. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: + * ast/rust-expression-yeast.cc (ExpressionYeast::dispatch_loops): Call DesugarWhileLet. + * ast/rust-desugar-while-let.cc: New file. + * ast/rust-desugar-while-let.h: New file. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-ast.cc (AttrInputMacro::operator=): Add return type. + * ast/rust-expr.h: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-desugar-for-loops.cc: Remove functions implemented in AST::Builder. + * ast/rust-desugar-for-loops.h: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-base.cc: Add rust_unreachable() when lowering desugared exprs. + * hir/rust-ast-lower-base.h: Mention this. + * hir/rust-ast-lower-block.h: Remove existing definitions. + * hir/rust-ast-lower-expr.cc: Likewise. + * hir/rust-ast-lower-expr.h: Likewise. + * hir/rust-ast-lower.cc: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-desugar-question-mark.cc (DesugarQuestionMark::go): Add assertion for the + expr's type. + * ast/rust-desugar-try-block.cc (DesugarTryBlock::go): Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-desugar-for-loops.h: Adapt API and remove visitor. + * ast/rust-desugar-for-loops.cc: Likewise. + * ast/rust-expression-yeast.cc: Call DesugarForLoop. + * ast/rust-expression-yeast.h: Declare dispatch_loops function. + * rust-session-manager.cc (Session::expansion): Do not call for-loop desugar. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/tree/rust-hir-expr.h (class OffsetOf): New. + * hir/tree/rust-hir-expr.cc: Define its methods. + * hir/tree/rust-hir-expr-abstract.h: Add ExprType::OffsetOf. + * hir/tree/rust-hir-full-decls.h (class OffsetOf): Declare it. + * backend/rust-compile-block.h: Add handling for OffsetOf. + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + * backend/rust-compile-expr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.h (RUST_BIR_BUILDER_EXPR_H): Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. + * checks/errors/borrowck/rust-function-collector.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): Likewise. + * checks/errors/privacy/rust-privacy-reporter.h (RUST_PRIVACY_REPORTER_H): Likewise. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Likewise. + * checks/errors/rust-const-checker.h: Likewise. + * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit): Likewise. + * checks/errors/rust-hir-pattern-analysis.h: Likewise. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Likewise. + * checks/errors/rust-unsafe-checker.h: Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + * hir/rust-hir-dump.cc (Dump::visit): Likewise. + * hir/rust-hir-dump.h: Likewise. + * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk): Likewise. + * hir/tree/rust-hir-visitor.h: Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + * typecheck/rust-hir-type-check-expr.h (RUST_HIR_TYPE_CHECK_EXPR): Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile the offset_of handler. + * lang.opt: Add -frust-assume-builtin-offset-of option. + * ast/rust-ast.h: Add has_str() for const_TokenPtr. + * expand/rust-macro-builtins.cc: Map offset_of as builtin. + * expand/rust-macro-builtins.h: Declare it. + * expand/rust-macro-expand.cc (MacroExpander::expand_invoc): Add hack for calling builtin + offset_of!(). + * resolve/rust-early-name-resolver-2.0.cc (Early::visit): Likewise. + * expand/rust-macro-builtins-offset-of.cc: New file. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Add OffsetOf expression kind. + * ast/rust-builtin-ast-nodes.h (class OffsetOf): Add node. + * ast/rust-ast.cc: Define it. + * ast/rust-ast-collector.cc: Add visitor for OffsetOf. + * ast/rust-ast-collector.h: Likewise. + * ast/rust-ast-visitor.cc: Likewise. + * ast/rust-ast-visitor.h: Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Likewise. + * hir/rust-ast-lower-base.h: Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + * hir/rust-ast-lower-expr.h: Likewise. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Likewise. + * resolve/rust-ast-resolve-base.h: Likewise. + * resolve/rust-early-name-resolver-2.0.cc: Likewise. + * expand/rust-derive.h: + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust-diagnostics.h (struct Error): Add disambiguation. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-macro-builtins-asm.cc (parse_format_strings): Emit an + error when expecting a comma. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * checks/errors/borrowck/rust-bir-fact-collector.h: Remove spurious + comment. + * checks/errors/rust-feature.cc: Likewise. + * util/optional.h: Likewise. + * expand/rust-token-tree-desugar.cc (TokenTreeDesugar::visit): Remove + semicolons on namespace. + * expand/rust-token-tree-desugar.h: Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * typecheck/rust-hir-type-check-base.cc + (TypeCheckBase::TypeCheckBase): Remove initialization of + resolver field. + * typecheck/rust-hir-type-check-base.h + (TypeCheckBase::resolver): Remove field. + * typecheck/rust-hir-trait-resolve.cc: Remove "options.h" + include. + (TraitResolver::resolve_path_to_trait): Assume name resolution + 2.0 is always enabled. + * typecheck/rust-hir-type-check-enumitem.cc: Remove "options.h" + include. + (TypeCheckEnumItem::visit): Assume name resolution 2.0 is always + enabled. + * typecheck/rust-hir-type-check-expr.cc: Remove "options.h" + include. + (TypeCheckExpr::visit): Assume name resolution 2.0 is always + enabled. + (TypeCheckExpr::resolve_operator_overload): Likewise. + (TypeCheckExpr::resolve_fn_trait_call): Likewise. + * typecheck/rust-hir-type-check-implitem.cc: Remove "options.h" + include. + (TypeCheckImplItem::visit): Assume name resolution 2.0 is always + enabled. + * typecheck/rust-hir-type-check-item.cc: Remove "options.h" + include. + (TypeCheckItem::visit): Assume name resolution 2.0 is always + enabled. + * typecheck/rust-hir-type-check-path.cc (TypeCheckExpr::visit): + Likewise. + (TypeCheckExpr::resolve_root_path): Likewise. + (TypeCheckExpr::resolve_segments): Likewise. + * typecheck/rust-hir-type-check-pattern.cc: Remove "options.h" + include. + (TypeCheckPattern::visit): Assume name resolution 2.0 is always + enabled. + * typecheck/rust-hir-type-check-type.cc + (TypeCheckType::resolve_root_path): Likewise. + (ResolveWhereClauseItem::visit): Likewise. + * typecheck/rust-hir-type-check.cc: Remove "options.h" include. + (TraitItemReference::get_type_from_fn): Assume name resolution + 2.0 is always enabled. + * typecheck/rust-type-util.cc (query_type): Likewise. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * backend/rust-compile-asm.cc (get_out_expr): Return valid output from + an operand. + (CompileAsm::asm_construct_outputs): Handle every output + (get_in_expr): Return valid input from an operand. + (CompileAsm::asm_construct_inputs): Handle every input + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-macro-builtins-asm.cc (parse_reg_operand_inout): Parse + expressions and build split in out. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * hir/rust-hir-dump.cc (Dump::visit): Dump inline assembly fields + * hir/tree/rust-hir-expr.h: Add non const getter and avoid operand copy + from getters. + * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk): Use non const + reference. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * expand/rust-macro-builtins-asm.cc (expand_inline_asm_strings): Handle + transformation for indexed positional arguments. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * rust-backend.h: New slice_index_expression function. + * rust-gcc.cc: Implementation of slice_index_expression to generate tree node for + accessing slice elements. + * backend/rust-compile-pattern.cc: Implement SlicePattern check expression & binding + compilation against SliceType scrutinee. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit(SlicePattern)): + Add new type check case for SliceType wrapped in ReferenceType. + * backend/rust-compile-pattern.cc: Adjusted the asserts accordingly for + CompilePatternCheckExpr(SlicePattern) & CompilePatternBindings(SlicePattern). + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile it. + * ast/rust-expression-yeast.cc (ExpressionYeast::dispatch): Dispatch to try-block + desugar. + * ast/rust-desugar-try-block.cc: New file. + * ast/rust-desugar-try-block.h: New file. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Add the new variant. + * ast/rust-expr.h: Use it for TryExpr class. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Add + visitor for IfLetExprConseqElse. + * resolve/rust-default-resolver.h (DefaultResolver::visit): + Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit a block's loop label if it + exists. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile it. + * rust-session-manager.cc: Call the expression desugar dispatcher. + * ast/rust-desugar-question-mark.cc: Rework class API. + * ast/rust-desugar-question-mark.h: Likewise. + * ast/rust-expression-yeast.cc: New file. + * ast/rust-expression-yeast.h: New file. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-expr.h: Fix formatting. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Handle defered consts. + * hir/tree/rust-hir-expr.cc (AnonConst::AnonConst): Likewise. + (AnonConst::operator=): Likewise. + * hir/tree/rust-hir-expr.h: Likewise. + * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor::walk): Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-expr.h: Add handling for deferred consts. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast.cc (AnonConst::as_string): Likewise. + (ArrayType::as_string): Likewise. + * ast/rust-type.h (class ArrayType): Use AnonConst for sizes. + * parse/rust-parse-impl.h (Parser::parse_anon_const): New function. + (Parser::parse_slice_or_array_type): Call it. + * parse/rust-parse.h: Declare it. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-early-name-resolver-2.0.cc (Early::resolve_glob_import): Adapt for enums. + (Early::finalize_glob_import): Likewise. + * resolve/rust-early-name-resolver-2.0.h: Likewise. + * resolve/rust-finalize-imports-2.0.cc (GlobbingVisitor::go): Likewise. + (GlobbingVisitor::visit_module_container): New function. + (GlobbingVisitor::visit_enum_container): New function. + * resolve/rust-finalize-imports-2.0.h: Declare them. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): Insert enums as potential + containers. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-hir-map.cc (Mappings::insert_ast_module): Rename to... + (Mappings::insert_glob_container): ...this. + (Mappings::lookup_ast_module): Rename to... + (Mappings::lookup_glob_container): ...this. + * util/rust-hir-map.h: Change declarations. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-cfg-strip.cc (CfgStrip::visit): Load unloaded + modules. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): + Assume modules have been loaded by CfgStrip. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-expand-visitor.cc + (ExpandVisitor::expand_inner_items): Adjust call to + expand_macro_children. + (ExpandVisitor::expand_inner_stmts): Likewise. + (ExpandVisitor::visit): Likewise. + * expand/rust-expand-visitor.h + (ExpandVisitor::expand_macro_children): Take a pointer to member + function instead of a std::function. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-resolve-path.cc (HIRCompileBase::query_compile): do another lookup + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast.cc: Include "rust-macro-invoc-lexer.h". + (AttributeParser::~AttributeParser): Move function definition + here. + (AttributeParser::AttributeParser): Likewise and adjust member + initialization. + (AttributeParser::parse_meta_item_inner): Handle changes to + peek_token. + (AttributeParser::parse_literal): Likewise. + (AttributeParser::parse_simple_path_segment): Likewise. + (AttributeParser::parse_meta_item_seq): Handle changes to + AttributeParser fields. + (AttributeParser::peek_token): Move function definition here and + wrap MacroInvocLexer. + (AttributeParser::skip_token): Likewise. + * ast/rust-macro.h (class MacroInvocLexer): Forward declare. + (class Parser): Likewise. + (AttributeParser::token_stream): Remove field. + (AttributeParser::stream_pos): Likewise. + (AttributeParser::lexer): New field. + (AttributeParser::parser): Likewise. + (AttributeParser::AttributeParser): Move definition to + "rust-ast.cc". + (AttributeParser::~AttributeParser): Likewise. + (AttributeParser::peek_token): Likewise. + (AttributeParser::skip_token): Likewise. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-resolve-path.cc (ResolvePathRef::resolve): return error_mark_node + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * hir/tree/rust-hir-expr.cc (OperatorExprMeta::OperatorExprMeta): track the rhs + * hir/tree/rust-hir-expr.h: likewise + * hir/tree/rust-hir-path.h: get rid of old comments + * typecheck/rust-hir-trait-reference.cc (TraitReference::get_trait_substs): return + references instead of copy + * typecheck/rust-hir-trait-reference.h: update header + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::ResolveOpOverload): write ambigious + operator overloads to a table and try to resolve it at the end + * typecheck/rust-hir-type-check-expr.h: new static helper + * typecheck/rust-hir-type-check.h (struct DeferredOpOverload): new model to defer resolution + * typecheck/rust-typecheck-context.cc (TypeCheckContext::lookup_operator_overload): new + (TypeCheckContext::compute_ambigious_op_overload): likewise + (TypeCheckContext::compute_inference_variables): likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc: check the canonical path + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * parse/rust-parse-impl.h (Parser::parse_simple_path): Be more + careful about skipping SCOPE_RESOLUTION tokens. + (Parser::parse_simple_path_segment): Allow parsing from a + starting offset. + (Parser::parse_use_tree): Handle a non-skipped SCOPE_RESOLUTION + token. + * parse/rust-parse.h (Parser::parse_simple_path_segment): Add + parameter for parsing from a starting offset. + +2025-08-05 lishin <lishin1008@gmail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): Add a catch for const/static. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * rust-backend.h: New size_constant_expression function. + * rust-gcc.cc: Implementation of size_constant_expression function to generate tree node + for array access. + * backend/rust-compile-pattern.h: Remove empty visits for SlicePattern. + * backend/rust-compile-pattern.cc: Implement SlicePattern check expression & binding + compilation against ArrayType scrutinee. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc(TypeCheckPattern::visit(SlicePattern)): + Implement size checking for SlicePattern when type checking against array parent + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * util/rust-attribute-values.h: Add declarations for them. + * util/rust-attributes.cc: Add definitions. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::visit): fix typo + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-casts.cc (TypeCastRules::resolve): optional emit_error flag + (TypeCastRules::check): try the simple cast rules then fallback to coercions + (TypeCastRules::check_ptr_ptr_cast): ensure the underlying's + (TypeCastRules::emit_cast_error): make this a static helper + * typecheck/rust-casts.h: new emit_error prototype + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Check for a label + before visiting it. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): track is super trait + * typecheck/rust-hir-type-bounds.h: refactor bounds scan + * typecheck/rust-hir-type-check-base.h: track from super trait + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): likewise + * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::is_bound_satisfied_for_type): refactor + (TypeBoundsProbe::scan): likewise + (TypeBoundPredicate::apply_generic_arguments): likewise + * typecheck/rust-tyty-subst.cc: optional bounds checking on parm subst + * typecheck/rust-tyty-subst.h: likewise + * typecheck/rust-tyty.h: likewise + +2025-08-05 Marc Poulhiès <dkm@kataplop.net> + + * checks/errors/borrowck/rust-bir-place.h (LoanId::value): Make + it size_t to match Loan's base type. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc(TypeCheckPattern::visit(LiteralPattern)): + Check LiteralPattern's type against its parent. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit(SlicePattern)): + Implement initial type checking for SlicePattern. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): check for missing borrow + * ast/rust-expr.h: add helper + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-base.cc (HIRCompileBase::query_compile_const_expr): new wrapper + * backend/rust-compile-base.h: add prototype + * backend/rust-compile-context.cc (Context::get): singleton helper + * backend/rust-compile-context.h: likewise + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): handle infer's that can default + * rust-session-manager.cc (Session::compile_crate): create the gcc context earlier for tychk + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::resolve_literal): const fold it + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): likewise + * typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit): likewise + * typecheck/rust-tyty.cc (BaseType::monomorphized_clone): fix constructor call + (ArrayType::as_string): print capacity + (ArrayType::clone): fix constructor call + * typecheck/rust-tyty.h: track capacity + * typecheck/rust-unify.cc (UnifyRules::expect_array): check the capacities + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): New visitor. + * resolve/rust-late-name-resolver-2.0.h: Declare it. + * resolve/rust-name-resolution-context.h (enum class): New binding context. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Check that the WhileLet has a label + before visiting it. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Add visitor + for TryExpr. + * ast/rust-ast-collector.h (TokenCollector::visit): Likewise. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast-visitor.h (ASTVisitor::visit): Likewise. + (DefaultASTVisitor::visit): Likewise. + * expand/rust-derive.h (DeriveVisitor::visit): Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Likewise. + * hir/rust-ast-lower-base.h (ASTLoweringBase::visit): Likewise. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): + Likewise. + * resolve/rust-ast-resolve-base.h (ResolverBase::visit): + Likewise. + * ast/rust-ast-full-decls.h (class TryExpr): New forward class + declaration. + * ast/rust-ast.cc (TryExpr::as_string): New function. + (TryExpr::accept_vis): Likewise. + * ast/rust-expr.h (class TryExpr): New class. + * parse/rust-parse.h (Parser::parse_try_expr): New function. + * parse/rust-parse-impl.h (Parser::parse_try_expr): Likewise. + (Parser::null_denotation_not_path): Use parse_try_expr to parse + try expressions. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * expand/rust-macro-builtins-format-args.cc + (format_args_parse_arguments): Accept a RAW_STRING_LITERAL token + as the first argument. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * parse/rust-parse-impl.h: Add enum prefix. + * parse/rust-parse.h (enum ParseSelfError): Change from enum... + (enum class): To enum class. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Replace + usages of reinterpret_cast with static_cast. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove + override for StructStruct visitor. + * resolve/rust-late-name-resolver-2.0.h (Late::visit): Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-context.cc (Context::Context): Remove + initialization of resolver field. + * backend/rust-compile-context.h (Context::get_resolver): Remove + function. + (Context::resolver): Remove field. + * backend/rust-compile-expr.cc (CompileExpr::visit): Assume name + resolution 2.0 is always enabled. + (CompileExpr::generate_closure_function): Likewise. + * backend/rust-compile-implitem.cc (CompileTraitItem::visit): + Likewise. + * backend/rust-compile-item.cc (CompileItem::visit): Likewise. + * backend/rust-compile-resolve-path.cc + (ResolvePathRef::resolve): Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * lang.opt (frust-name-resolution-2.0): Enable by default. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * backend/rust-compile-pattern.cc (CompilePatternCheckExpr::visit(TuplePattern)): + Implement check expression compilation for TuplePatternItems::RANGED. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc (visit(TuplePattern)): Fix + incorrect logic for field size checking. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc: Remove extra include, fix new formatting. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h (reconstruct_vec): Pre-allocate size of vector. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Remove object file for ASTTypeBuilder. + * ast/rust-ast-builder.h: Remove function. + * ast/rust-ast-builder.cc (Builder::new_type): Likewise. + (Builder::new_const_param): Use reconstruct_type() instead. + (Builder::new_generic_args): Likewise. + * expand/rust-derive-default.cc (DeriveDefault::visit_struct): Likewise. + (DeriveDefault::visit_tuple): Likewise. + * expand/rust-derive-eq.cc (DeriveEq::visit_tuple): Likewise. + (DeriveEq::visit_struct): Likewise. + (DeriveEq::visit_enum): Likewise. + (DeriveEq::visit_union): Likewise. + * ast/rust-ast-builder-type.cc: Removed. + * ast/rust-ast-builder-type.h: Removed. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h: Add reconstruct() and reconstruct_impl() for Type nodes. + * ast/rust-type.h: Implement them. + * ast/rust-macro.h: Likewise. + * ast/rust-path.h: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast.h (reconstruct): New function for calling the `reconstruct_*_impl` method + and asserting that the new NodeId is different, and then wrap it in a unique_ptr<T>. + (reconstruct_vec): Likewise, but for vectors of unique_ptr<T> + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx (ForeverStack::resolve_path): + Resolve final segments which point to modules. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): + Avoid inserting module names into ribs in the type namespace. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (visit_identifier_as_pattern): Handle is_ref and is_mut. + (Late::visit): Likewise. + * resolve/rust-name-resolution-context.cc + (BindingLayer::insert_ident): Likewise. + (BindingLayer::bind_test): Handle changes to BindingLayer + fields. + (BindingLayer::merge): Likewise and emit more error messages. + * resolve/rust-name-resolution-context.h + (struct IdentifierMode): New. + (Binding::has_expected_bindings): New field. + (Binding::set): Rename field to... + (Binding::idents): ...here and convert from a set to a map. + (Binding::Binding): Initialize has_expected_bindings. + (BindingLayer::insert_ident): Adjust parameters. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * ast/rust-expr.h: Add getter to locus field. + * ast/rust-pattern.h (tokenid_to_rangekind): Likewise. + * hir/tree/rust-hir-item.h: Likewise. + * hir/tree/rust-hir-visibility.h: Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc + (DefaultResolver::visit_extern_crate): New function. + (DefaultResolver::visit): New visitor function for ExternCrate. + * resolve/rust-default-resolver.h + (DefaultResolver::visit_extern_crate): New function. + (DefaultResolver::visit): New visitor function for ExternCrate. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::visit): + Adjust ExternCrate visitor and rename to... + (TopLevel::visit_extern_crate): ...here. + * resolve/rust-toplevel-name-resolver-2.0.h (TopLevel::visit): + Remove ExternCrate visitor override. + (TopLevel::visit_extern_crate): New function. + * rust-session-manager.cc (Session::load_extern_crate): Only run + name resolution 1.0 if name resolution 2.0 is disabled. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit(TuplePattern)): + Implement type checking for ItemType::RANGED. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust-lang.cc: Move version check from C++11 to C++14. + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * Make-lang.in: Scaffolding new rust-hir-visitor files + * hir/tree/rust-hir-visitor.h (DefaultHIRVisitor): Declare default HIR visitor + * hir/tree/rust-hir-visitor.cc (DefaultHIRVisitor): Define default HIR visitor + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * Make-lang.in (GRS_OBJS): Add rust-ggc.o. + * backend/rust-compile-base.cc + (HIRCompileBase::compile_function): Adjust call to + Backend::function. + (HIRCompileBase::compile_constant_item): Likewise and adjust + initialization of Backend::typed_identifier. + * backend/rust-compile-expr.cc (CompileExpr::visit): Adjust call + to Backend::label. + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): + Adjust initialization of Backend::typed_identifier. + * rust-backend.h: Add includes. + (Backend::GGC::Ident): Use Rust::GGC::Ident. + (struct typed_identifier): Store name as a GGC::Ident rather + than a std::string and adjust constructors. + (named_type): Take GGC::Ident/tl::optional<GGC::Ident> rather + than std::string. + (global_variable): Likewise. + (local_variable): Likewise. + (parameter_variable): Likewise. + (static_chain_variable): Likewise. + (label): Likewise. + (function): Likewise. + * rust-gcc.cc (named_type): Likewise. + (global_variable): Likewise. + (local_variable): Likewise. + (parameter_variable): Likewise. + (static_chain_variable): Likewise. + (label): Likewise. + (function): Likewise. + (function_defer_statement): Adjust call to Backend::label. + (get_identifier_from_string): Remove function. + (fill_in_fields): Handle adjustments to typed_identifier. + * util/rust-ggc.cc: New file. + * util/rust-ggc.h: New file. + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * hir/tree/rust-hir-item.h (SelfParam::get_lifetime): Add getter + for non const lifetime object + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * hir/tree/rust-hir-expr.h (MatchArm::get_outer_attrs): Add getter for outer attributions + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-resolve-path.cc: if this fails fall back to query compile + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-expr.cc (CompileExpr::visit): add const call check + * backend/rust-compile-item.cc (CompileItem::visit): ensure we upfront compile types where + possible + * backend/rust-compile-item.h: update header + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): make parent ctx optional + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * backend/rust-compile-pattern.cc(CompilePatternCheckExpr::visit(TupleStructPattern)): + Fix error thrown when compiling non-enum TupleStructPattern. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): + Call DefaultASTVisitor::visit even on ConstantItem instances + without expressions. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-unify.cc (UnifyRules::expect_fnptr): add unify rules + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-reference.cc (TraitReference::on_resolved): ensure associated + types are done first + * typecheck/rust-hir-type-check-type.cc: Update call site. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty-bounds.cc: Check super traits for type bindings. + * typecheck/rust-tyty.h: Add helper methods for bound checking. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-bounds.h: Rename method. + * typecheck/rust-tyty-bounds.cc: Refactor marker trait assembly + and add proper Fn trait handling for function types. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-dot-operator.cc: Major refactoring and cleanup. + * typecheck/rust-hir-dot-operator.h: Add new helper methods. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-trait-resolve.cc: Add cyclical projection + protection. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check-expr.cc: Look at bounds behind + references. + * typecheck/rust-hir-type-check-expr.h: Add helper method. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust-session-manager.cc (Session::compile_crate): Move + AST desugaring to... + (Session::expansion): ...here and add a final TopLevel pass + afterwards. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): check for has_expr + * hir/rust-hir-dump.cc (Dump::visit): likewise + * hir/tree/rust-hir-item.h: add has_expr helper + * resolve/rust-ast-resolve-item.cc (ResolveItem::visit): check for has_expr + * resolve/rust-ast-resolve-stmt.h: likewise + * typecheck/rust-hir-type-check-stmt.cc (TypeCheckStmt::visit): likewise + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Add + visitor for ExternCrate. + * hir/rust-ast-lower-item.h (ASTLoweringItem::visit): Likewise. + * rust-session-manager.cc (Session::load_extern_crate): Avoid + lowering or type resolving external crates here. + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): + Add visitor for ExternCrate. + * typecheck/rust-hir-type-check-item.h (TypeCheckItem::visit): + Replace empty definition with a declaration. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-tyty.cc (ParamType::handle_substitions): make this consistent + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit(IdentifierPattern)): + Remove redundant subpattern check. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * backend/rust-compile-pattern.cc: Add support for IdentifierPattern's + subpattern under CompilePatternBindings. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * resolve/rust-ast-resolve-pattern.cc: Implement name resolution for + IdentifierPattern's subpattern. + * resolve/rust-late-name-resolver-2.0.cc: Ditto, but for nr2. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * ast/rust-ast-collector.cc: Rename get_pattern_to_bind to get_subpattern + * ast/rust-ast-visitor.cc: Ditto. + * ast/rust-pattern.h: Ditto. + * expand/rust-cfg-strip.cc: Ditto. + * hir/rust-ast-lower-pattern.cc: Ditto. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): + Adjust scoping of trait definitions and their generic + parameters. + * resolve/rust-forever-stack.hxx (ForeverStack::get): Prevent + lookups inside TraitOrImpl ribs. + (ForeverStack::resolve_segments): Prevent lookups of the first + segment inside TraitOrImpl ribs. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * hir/rust-hir-dump.cc: Change pattern dumps to use visit_field. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive.cc: Fix formatting after fork update. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-cmp-common.cc (EnumMatchBuilder::tuple): Create two different + variant paths. + (EnumMatchBuilder::strukt): Likewise. + * expand/rust-derive-cmp-common.h: Change API. + * expand/rust-derive-ord.cc (DeriveOrd::visit_enum): Use new EnumMatchBuilder API. + * expand/rust-derive-partial-eq.cc (DerivePartialEq::visit_enum): Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc (DeriveOrd::make_cmp_arms): Use new make_equal function. + (DeriveOrd::make_equal): New function. + (DeriveOrd::recursive_match): Handle the unit struct/tuple case. + * expand/rust-derive-ord.h: Declare make_equal. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc (DeriveOrd::cmp_call): Use references. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc (DeriveOrd::make_cmp_arms): Fix condition. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc: Finish implementation for enums. + * expand/rust-derive-ord.h: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-partial-eq.cc (DerivePartialEq::eq_fn): Change signature. + (DerivePartialEq::visit_tuple): Use new eq_fn API. + (DerivePartialEq::visit_struct): Likewise. + (DerivePartialEq::visit_enum): Implement proper discriminant comparison. + * expand/rust-derive-partial-eq.h: Change eq_fn signature. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-cmp-common.h (class EnumMatchBuilder): New helper class. + * expand/rust-derive-cmp-common.cc (EnumMatchBuilder::tuple): New function. + (EnumMatchBuilder::strukt): New function. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.h: Put `loc` member in public. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc (DeriveOrd::cmp_call): New function. + (DeriveOrd::recursive_match): Use it. + (DeriveOrd::visit_enum): Likewise. + * expand/rust-derive-ord.h: Declare it. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-hash.cc (DeriveHash::visit_enum): Use new APIs. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::discriminant_value): New function. + * ast/rust-ast-builder.h: Declare it. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc (is_last): Remove. + (DeriveOrd::visit_tuple): Fix implementation. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-cmp-common.cc (SelfOther::indexes): Fix formatting. + (SelfOther::fields): Make iterator const. + * expand/rust-derive-cmp-common.h (struct SelfOther): New declaration for indexes. + * expand/rust-derive-partial-eq.cc (DerivePartialEq::visit_tuple): Use the new API. + (DerivePartialEq::visit_struct): Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-ord.cc (DeriveOrd::make_cmp_arms): New function. + (is_last): Likewise. + (recursive_match): Likewise. + (DeriveOrd::recursive_match): Likewise. + (DeriveOrd::visit_struct): Add proper implementation. + (DeriveOrd::visit_union): Likewise. + * expand/rust-derive-ord.h: Declare these new functions. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-partial-eq.cc (DerivePartialEq::tuple_indexes): Remove. + (DerivePartialEq::field_acccesses): Remove. + (DerivePartialEq::visit_tuple): Use new API. + (DerivePartialEq::visit_struct): Likewise. + * expand/rust-derive-partial-eq.h: Remove declarations. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-cmp-common.cc: New file. + * expand/rust-derive-cmp-common.h: New file. + * Make-lang.in: Compile them. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::block): New function. + (Builder::match_case): Likewise. + * ast/rust-ast-builder.h: Declare them. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::new_const_param): New function. + * ast/rust-ast-builder.h (vec): New function for creating 3 elts vector. + * expand/rust-derive.cc: Use the new_const_param builder. + * ast/rust-path.h: Add get_default_value() method. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * Make-lang.in: Compile it. + * expand/rust-derive.cc (DeriveVisitor::derive): Call them. + * expand/rust-derive-ord.cc: New file. + * expand/rust-derive-ord.h: New file. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-clone.h: Add missing override qualifiers to DeriveVisitor methods. + * expand/rust-derive-copy.h: Likewise. + * expand/rust-derive-eq.h: Likewise. + * expand/rust-derive-hash.h: Likewise. + * expand/rust-derive-partial-eq.h: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-rib.h: Add missing switch cases. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-type-util.cc (query_type): early return. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): reuse GCC's build_array_type + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc + (visit_identifier_as_pattern): Make sure to map identifiers + inside or-bindings to prior identifiers. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * ast/rust-ast-collector.cc: Rename to_bind to subpattern. + * ast/rust-ast-visitor.cc: Ditto. + * ast/rust-pattern.cc: Ditto. + * ast/rust-pattern.h: Ditto. + * backend/rust-compile-pattern.cc: Ditto. + * expand/rust-cfg-strip.cc: Ditto. + * hir/rust-ast-lower-pattern.cc: Ditto. + * hir/rust-hir-dump.cc: Ditto. + * hir/tree/rust-hir-pattern.h: Ditto. + * hir/tree/rust-hir.cc: Ditto. + * typecheck/rust-hir-type-check-pattern.cc: Ditto. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * backend/rust-compile-pattern.cc: Add CheckExpr compilation for + IdentifierPattern with subpattern. + * backend/rust-compile-pattern.h: Modify IdentifierPattern's + visit func to support the above. + * typecheck/rust-hir-type-check-pattern.cc: Add typechecking + support for the changes above. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc + (DefaultResolver::visit_closure_params): New member function + definition. + (DefaultResolver::visit): New visiting function definition for + ClosureExpr called from visiting functions for ClosureExprInner + and ClosureExprInnerTyped. + * resolve/rust-default-resolver.h + (DefaultResolver::visit_closure_params): New member function + declaration. + (DefaultResolver::visit): New visiting function declaration for + ClosureExpr. + * resolve/rust-late-name-resolver-2.0.cc (add_captures): Remove + function. + (Late::visit): New visiting function definition for ClosureExpr, + remove visiting function definitions for ClosureExprInner and + ClosureExprInnerTyped. + (Late::visit_closure_params): New member function definition. + * resolve/rust-late-name-resolver-2.0.h (Late::visit): New + visiting function declaration for ClosureExpr, remove visiting + function declarations for ClosureExprInner and + ClosureExprInnerTyped. + (Late::visit_closure_params): New member function declaration. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.hxx (ForeverStack::resolve_path): + Handle single segment paths "crate", "self", and "super". + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Use + visit_identifier_as_pattern to handle IdentifierPattern and + StructPatternFieldIdent. + (visit_identifier_as_pattern): New function. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-expr.h (ClosureExpr::get_definition_expr): New + virtual member function. + (ClosureExprInner::get_definition_expr): Add override specifier. + (ClosureExprInnerTyped::get_definition_block): Rename to... + (ClosureExprInnerTyped::get_definition_expr): ...here and add + override specifier. + * ast/rust-ast-collector.cc (TokenCollector::visit): Handle + rename of ClosureExprInnerTyped::get_definition_block to + ClosureExprInnerTyped::get_definition_expr. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * expand/rust-cfg-strip.cc (CfgStrip::visit): Likewise. + * expand/rust-expand-visitor.cc (ExpandVisitor::visit): + Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): + Likewise. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): + Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-base.cc + (HIRCompileBase::compile_function): Since canonical paths + returned from nr2.0 now include the crate name, avoid prepending + the crate name again. + * backend/rust-compile-implitem.cc (CompileTraitItem::visit): + Use NameResolutionContext::to_canonical_path instead of + ForeverStack::to_canonical_path. + * backend/rust-compile-item.cc (CompileItem::visit): Likewise. + * typecheck/rust-hir-type-check-enumitem.cc + (TypeCheckEnumItem::visit): Likewise. + * typecheck/rust-hir-type-check-implitem.cc + (TypeCheckImplItem::visit): Likewise. + * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): + Likewise. + * typecheck/rust-hir-type-check.cc + (TraitItemReference::get_type_from_fn): Likewise. + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Add + Crate and EnumItem instance visitors, handle canonical path + context scoping. + * resolve/rust-default-resolver.h (DefaultResolver::visit): Add + Crate and EnumItem instance visitors. + * resolve/rust-early-name-resolver-2.0.cc (Early::go): Visit + instances of Crate using the virtual member function visit. + * resolve/rust-forever-stack.h + (ForeverStack::to_canonical_path): Remove function declaration. + * resolve/rust-forever-stack.hxx + (ForeverStack::to_canonical_path): Remove function definition. + * resolve/rust-late-name-resolver-2.0.cc (Late::go): Visit + instances of Crate using the virtual member function visit. + * resolve/rust-name-resolution-context.cc + (CanonicalPathRecordCrateRoot::as_path): New function definition. + (CanonicalPathRecordNormal::as_path): Likewise. + (CanonicalPathRecordLookup::as_path): Likewise. + (CanonicalPathRecordImpl::as_path): Likewise. + (CanonicalPathRecordTraitImpl::as_path): Likewise. + (NameResolutionContext::NameResolutionContext): Initialize + member variable canonical_ctx. + * resolve/rust-name-resolution-context.h: Include "rust-item.h". + (class NameResolutionContext): Forward declare class. + (class CanonicalPathRecord): New class. + (class CanonicalPathRecordWithParent): Likewise. + (class CanonicalPathRecordCrateRoot): Likewise. + (class CanonicalPathRecordNormal): Likewise. + (class CanonicalPathRecordLookup): Likewise. + (class CanonicalPathRecordImpl): Likewise. + (class CanonicalPathRecordTraitImpl): Likewise. + (class CanonicalPathCtx): Likewise. + (NameResolutionContext::canonical_ctx): New member variable. + (NameResolutionContext::to_canonical_path): New member function. + * resolve/rust-toplevel-name-resolver-2.0.cc (TopLevel::go): + Visit instances of Crate with the virtual member function visit. + (TopLevel::visit): Handle canonical path context scoping for + external crates, use DefaultResolver::visit when visiting + instances of StructStruct. + * util/rust-canonical-path.h (CanonicalPath::new_seg): Take path + parameter by-value, as a duplicate instance will be constructed + regardless. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * hir/rust-ast-lower-pattern.cc: Lower of IdentifierPattern's to_bind to HIR. + * hir/rust-hir-dump.cc: Update IdentifierPattern's dump to properly show to_bind's full + full properties. + +2025-08-05 Vishruth-Thimmaiah <vishruththimmaiah@gmail.com> + + * lex/rust-lex.cc (Lexer::parse_raw_byte_string): + Fix infinite looping when a raw byte string is not terminated. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc (DefaultResolver::visit): Use + visit_impl_type to visit the self types of impl blocks. + * resolve/rust-default-resolver.h + (DefaultResolver::visit_impl_type): New member function + declaration. + * resolve/rust-late-name-resolver-2.0.cc (Late::Late): + Initialize member variable block_big_self. + (Late::visit_impl_type): New member function definition. + (Late::visit): Check for Self while inside impl block self + types. + * resolve/rust-late-name-resolver-2.0.h (Late::visit_impl_type): + New member function. + (Late::block_big_self): New member variable. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-forever-stack.h + (enum ResolutionMode): New. + (ForeverStack::get): Add a private overload that takes a + starting node as a parameter. + (ForeverStack::resolve_path): Replace boolean parameter + has_opening_scope_resolution with ResolutionMode parameter mode. + * resolve/rust-forever-stack.hxx + (ForeverStack::resolve_path): Likewise. + (ForeverStack::get): Add a private overload that takes a + starting node as a parameter. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Add Visibility visitor. + * resolve/rust-late-name-resolver-2.0.h + (Late::visit): Likewise. + * resolve/rust-name-resolution-context.h + (NameResolutionContext::resolve_path): Rework overloading a bit + and accept ResolutionMode parameter. + +2025-08-05 Vishruth-Thimmaiah <vishruththimmaiah@gmail.com> + + * parse/rust-parse.cc (Rust::extract_module_path): + Handle empty or whitespace-only path attributes. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Handle + changed type of ConstantItem::identifier. + * ast/rust-ast.cc (ConstantItem::as_string): Likewise. + * ast/rust-ast.h (operator const std::string &): New member + function. + * ast/rust-item.h (ConstantItem::identifier): Change type from + std::string to Identifier. + (ConstantItem::ConstantItem): Handle changed type of identifier + field. + (ConstantItem::is_unnamed): Likewise. + (ConstantItem::get_identifier): Likewise. + * hir/rust-ast-lower-extern.h (ASTLoweringExternItem::visit): + Avoid discarding location of wildcard patterns. + * lex/rust-token.cc: Include "rust-ast.h". + (Token::make_identifier): Add overload accepting an Identifier + instance. + * lex/rust-token.h (class Identifier): Add forward declaration + in order to... + (Token::make_identifier): ...declare an overload for this static + member function. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * hir/tree/rust-hir-expr.h: New classes. + * hir/tree/rust-hir-full-decls.h: Likewise. + * hir/tree/rust-hir.cc: Handle AnonConst and ConstBlock. + * backend/rust-compile-block.cc: Likewise. + * backend/rust-compile-block.h: Likewise. + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + * backend/rust-compile-expr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit): Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Likewise. + * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise. + * checks/errors/borrowck/rust-function-collector.h: Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit): Likewise. + * checks/errors/privacy/rust-privacy-reporter.h: Likewise. + * checks/errors/rust-const-checker.cc (ConstChecker::visit): Likewise. + * checks/errors/rust-const-checker.h: Likewise. + * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit): Likewise. + * checks/errors/rust-hir-pattern-analysis.h: Likewise. + * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Likewise. + * checks/errors/rust-unsafe-checker.h: Likewise. + * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Likewise. + (translate_operand_out): Likewise. + (translate_operand_inout): Likewise. + (translate_operand_const): Likewise. + * hir/rust-ast-lower-expr.h: Likewise. + * hir/rust-hir-dump.cc (Dump::visit): Likewise. + * hir/rust-hir-dump.h: Likewise. + * hir/tree/rust-hir-expr-abstract.h: Likewise. + * hir/tree/rust-hir-expr.cc (AnonConst::AnonConst): Likewise. + (AnonConst::operator=): Likewise. + (ConstBlock::ConstBlock): Likewise. + (ConstBlock::operator=): Likewise. + * hir/tree/rust-hir-visitor.h: + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + (typecheck_inline_asm_operand): Likewise. + * typecheck/rust-hir-type-check-expr.h: Likewise. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * parse/rust-parse-impl.h (Parser::parse_const_block_expr): New function. + * parse/rust-parse.h: Declare it. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-expr.h: Declare AnonConst and ConstBlock and use them. + * ast/rust-ast-full-decls.h: Likewise. + * ast/rust-ast.cc: Add implementation for AnonConst and ConstBlock. + * ast/rust-ast.h: Likewise. + * ast/rust-ast-collector.cc (TokenCollector::visit): Likewise. + * ast/rust-ast-collector.h: Likewise. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast-visitor.h: Likewise. + * expand/rust-derive.h: Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Likewise. + * hir/rust-ast-lower-base.h: Likewise. + * hir/rust-ast-lower-expr.cc (translate_operand_const): Likewise. + * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Likewise. + * resolve/rust-ast-resolve-base.h: Likewise. + * resolve/rust-ast-resolve-expr.h: Likewise. + * resolve/rust-ast-resolve-expr.cc: Likewise. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-coercion.cc (TypeCoercionRules::coerce_unsized): dont emit error here + * typecheck/rust-unify.cc (UnifyRules::resolve_subtype): new helper to handle emit error + (UnifyRules::expect_adt): call resolve_subtype + (UnifyRules::expect_reference): likewise + (UnifyRules::expect_pointer): likewise + (UnifyRules::expect_array): likewise + (UnifyRules::expect_slice): likewise + (UnifyRules::expect_fndef): likewise + (UnifyRules::expect_fnptr): likewise + (UnifyRules::expect_tuple): likewise + (UnifyRules::expect_closure): likewise + (UnifyRules::expect_opaque): likeiwse + * typecheck/rust-unify.h: add new helper to header + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-default-resolver.cc + (DefaultResolver::visit_if_let_patterns): New function + definition. + (DefaultResolver::visit): New IfLetExpr visitor definition. + * resolve/rust-default-resolver.h + (DefaultResolver::visit_if_let_patterns): New function + declaration. + (DefaultResolver::visit): New IfLetExpr visitor declaration. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove + IfLetExpr visitor definition. + (Late::visit_if_let_patterns): New function definition. + * resolve/rust-late-name-resolver-2.0.h (Late::visit): Remove + IfLetExpr visitor declaration. + (Late::visit_if_let_patterns): New function declaration. + * resolve/rust-name-resolution-context.h (BindingSource::IfLet): + New enumerator. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): we need to resolve the + underlying type + * typecheck/rust-substitution-mapper.cc (SubstMapperInternal::visit): just clone + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): + ensure we monomphize to get the underlying + * typecheck/rust-tyty.cc (BaseType::destructure): handle opaque types + (OpaqueType::resolve): this is much simpler now + (OpaqueType::handle_substitions): no longer needed + * typecheck/rust-tyty.h: update header + * typecheck/rust-unify.cc (UnifyRules::expect_opaque): unify rules for opaque + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * backend/rust-compile-type.cc (TyTyResolveCompile::visit): use get_name + * typecheck/rust-tyty.cc (TupleType::get_name): likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::check_base_type_privacy): + no need for unreachable here + * typecheck/rust-unify.cc (UnifyRules::commit): dont clone infer vars + (UnifyRules::expect_inference_variable): likewise + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * typecheck/rust-hir-type-check.h: new function + * typecheck/rust-typecheck-context.cc (TypeCheckContext::compute_inference_variables): + call the new helper + (TypeCheckContext::compute_infer_var): refactored code + +2025-08-05 Tom Schollenberger <tss2344@g.rit.edu> + + * resolve/rust-early-name-resolver-2.0.cc (Early::visit_attributes): rust_assert to if + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * parse/rust-parse-impl.h (Parser::parse_expr_stmt): Avoid + reference binding and remove std::move in return statements. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Only visit the path of an instance + of Visibility if the instance has a path. + * ast/rust-ast.h + (SimplePath::SimplePath): Make sure constructors are explicit. + * resolve/rust-early-name-resolver-2.0.cc + (Early::visit_attributes): Pass entire paths to + NameResolutionContext::resolve_path. + (Early::visit): Likewise and avoid copying a path. + * resolve/rust-forever-stack.hxx + (ForeverStack::resolve_path): Assert that at least one path + segment has been passed in. + +2025-08-05 Marc Poulhiès <dkm@kataplop.net> + + * rust-attribs.cc (handle_hot_attribute): Remove clang-format comment. + +2025-08-05 Marc Poulhiès <dkm@kataplop.net> + + * ast/rust-ast-builder-type.cc (ASTTypeBuilder::visit): Reindent. + * ast/rust-ast-builder.cc (Builder::new_generic_args): Likewise. + * ast/rust-ast-collector.cc (TokenCollector::visit): Likewise. + * ast/rust-ast-dump.h (debug): Likewise. + * ast/rust-ast-formatting.h (indent_spaces): Likewise. + (get_string_in_delims): Likewise. + (get_mode_dump_desc): Likewise. + (append_attributes): Likewise. + (unquote_string): Likewise. + * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Likewise. + * ast/rust-ast.cc (Attribute::get_traits_to_derive): Likewise. + (UseTreeGlob::as_string): Likewise. + (UseTreeList::as_string): Likewise. + (AttributeParser::parse_path_meta_item): Likewise. + (FormatArgs::set_outer_attrs): Likewise. + * ast/rust-ast.h (operator<<): Likewise. + * ast/rust-cond-compilation.h: Likewise. + * ast/rust-desugar-apit.cc: Likewise. + * ast/rust-fmt.h (collect_pieces): Likewise. + (clone_pieces): Likewise. + * ast/rust-pattern.h (tokenid_to_rangekind): Likewise. + * backend/rust-compile-context.cc (Context::type_hasher): Likewise. + * backend/rust-compile-expr.cc (CompileExpr::visit): Likewise. + * backend/rust-compile-intrinsic.cc (get_identifier): Likewise. + (offset_handler): Likewise. + (sizeof_handler): Likewise. + (transmute_handler): Likewise. + (rotate_handler): Likewise. + (wrapping_op_handler_inner): Likewise. + (op_with_overflow_inner): Likewise. + (uninit_handler): Likewise. + (move_val_init_handler): Likewise. + (assume_handler): Likewise. + (discriminant_value_handler): Likewise. + (variant_count_handler): Likewise. + (prefetch_data_handler): Likewise. + (atomic_store_handler_inner): Likewise. + (atomic_load_handler_inner): Likewise. + (unchecked_op_inner): Likewise. + (copy_handler_inner): Likewise. + (expect_handler_inner): Likewise. + (try_handler_inner): Likewise. + * backend/rust-compile-pattern.cc (compile_range_pattern_bound): Likewise. + (CompilePatternCheckExpr::visit): Likewise. + (CompilePatternBindings::visit): Likewise. + (CompilePatternLet::visit): Likewise. + * backend/rust-compile-var-decl.h: Likewise. + * backend/rust-constexpr.cc (verify_constant): Likewise. + (find_array_ctor_elt): Likewise. + (array_index_cmp): Likewise. + (potential_constant_expression_1): Likewise. + (unshare_constructor): Likewise. + (maybe_save_constexpr_fundef): Likewise. + (returns): Likewise. + (breaks): Likewise. + (continues): Likewise. + (switches): Likewise. + (constant_value_1): Likewise. + (decl_constant_value): Likewise. + (non_const_var_error): Likewise. + (eval_constant_expression): Likewise. + (constexpr_fn_retval): Likewise. + (eval_store_expression): Likewise. + (eval_call_expression): Likewise. + (eval_binary_expression): Likewise. + (get_function_named_in_call): Likewise. + (eval_statement_list): Likewise. + (extract_string_elt): Likewise. + (eval_conditional_expression): Likewise. + (eval_bit_field_ref): Likewise. + (eval_loop_expr): Likewise. + (eval_switch_expr): Likewise. + (eval_unary_expression): Likewise. + (get_or_insert_ctor_field): Likewise. + (eval_and_check_array_index): Likewise. + * backend/rust-constexpr.h (maybe_save_constexpr_fundef): Likewise. + * backend/rust-mangle-v0.cc (v0_path): Likewise. + (v0_complex_type_prefix): Likewise. + * backend/rust-mangle.h (legacy_mangle_item): Likewise. + (v0_mangle_item): Likewise. + * backend/rust-tree.cc (convert_to_void): Likewise. + (find_parameter_packs_r): Likewise. + (rs_tree_equal): Likewise. + (publicly_uniquely_derived_p): Likewise. + (instantiation_dependent_expression_p): Likewise. + (type_has_nontrivial_copy_init): Likewise. + (is_normal_capture_proxy): Likewise. + (is_bitfield_expr_with_lowered_type): Likewise. + (undeduced_auto_decl): Likewise. + (require_deduced_type): Likewise. + (gt_pch_nx): Likewise. + (lvalue_kind): Likewise. + * backend/rust-tree.h (LANG_DECL_MIN_CHECK): Likewise. + (LANG_DECL_FN_CHECK): Likewise. + (LANG_DECL_NS_CHECK): Likewise. + (LANG_DECL_PARM_CHECK): Likewise. + (LANG_DECL_DECOMP_CHECK): Likewise. + (resort_type_member_vec): Likewise. + (convert_to_void): Likewise. + (mark_discarded_use): Likewise. + (mark_exp_read): Likewise. + (mark_use): Likewise. + (mark_rvalue_use): Likewise. + (mark_lvalue_use): Likewise. + (mark_lvalue_use_nonread): Likewise. + (convert_from_reference): Likewise. + (maybe_warn_nodiscard): Likewise. + (expr_loc_or_loc): Likewise. + (expr_loc_or_input_loc): Likewise. + (get_fndecl_from_callee): Likewise. + (pointer_offset_expression): Likewise. + (is_empty_class): Likewise. + (is_really_empty_class): Likewise. + (rs_type_quals): Likewise. + (init_modules): Likewise. + (lookup_add): Likewise. + (ovl_make): Likewise. + (struct c_fileinfo): Likewise. + (get_fileinfo): Likewise. + (cxx_make_type): Likewise. + (build_cplus_array_type): Likewise. + (comptypes): Likewise. + (rs_build_qualified_type_real): Likewise. + (vector_targets_convertible_p): Likewise. + (get_class_binding_direct): Likewise. + (lang_check_failed): Likewise. + (check_for_uninitialized_const_var): Likewise. + (cp_fold_maybe_rvalue): Likewise. + (fold_offsetof): Likewise. + (fold_non_dependent_expr): Likewise. + (in_immediate_context): Likewise. + (cxx_mark_addressable): Likewise. + (decl_constant_value): Likewise. + (is_class_type): Likewise. + (fold_builtin_is_pointer_inverconvertible_with_class): Likewise. + (c_common_type_for_mode): Likewise. + (next_common_initial_seqence): Likewise. + (fold_builtin_is_corresponding_member): Likewise. + (maybe_constant_value): Likewise. + (rs_walk_subtrees): Likewise. + (make_tree_vector): Likewise. + (release_tree_vector): Likewise. + (location_of): Likewise. + (maybe_constant_init): Likewise. + (explain_invalid_constexpr_fn): Likewise. + (literal_type_p): Likewise. + (maybe_constexpr_fn): Likewise. + (fold_non_dependent_init): Likewise. + * checks/errors/borrowck/polonius/rust-polonius.h (polonius_run): Likewise. + (FFIVector__new): Likewise. + (FFIVector__new_vec_pair): Likewise. + (FFIVector__new_vec_triple): Likewise. + (FFIVector__push): Likewise. + (FFIVector__push_vec_triple): Likewise. + * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc + (ExprStmtBuilder::visit): Likewise. + * checks/errors/borrowck/rust-bir-builder-pattern.cc + (PatternBindingBuilder::visit): Likewise. + * checks/errors/borrowck/rust-bir-dump.cc (Dump::visit): Likewise. + * checks/errors/borrowck/rust-bir-fact-collector.h (points): Likewise. + * checks/errors/borrowck/rust-bir-place.h: Likewise. + * checks/errors/borrowck/rust-bir-visitor.h: Likewise. + * checks/errors/privacy/rust-privacy-check.cc (saw_errors): Likewise. + * checks/errors/privacy/rust-privacy-ctx.h (rust_privacy_ctx_test): Likewise. + * checks/errors/privacy/rust-privacy-reporter.cc + (PrivacyReporter::check_for_privacy_violation): Likewise. + (PrivacyReporter::check_base_type_privacy): Likewise. + (PrivacyReporter::visit): Likewise. + * checks/errors/privacy/rust-reachability.cc (ReachabilityVisitor::visit): Likewise. + * checks/errors/privacy/rust-visibility-resolver.cc + (VisibilityResolver::resolve_visibility): Likewise. + * checks/errors/rust-hir-pattern-analysis.cc (Constructor::is_covered_by): Likewise. + (PlaceInfo::specialize): Likewise. + (WitnessPat::to_string): Likewise. + (WitnessMatrix::apply_constructor): Likewise. + (lower_pattern): Likewise. + (lower_tuple_pattern): Likewise. + (lower_struct_pattern): Likewise. + * checks/errors/rust-hir-pattern-analysis.h (check_match_usefulness): Likewise. + * expand/rust-cfg-strip.cc (CfgStrip::maybe_strip_generic_args): Likewise. + * expand/rust-derive-eq.cc (DeriveEq::visit_enum): Likewise. + * expand/rust-derive.cc: Likewise. + * expand/rust-expand-format-args.cc (expand_format_args): Likewise. + * expand/rust-expand-visitor.h (is_derive): Likewise. + (is_builtin): Likewise. + * expand/rust-macro-builtins-asm.cc (expand_inline_asm_strings): Likewise. + * expand/rust-macro-builtins-asm.h (parse_asm): Likewise. + (check_identifier): Likewise. + (check_and_set): Likewise. + (parse_label): Likewise. + (parse_llvm_outputs): Likewise. + (parse_llvm_inputs): Likewise. + (parse_llvm_clobbers): Likewise. + (parse_llvm_options): Likewise. + * expand/rust-macro-builtins-helpers.h (make_macro_path_str): Likewise. + (make_token): Likewise. + (make_string): Likewise. + (macro_end_token): Likewise. + (parse_single_string_literal): Likewise. + (source_relative_path): Likewise. + (load_file_bytes): Likewise. + * expand/rust-macro-expand.cc (MacroExpander::match_fragment): Likewise. + (MacroExpander::match_matcher): Likewise. + (MacroExpander::match_n_matches): Likewise. + * expand/rust-macro-substitute-ctx.cc (SubstituteCtx::substitute_token): Likewise. + * expand/rust-proc-macro.h (load_macros): Likewise. + (generate_proc_macro_decls_symbol): Likewise. + * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_generic_args): Likewise. + (ASTLoweringBase::lower_range_pattern_bound): Likewise. + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): Likewise. + * hir/rust-ast-lower-pattern.cc (ASTLoweringPattern::visit): Likewise. + * hir/rust-ast-lower.h (struct_field_name_exists): Likewise. + (translate_visibility): Likewise. + * hir/rust-hir-dump.cc (Dump::visit): Likewise. + * hir/rust-hir-dump.h (debug): Likewise. + * hir/tree/rust-hir.cc (UseTreeGlob::as_string): Likewise. + (UseTreeList::as_string): Likewise. + * lex/rust-lex.cc (Lexer::parse_escape): Likewise. + (Lexer::parse_utf8_escape): Likewise. + * lex/rust-lex.h (rust_input_source_test): Likewise. + * lex/rust-token.cc (RS_TOKEN_KEYWORD_2015): Likewise. + * lex/rust-token.h (get_token_description): Likewise. + (token_id_to_str): Likewise. + (token_id_is_keyword): Likewise. + (token_id_keyword_string): Likewise. + (get_type_hint_string): Likewise. + (nfc_normalize_token_string): Likewise. + * metadata/rust-export-metadata.cc (PublicInterface::write_to_path): Likewise. + * metadata/rust-import-archive.cc: Likewise. + * metadata/rust-imports.h (add_search_path): Likewise. + * parse/rust-cfg-parser.h (parse_cfg_option): Likewise. + (rust_cfg_parser_test): Likewise. + * parse/rust-parse-impl.h (Parser::skip_generics_right_angle): Likewise. + (Parser::parse_attr_input): Likewise. + (Parser::parse_macro_match): Likewise. + (Parser::parse_visibility): Likewise. + (Parser::parse_module): Likewise. + (Parser::parse_use_tree): Likewise. + (Parser::parse_generic_param): Likewise. + (Parser::parse_struct): Likewise. + (Parser::parse_enum_item): Likewise. + (Parser::parse_inherent_impl_item): Likewise. + (Parser::parse_external_item): Likewise. + (Parser::parse_generic_arg): Likewise. + (Parser::parse_type_path_segment): Likewise. + (Parser::parse_expr_stmt): Likewise. + (Parser::parse_if_expr): Likewise. + (Parser::parse_if_let_expr): Likewise. + (Parser::parse_type): Likewise. + (Parser::parse_for_prefixed_type): Likewise. + (Parser::parse_slice_or_array_type): Likewise. + (Parser::parse_type_no_bounds): Likewise. + (Parser::parse_range_pattern_bound): Likewise. + (Parser::parse_pattern_no_alt): Likewise. + (Parser::parse_grouped_or_tuple_pattern): Likewise. + (Parser::parse_ident_leading_pattern): Likewise. + (Parser::parse_tuple_struct_items): Likewise. + (Parser::parse_stmt_or_expr): Likewise. + (Parser::parse_struct_expr_field): Likewise. + (Parser::null_denotation): Likewise. + (Parser::left_denotation): Likewise. + (Parser::parse_closure_expr_pratt): Likewise. + * parse/rust-parse.cc (peculiar_fragment_match_compatible): Likewise. + (is_match_compatible): Likewise. + * parse/rust-parse.h (extract_module_path): Likewise. + (is_match_compatible): Likewise. + * resolve/rust-ast-resolve-expr.cc (translate_operand): Likewise. + * resolve/rust-ast-resolve-item.cc (flatten_glob): Likewise. + (flatten_rebind): Likewise. + (flatten_list): Likewise. + (flatten): Likewise. + * resolve/rust-ast-resolve-item.h (rust_simple_path_resolve_test): Likewise. + * resolve/rust-ast-resolve-pattern.cc (PatternDeclaration::visit): Likewise. + (resolve_range_pattern_bound): Likewise. + * resolve/rust-ast-resolve-type.cc (ResolveRelativeTypePath::go): Likewise. + (ResolveTypeToCanonicalPath::visit): Likewise. + * resolve/rust-ast-resolve.cc (saw_errors): Likewise. + * resolve/rust-early-name-resolver-2.0.cc (Early::finalize_rebind_import): Likewise. + * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Likewise. + * resolve/rust-toplevel-name-resolver-2.0.cc (flatten_glob): Likewise. + * rust-backend.h (init): Likewise. + (debug): Likewise. + (get_identifier_node): Likewise. + (wchar_type): Likewise. + (get_pointer_size): Likewise. + (raw_str_type): Likewise. + (integer_type): Likewise. + (float_type): Likewise. + (pointer_type): Likewise. + (reference_type): Likewise. + (immutable_type): Likewise. + (function_type): Likewise. + (function_type_variadic): Likewise. + (function_ptr_type): Likewise. + (struct_type): Likewise. + (union_type): Likewise. + (array_type): Likewise. + (named_type): Likewise. + (type_field_offset): Likewise. + (var_expression): Likewise. + (float_constant_expression): Likewise. + (string_constant_expression): Likewise. + (char_constant_expression): Likewise. + (wchar_constant_expression): Likewise. + (boolean_constant_expression): Likewise. + (convert_expression): Likewise. + (struct_field_expression): Likewise. + (compound_expression): Likewise. + (conditional_expression): Likewise. + (negation_expression): Likewise. + (arithmetic_or_logical_expression): Likewise. + (arithmetic_or_logical_expression_checked): Likewise. + (comparison_expression): Likewise. + (lazy_boolean_expression): Likewise. + (constructor_expression): Likewise. + (array_constructor_expression): Likewise. + (array_initializer): Likewise. + (array_index_expression): Likewise. + (call_expression): Likewise. + (init_statement): Likewise. + (assignment_statement): Likewise. + (return_statement): Likewise. + (if_statement): Likewise. + (loop_expression): Likewise. + (exit_expression): Likewise. + (statement_list): Likewise. + (exception_handler_statement): Likewise. + (block): Likewise. + (block_add_statements): Likewise. + (global_variable): Likewise. + (global_variable_set_init): Likewise. + (local_variable): Likewise. + (parameter_variable): Likewise. + (static_chain_variable): Likewise. + (temporary_variable): Likewise. + (label): Likewise. + (function): Likewise. + (function_defer_statement): Likewise. + (function_set_parameters): Likewise. + (write_global_definitions): Likewise. + (fill_in_fields): Likewise. + * rust-diagnostics.cc (expand_format): Likewise. + (expand_message): Likewise. + (va_constructor): Likewise. + * rust-diagnostics.h (RUST_ATTRIBUTE_GCC_DIAG): Likewise. + (rust_open_quote): Likewise. + (rust_close_quote): Likewise. + (rust_debug_loc): Likewise. + * rust-gcc.cc (non_zero_size_type): Likewise. + * rust-object-export.h (rust_field_alignment): Likewise. + (rust_read_export_data): Likewise. + (rust_write_export_data): Likewise. + * rust-session-manager.cc (saw_errors): Likewise. + (rust_get_linemap): Likewise. + (validate_crate_name): Likewise. + (Session::load_extern_crate): Likewise. + * rust-session-manager.h (rust_crate_name_validation_test): Likewise. + * rust-system.h (rust_preserve_from_gc): Likewise. + (rust_localize_identifier): Likewise. + * rust-target.h (rust_add_target_info): Likewise. + * typecheck/rust-autoderef.cc: + * typecheck/rust-casts.cc (TypeCastRules::cast_rules): Likewise. + * typecheck/rust-coercion.cc (TypeCoercionRules::do_coercion): Likewise. + (TypeCoercionRules::coerce_unsafe_ptr): Likewise. + (TypeCoercionRules::coerce_borrowed_pointer): Likewise. + * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): Likewise. + (TraitItemReference::is_object_safe): Likewise. + * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::resolve_literal): Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + (typecheck_inline_asm_operand): Likewise. + * typecheck/rust-hir-type-check-implitem.cc (TypeCheckImplItem::visit): Likewise. + (TypeCheckImplItemWithTrait::visit): Likewise. + * typecheck/rust-hir-type-check-pattern.cc (TypeCheckPattern::visit): Likewise. + * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::visit): Likewise. + * typecheck/rust-hir-type-check-type.cc + (TypeResolveGenericParam::apply_trait_bounds): Likewise. + (ResolveWhereClauseItem::visit): Likewise. + * typecheck/rust-hir-type-check.cc (saw_errors): Likewise. + (TraitItemReference::get_type_from_fn): Likewise. + * typecheck/rust-type-util.h (query_type): Likewise. + (types_compatable): Likewise. + (unify_site): Likewise. + (unify_site_and): Likewise. + (coercion_site): Likewise. + (try_coercion): Likewise. + (cast_site): Likewise. + * typecheck/rust-tyty-bounds.cc: + * typecheck/rust-tyty-call.cc (TypeCheckCallExpr::visit): Likewise. + * typecheck/rust-tyty-cmp.h: + * typecheck/rust-tyty-variance-analysis.h (query_field_regions): Likewise. + * typecheck/rust-tyty.cc (BaseType::is_unit): Likewise. + (BaseType::has_substitutions_defined): Likewise. + (BaseType::needs_generic_substitutions): Likewise. + (BaseType::get_subst_argument_mappings): Likewise. + (InferType::default_type): Likewise. + (InferType::apply_primitive_type_hint): Likewise. + * typecheck/rust-tyty.h (is_primitive_type_kind): Likewise. + * typecheck/rust-unify.cc (UnifyRules::expect_inference_variable): Likewise. + (UnifyRules::expect_adt): Likewise. + (UnifyRules::expect_str): Likewise. + (UnifyRules::expect_reference): Likewise. + (UnifyRules::expect_pointer): Likewise. + (UnifyRules::expect_param): Likewise. + (UnifyRules::expect_array): Likewise. + (UnifyRules::expect_slice): Likewise. + (UnifyRules::expect_fndef): Likewise. + (UnifyRules::expect_fnptr): Likewise. + (UnifyRules::expect_tuple): Likewise. + (UnifyRules::expect_bool): Likewise. + (UnifyRules::expect_char): Likewise. + (UnifyRules::expect_int): Likewise. + (UnifyRules::expect_uint): Likewise. + (UnifyRules::expect_float): Likewise. + (UnifyRules::expect_isize): Likewise. + (UnifyRules::expect_usize): Likewise. + (UnifyRules::expect_never): Likewise. + (UnifyRules::expect_placeholder): Likewise. + (UnifyRules::expect_projection): Likewise. + (UnifyRules::expect_dyn): Likewise. + (UnifyRules::expect_closure): Likewise. + (UnifyRules::expect_opaque): Likewise. + * util/rust-abi.h (get_abi_from_string): Likewise. + (get_string_from_abi): Likewise. + * util/rust-attributes.cc (check_doc_attribute): Likewise. + * util/rust-base62.h (base62_integer): Likewise. + * util/rust-dir-owner.h (get_file_subdir): Likewise. + * util/rust-edition.h (get_rust_edition): Likewise. + * util/rust-punycode.h (encode_punycode): Likewise. + (rust_punycode_encode_test): Likewise. + * util/rust-token-converter.cc (convert): Likewise. + (from_tokenstream): Likewise. + * util/rust-token-converter.h (convert): Likewise. + (convert_literal): Likewise. + * util/rust-unicode.h (is_alphabetic): Likewise. + (is_ascii_only): Likewise. + (is_numeric): Likewise. + (is_nfc_qc_no): Likewise. + (is_nfc_qc_maybe): Likewise. + (nfc_quick_check): Likewise. + (rust_nfc_qc_test): Likewise. + (rust_utf8_normalize_test): Likewise. + (rust_utf8_property_test): Likewise. + * util/rust-unwrap-segment.h (unwrap_segment_node_id): Likewise. + +2025-08-05 Marc Poulhiès <dkm@kataplop.net> + + * Make-lang.in (GRS_OBJS): Remove rust-macro.o. + * ast/rust-macro.cc: Removed. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * parse/rust-parse-impl.h + (Parser::parse_attr_input): Handle more delimeter tokens and the + END_OF_FILE token. + (Parser::skip_after_end_attribute): Handle the END_OF_FILE + token. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * hir/rust-ast-lower-item.cc + (ASTLoweringItem::visit): Keep going after a duplicate field is + found. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * checks/errors/borrowck/rust-bir-builder-internal.h: Include + "rust-immutable-name-resolution-context.h" and "options.h". + (AbstractBuilder::resolve_label): Use the 2.0 name resolver when + it's enabled. + (AbstractBuilder::resolve_variable): Likewise. + (AbstractBuilder::resolve_variable_or_fn): Likewise. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * expand/rust-derive-default.cc (DeriveDefault::visit_struct): use builder + (DeriveDefault::visit_tuple): likewise + * expand/rust-derive-eq.cc (DeriveEq::visit_tuple): likewise + (DeriveEq::visit_struct): likewise + (DeriveEq::visit_enum): likewise + (DeriveEq::visit_union): likewise + +2025-08-05 Marc Poulhiès <dkm@kataplop.net> + + PR rust/120018 + * rust-attribs.cc (handle_noreturn_attribute): Reindent declaration. + (handle_leaf_attribute): Likewise. + (handle_const_attribute): Likewise. + (handle_malloc_attribute): Likewise. + (handle_pure_attribute): Likewise. + (handle_novops_attribute): Likewise. + (handle_nonnull_attribute): Likewise. + (handle_nothrow_attribute): Likewise. + (handle_type_generic_attribute): Likewise. + (handle_transaction_pure_attribute): Likewise. + (handle_returns_twice_attribute): Likewise. + (handle_fnspec_attribute): Likewise. + (handle_omp_declare_simd_attribute): Likewise. + (handle_cold_attribute): New. + (handle_hot_attribute): New. + (attribute_spec::exclusions attr_cold_hot_exclusions): New. + (grs_langhook_common_attributes): Make it static. + (grs_langhook_common_attribute_table): New. + (grs_langhook_gnu_attributes): New. + (grs_langhook_gnu_attribute_table): New. + (handle_malloc_attribute): Make it static. + (handle_fnspec_attribute): Likewise. + (handle_pure_attribute): Replace gcc_assert by explicit warning. + (handle_novops_attribute): Likewise. + (handle_nothrow_attribute): Likewise. + (handle_returns_twice_attribute): Likewise. + (handle_omp_declare_simd_attribute): Likewise and make it static. + * rust-lang.cc (grs_langhook_gnu_attribute_table): New. + (grs_langhook_common_attribute_table): Adjust type to new hook. + (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Remove. + (LANG_HOOKS_ATTRIBUTE_TABLE): New. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-path.cc + (TypePath::make_debug_string): Add definition. + * ast/rust-path.h + (TypePath::make_debug_string): Add declaration. + * resolve/rust-default-resolver.cc + (DefaultResolver::visit): Adjust InherentImpl and TraitImpl + visitors to better handle associated item scope. + * resolve/rust-default-resolver.h + (DefaultResolver::maybe_insert_big_self): Add. + * resolve/rust-late-name-resolver-2.0.cc + (Late::visit): Adjust type path resolution errors. + * resolve/rust-rib.h + (Rib::Kind): Add Generics kind. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Remove InherentImpl and TraitImpl visitor + overrides. + (TopLevel::maybe_insert_big_self): Add override in order to add + a definition of 'Self'. + * resolve/rust-toplevel-name-resolver-2.0.h + (TopLevel::visit): Remove InherentImpl and TraitImpl visitor + overrides. + (TopLevel::maybe_insert_big_self): Add override. + +2025-08-05 0xn4utilus <gyanendrabanjare8@gmail.com> + + * ast/rust-ast-collector.cc (TokenCollector::visit): Implement for InlineAsm. + * ast/rust-ast-full-decls.h (enum class): Move InlineAsmOption enum inside InlineAsm. + * ast/rust-expr.h (enum class): Likewise. + (class InlineAsm): Likewise. + * expand/rust-macro-builtins-asm.cc (check_and_set): Likewise. + (parse_options): Likewise. + * expand/rust-macro-builtins-asm.h (check_and_set): Likewise. + * hir/tree/rust-hir-expr.cc (InlineAsm::InlineAsm): Likewise. + * hir/tree/rust-hir-expr.h: Likewise. + * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): Likewise. + +2025-08-05 Tom Schollenberger <tss2344@g.rit.edu> + + * backend/rust-constexpr.cc (eval_constant_expression): Check if t is a NULL_TREE + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * ast/rust-desugar-apit.cc: track if this is a impl-trait generic + * ast/rust-item.h (class TypeParam): add field to track if from impl trait + * hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): likewise + * hir/tree/rust-hir-item.cc (TypeParam::TypeParam): upate hir as well + (TypeParam::operator=): likewise + * hir/tree/rust-hir-item.h (class TypeParam): likewise + * typecheck/rust-tyty-subst.cc (SubstitutionParamMapping::get_generic_param): add error + * typecheck/rust-tyty-subst.h: add const getter for the associated TypeParm + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * ast/rust-ast-visitor.cc + (DefaultASTVisitor::visit): Make call to EnumItem visitor from + EnumItem derived class visitors non-virtual. + * ast/rust-collect-lang-items.cc + (CollectLangItems::visit): Handle visitation of classes derived + from EnumItem. + * ast/rust-collect-lang-items.h + (CollectLangItems::visit): Likewise. + * resolve/rust-toplevel-name-resolver-2.0.cc + (TopLevel::visit): Call DefaultResolver::visit on EnumItem + instances. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * backend/rust-compile-pattern.cc + (CompilePatternCheckExpr::visit): Fix GENERIC generation in + light of enum layout changes since this code was written. + (CompilePatternBindings::handle_struct_pattern_ident_pat): + Delegate handling of child patterns to another + CompilePatternBindings::Compile call. + (CompilePatternBindings::make_struct_access): Make field name + parameter const qualified. + * backend/rust-compile-pattern.h + (CompilePatternBindings::make_struct_access): Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * resolve/rust-ast-resolve-item.cc + (ResolveItem::visit): Use the return values of + CanonicalPath::inherent_impl_seg and + CanonicalPath::trait_impl_projection_seg more directly. + * util/rust-canonical-path.h + (CanonicalPath::trait_impl_projection_seg): Append "<impl " + instead of "<" to the beginning of the returned path segment. + (CanonicalPath::inherent_impl_seg): Likewise. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * Make-lang.in: new desugar file + * ast/rust-ast.cc (ImplTraitTypeOneBound::as_string): its a unique_ptr now + (FormatArgs::set_outer_attrs): reformat + * ast/rust-path.h: remove has_generic_args assertion (can be empty because of desugar) + * ast/rust-type.h (class ImplTraitTypeOneBound): add copy ctor and use unique_ptr + * hir/rust-ast-lower-type.cc (ASTLoweringType::visit): update to use unique_ptr + * parse/rust-parse-impl.h (Parser::parse_type): reuse the existing unique_ptr instead + (Parser::parse_type_no_bounds): likewise + (Parser::parse_pattern): likewise + * resolve/rust-ast-resolve-type.cc (ResolveType::visit): its a unique_ptr now + * rust-session-manager.cc (Session::compile_crate): call desugar + * ast/rust-desugar-apit.cc: New file. + * ast/rust-desugar-apit.h: New file. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * hir/rust-ast-lower-implitem.cc (ASTLowerImplItem::visit): allow impl type + * hir/rust-ast-lower-item.cc (ASTLoweringItem::visit): likewise + * hir/rust-ast-lower-type.cc (ASTLoweringType::ASTLoweringType): new flag for impl trait + (ASTLoweringType::translate): pass flag + (ASTLoweringType::visit): track impl trait tag + (ASTLoweringType::emit_impl_trait_error): new diagnostic + * hir/rust-ast-lower-type.h: add new field + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * expand/rust-derive-partial-eq.cc (DerivePartialEq::match_enum_tuple): Remove debug call. + (DerivePartialEq::match_enum_struct): Add proper implementation. + (DerivePartialEq::visit_enum): Call it. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * ast/rust-ast-builder.cc (Builder::struct_pattern_ident_pattern): New. + * ast/rust-ast-builder.h: New declaration. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * backend/rust-compile-pattern.cc (CompilePatternBindings::make_struct_access): + New function. + (CompilePatternBindings::visit): Properly implement patterns mentioned above + and call make_struct_accesss. + * backend/rust-compile-pattern.h: New declaration. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * backend/rust-compile-pattern.h: Split struct pattern compilation into three functions. + * backend/rust-compile-pattern.cc: Implement them. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * resolve/rust-late-name-resolver-2.0.cc (Late::Late): False initialize the + funny_error field. + 2025-07-25 David Malcolm <dmalcolm@redhat.com> * resolve/rust-ice-finalizer.cc: Update usage of "diagnostic_info" diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 835e113..8cdf6c9 100644 --- a/gcc/rust/Make-lang.in +++ b/gcc/rust/Make-lang.in @@ -73,6 +73,9 @@ GRS_OBJS = \ rust/rust-lex.o \ rust/rust-cfg-parser.o \ rust/rust-parse.o \ + rust/rust-parse-impl-proc-macro.o \ + rust/rust-parse-impl-macro.o \ + rust/rust-parse-impl-lexer.o \ rust/rust-ast.o \ rust/rust-ast-formatting.o \ rust/rust-path.o \ @@ -81,6 +84,7 @@ GRS_OBJS = \ rust/rust-ast-dump.o \ rust/rust-ast-collector.o \ rust/rust-ast-visitor.o \ + rust/rust-hir-visitor.o \ rust/rust-hir-dump.o \ rust/rust-session-manager.o \ rust/rust-compile.o \ @@ -92,14 +96,15 @@ GRS_OBJS = \ rust/rust-cfg-strip.o \ rust/rust-expand-visitor.o \ rust/rust-ast-builder.o \ - rust/rust-ast-builder-type.o \ rust/rust-derive.o \ + rust/rust-derive-cmp-common.o \ rust/rust-derive-clone.o \ rust/rust-derive-copy.o \ rust/rust-derive-debug.o \ rust/rust-derive-default.o \ rust/rust-derive-partial-eq.o \ rust/rust-derive-eq.o \ + rust/rust-derive-ord.o \ rust/rust-derive-hash.o \ rust/rust-proc-macro.o \ rust/rust-macro-invoc-lexer.o \ @@ -113,6 +118,7 @@ GRS_OBJS = \ rust/rust-macro-builtins-log-debug.o \ rust/rust-macro-builtins-test-bench.o \ rust/rust-macro-builtins-format-args.o \ + rust/rust-macro-builtins-offset-of.o \ rust/rust-macro-builtins-location.o \ rust/rust-macro-builtins-include.o \ rust/rust-token-tree-desugar.o \ @@ -123,7 +129,6 @@ GRS_OBJS = \ rust/rust-keyword-values.o \ rust/rust-abi.o \ rust/rust-token-converter.o \ - rust/rust-macro.o \ rust/rust-ast-lower.o \ rust/rust-ast-lower-base.o \ rust/rust-ast-lower-pattern.o \ @@ -204,6 +209,7 @@ GRS_OBJS = \ rust/rust-lint-marklive.o \ rust/rust-lint-unused-var.o \ rust/rust-readonly-check.o \ + rust/rust-readonly-check2.o \ rust/rust-hir-type-check-path.o \ rust/rust-unsafe-checker.o \ rust/rust-hir-pattern-analysis.o \ @@ -237,11 +243,16 @@ GRS_OBJS = \ rust/rust-punycode.o \ rust/rust-unwrap-segment.o \ rust/rust-edition.o \ + rust/rust-ggc.o \ rust/rust-expand-format-args.o \ rust/rust-lang-item.o \ rust/rust-collect-lang-items.o \ + rust/rust-expression-yeast.o \ rust/rust-desugar-for-loops.o \ + rust/rust-desugar-while-let.o \ rust/rust-desugar-question-mark.o \ + rust/rust-desugar-apit.o \ + rust/rust-desugar-try-block.o \ $(END) # removed object files from here diff --git a/gcc/rust/ast/rust-ast-builder-type.cc b/gcc/rust/ast/rust-ast-builder-type.cc deleted file mode 100644 index 13126b4..0000000 --- a/gcc/rust/ast/rust-ast-builder-type.cc +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (C) 2020-2024 Free Software Foundation, Inc. - -// This file is part of GCC. - -// GCC is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 3, or (at your option) any later -// version. - -// GCC is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. - -// You should have received a copy of the GNU General Public License -// along with GCC; see the file COPYING3. If not see -// <http://www.gnu.org/licenses/>. - -#include "rust-ast-builder-type.h" -#include "rust-ast-builder.h" -#include "rust-ast-full.h" -#include "rust-common.h" - -namespace Rust { -namespace AST { - -ASTTypeBuilder::ASTTypeBuilder () : translated (nullptr) {} - -Type * -ASTTypeBuilder::build (Type &type) -{ - ASTTypeBuilder builder; - type.accept_vis (builder); - rust_assert (builder.translated != nullptr); - return builder.translated; -} - -void -ASTTypeBuilder::visit (BareFunctionType &fntype) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (TupleType &tuple) -{ - std::vector<std::unique_ptr<Type> > elems; - for (auto &elem : tuple.get_elems ()) - { - Type *t = ASTTypeBuilder::build (*elem.get ()); - std::unique_ptr<Type> ty (t); - elems.push_back (std::move (ty)); - } - translated = new TupleType (std::move (elems), tuple.get_locus ()); -} - -void -ASTTypeBuilder::visit (TypePath &path) -{ - std::vector<std::unique_ptr<TypePathSegment> > segments; - for (auto &seg : path.get_segments ()) - { - switch (seg->get_type ()) - { - case TypePathSegment::REG: { - const TypePathSegment &segment - = (const TypePathSegment &) (*seg.get ()); - TypePathSegment *s - = new TypePathSegment (segment.get_ident_segment (), - segment.get_separating_scope_resolution (), - segment.get_locus ()); - std::unique_ptr<TypePathSegment> sg (s); - segments.push_back (std::move (sg)); - } - break; - - case TypePathSegment::GENERIC: { - TypePathSegmentGeneric &generic - = (TypePathSegmentGeneric &) (*seg.get ()); - - GenericArgs args - = Builder::new_generic_args (generic.get_generic_args ()); - TypePathSegmentGeneric *s - = new TypePathSegmentGeneric (generic.get_ident_segment (), false, - std::move (args), - generic.get_locus ()); - std::unique_ptr<TypePathSegment> sg (s); - segments.push_back (std::move (sg)); - } - break; - - case TypePathSegment::FUNCTION: { - rust_unreachable (); - // TODO - // const TypePathSegmentFunction &fn - // = (const TypePathSegmentFunction &) (*seg.get ()); - } - break; - } - } - - translated = new TypePath (std::move (segments), path.get_locus (), - path.has_opening_scope_resolution_op ()); -} - -void -ASTTypeBuilder::visit (QualifiedPathInType &path) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (ArrayType &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (ReferenceType &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (RawPointerType &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (SliceType &type) -{ - Type *t = ASTTypeBuilder::build (type.get_elem_type ()); - std::unique_ptr<Type> ty (t); - translated = new SliceType (std::move (ty), type.get_locus ()); -} - -void -ASTTypeBuilder::visit (InferredType &type) -{ - translated = new InferredType (type.get_locus ()); -} - -void -ASTTypeBuilder::visit (NeverType &type) -{ - translated = new NeverType (type.get_locus ()); -} - -void -ASTTypeBuilder::visit (TraitObjectTypeOneBound &type) -{ - /* TODO */ -} - -void -ASTTypeBuilder::visit (TraitObjectType &type) -{ - /* TODO */ -} - -} // namespace AST -} // namespace Rust diff --git a/gcc/rust/ast/rust-ast-builder-type.h b/gcc/rust/ast/rust-ast-builder-type.h deleted file mode 100644 index b67ae3b..0000000 --- a/gcc/rust/ast/rust-ast-builder-type.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2020-2024 Free Software Foundation, Inc. - -// This file is part of GCC. - -// GCC is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 3, or (at your option) any later -// version. - -// GCC is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. - -// You should have received a copy of the GNU General Public License -// along with GCC; see the file COPYING3. If not see -// <http://www.gnu.org/licenses/>. - -#ifndef RUST_AST_BUILDER_TYPE -#define RUST_AST_BUILDER_TYPE - -#include "rust-ast-visitor.h" - -namespace Rust { -namespace AST { - -class ASTTypeBuilder : public DefaultASTVisitor -{ -protected: - using DefaultASTVisitor::visit; - -public: - static Type *build (Type &type); - - void visit (BareFunctionType &fntype) override; - void visit (TupleType &tuple) override; - void visit (TypePath &path) override; - void visit (QualifiedPathInType &path) override; - void visit (ArrayType &type) override; - void visit (ReferenceType &type) override; - void visit (RawPointerType &type) override; - void visit (SliceType &type) override; - void visit (InferredType &type) override; - void visit (NeverType &type) override; - void visit (TraitObjectTypeOneBound &type) override; - void visit (TraitObjectType &type) override; - -private: - ASTTypeBuilder (); - - Type *translated; -}; - -} // namespace AST -} // namespace Rust - -#endif // RUST_AST_BUILDER_TYPE diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc index 08c52b1..ed10ce7 100644 --- a/gcc/rust/ast/rust-ast-builder.cc +++ b/gcc/rust/ast/rust-ast-builder.cc @@ -18,7 +18,6 @@ #include "rust-ast-builder.h" #include "optional.h" -#include "rust-ast-builder-type.h" #include "rust-ast.h" #include "rust-common.h" #include "rust-expr.h" @@ -29,7 +28,6 @@ #include "rust-pattern.h" #include "rust-system.h" #include "rust-token.h" -#include <memory> namespace Rust { namespace AST { @@ -332,6 +330,12 @@ Builder::block () const } std::unique_ptr<BlockExpr> +Builder::block (std::unique_ptr<Expr> &&tail_expr) const +{ + return block (tl::nullopt, std::move (tail_expr)); +} + +std::unique_ptr<BlockExpr> Builder::block (std::vector<std::unique_ptr<Stmt>> &&stmts, std::unique_ptr<Expr> &&tail_expr) const { @@ -442,6 +446,14 @@ Builder::field_access (std::unique_ptr<Expr> &&instance, new FieldAccessExpr (std::move (instance), field, {}, loc)); } +std::unique_ptr<StructPatternField> +Builder::struct_pattern_ident_pattern (std::string field_name, + std::unique_ptr<Pattern> &&pattern) +{ + return std::make_unique<StructPatternFieldIdentPat> ( + field_name, std::move (pattern), std::vector<Attribute> (), loc); +} + std::unique_ptr<Pattern> Builder::wildcard () const { @@ -482,9 +494,14 @@ MatchCase Builder::match_case (std::unique_ptr<Pattern> &&pattern, std::unique_ptr<Expr> &&expr) { - return MatchCase (match_arm (std::move (pattern)), std::move (expr)); + return match_case (match_arm (std::move (pattern)), std::move (expr)); } +MatchCase +Builder::match_case (MatchArm &&arm, std::unique_ptr<Expr> &&expr) +{ + return MatchCase (std::move (arm), std::move (expr)); +} std::unique_ptr<Expr> Builder::loop (std::vector<std::unique_ptr<Stmt>> &&stmts) { @@ -523,11 +540,14 @@ Builder::generic_type_param ( std::vector<Attribute> ()); } -std::unique_ptr<Type> -Builder::new_type (Type &type) +std::unique_ptr<Stmt> +Builder::discriminant_value (std::string binding_name, std::string instance) { - Type *t = ASTTypeBuilder::build (type); - return std::unique_ptr<Type> (t); + auto intrinsic = ptrify ( + path_in_expression ({"core", "intrinsics", "discriminant_value"}, true)); + + return let (identifier_pattern (binding_name), nullptr, + call (std::move (intrinsic), identifier (instance))); } std::unique_ptr<GenericParam> @@ -547,6 +567,16 @@ Builder::new_lifetime_param (LifetimeParam ¶m) } std::unique_ptr<GenericParam> +Builder::new_const_param (ConstGenericParam ¶m) const +{ + return std::make_unique<ConstGenericParam> (param.get_name (), + param.get_type ().clone_type (), + param.get_default_value (), + param.get_outer_attrs (), + param.get_locus ()); +} + +std::unique_ptr<GenericParam> Builder::new_type_param ( TypeParam ¶m, std::vector<std::unique_ptr<TypeParamBound>> extra_bounds) { @@ -557,7 +587,7 @@ Builder::new_type_param ( std::unique_ptr<Type> type = nullptr; if (param.has_type ()) - type = new_type (param.get_type ()); + type = param.get_type ().reconstruct (); for (auto &&extra_bound : extra_bounds) type_param_bounds.emplace_back (std::move (extra_bound)); @@ -566,7 +596,8 @@ Builder::new_type_param ( { switch (b->get_bound_type ()) { - case TypeParamBound::TypeParamBoundType::TRAIT: { + case TypeParamBound::TypeParamBoundType::TRAIT: + { const TraitBound &tb = (const TraitBound &) *b.get (); const TypePath &path = tb.get_type_path (); @@ -591,7 +622,8 @@ Builder::new_type_param ( { switch (seg->get_type ()) { - case TypePathSegment::REG: { + case TypePathSegment::REG: + { const TypePathSegment &segment = (const TypePathSegment &) (*seg.get ()); TypePathSegment *s = new TypePathSegment ( @@ -603,7 +635,8 @@ Builder::new_type_param ( } break; - case TypePathSegment::GENERIC: { + case TypePathSegment::GENERIC: + { TypePathSegmentGeneric &generic = (TypePathSegmentGeneric &) (*seg.get ()); @@ -617,7 +650,8 @@ Builder::new_type_param ( } break; - case TypePathSegment::FUNCTION: { + case TypePathSegment::FUNCTION: + { rust_unreachable (); // TODO // const TypePathSegmentFunction &fn @@ -639,7 +673,8 @@ Builder::new_type_param ( } break; - case TypeParamBound::TypeParamBoundType::LIFETIME: { + case TypeParamBound::TypeParamBoundType::LIFETIME: + { const Lifetime &l = (const Lifetime &) *b.get (); auto bl = new Lifetime (l.get_lifetime_type (), @@ -682,7 +717,7 @@ Builder::new_generic_args (GenericArgs &args) for (auto &binding : args.get_binding_args ()) { Type &t = *binding.get_type_ptr ().get (); - std::unique_ptr<Type> ty = new_type (t); + std::unique_ptr<Type> ty = t.reconstruct (); GenericArgsBinding b (binding.get_identifier (), std::move (ty), binding.get_locus ()); binding_args.push_back (std::move (b)); @@ -690,19 +725,25 @@ Builder::new_generic_args (GenericArgs &args) for (auto &arg : args.get_generic_args ()) { + tl::optional<GenericArg> new_arg = tl::nullopt; + switch (arg.get_kind ()) { - case GenericArg::Kind::Type: { - std::unique_ptr<Type> ty = new_type (arg.get_type ()); - GenericArg arg = GenericArg::create_type (std::move (ty)); - } + case GenericArg::Kind::Type: + new_arg = GenericArg::create_type (arg.get_type ().reconstruct ()); break; - - default: - // FIXME - rust_unreachable (); + case GenericArg::Kind::Either: + new_arg + = GenericArg::create_ambiguous (arg.get_path (), arg.get_locus ()); + break; + case GenericArg::Kind::Const: + new_arg + = GenericArg::create_const (arg.get_expression ().clone_expr ()); + // FIXME: Use `reconstruct()` here, not `clone_expr()` break; } + + generic_args.emplace_back (*new_arg); } return GenericArgs (std::move (lifetime_args), std::move (generic_args), diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h index 41ce118..843bab8 100644 --- a/gcc/rust/ast/rust-ast-builder.h +++ b/gcc/rust/ast/rust-ast-builder.h @@ -24,6 +24,7 @@ #include "rust-ast.h" #include "rust-item.h" #include "rust-operators.h" +#include <initializer_list> namespace Rust { namespace AST { @@ -51,6 +52,19 @@ vec (std::unique_ptr<T> &&t1, std::unique_ptr<T> &&t2) return v; } +template <typename T> +std::vector<std::unique_ptr<T>> +vec (std::unique_ptr<T> &&t1, std::unique_ptr<T> &&t2, std::unique_ptr<T> &&t3) +{ + auto v = std::vector<std::unique_ptr<T>> (); + + v.emplace_back (std::move (t1)); + v.emplace_back (std::move (t2)); + v.emplace_back (std::move (t3)); + + return v; +} + /* Pointer-ify something */ template <typename T> static std::unique_ptr<T> @@ -117,6 +131,9 @@ public: /* Create an empty block */ std::unique_ptr<BlockExpr> block () const; + /* Create a block with just a tail expression */ + std::unique_ptr<BlockExpr> block (std::unique_ptr<Expr> &&tail_expr) const; + /* Create an early return expression with an optional expression */ std::unique_ptr<Expr> return_expr (std::unique_ptr<Expr> &&to_return = nullptr); @@ -254,6 +271,10 @@ public: std::unique_ptr<Expr> field_access (std::unique_ptr<Expr> &&instance, std::string field) const; + std::unique_ptr<StructPatternField> + struct_pattern_ident_pattern (std::string field_name, + std::unique_ptr<Pattern> &&pattern); + /* Create a wildcard pattern (`_`) */ std::unique_ptr<Pattern> wildcard () const; /* Create a reference pattern (`&pattern`) */ @@ -268,6 +289,7 @@ public: MatchArm match_arm (std::unique_ptr<Pattern> &&pattern); MatchCase match_case (std::unique_ptr<Pattern> &&pattern, std::unique_ptr<Expr> &&expr); + MatchCase match_case (MatchArm &&arm, std::unique_ptr<Expr> &&expr); /* Create a loop expression */ std::unique_ptr<Expr> loop (std::vector<std::unique_ptr<Stmt>> &&stmts); @@ -285,11 +307,20 @@ public: std::vector<std::unique_ptr<TypeParamBound>> &&bounds, std::unique_ptr<Type> &&type = nullptr); - static std::unique_ptr<Type> new_type (Type &type); + /** + * Create a let statement with the discriminant value of a given enum + * instance. This helper exists since it is a common operation in a lot of the + * derive implementations, and it sucks to repeat all the steps every time. + */ + std::unique_ptr<Stmt> discriminant_value (std::string binding_name, + std::string instance = "self"); static std::unique_ptr<GenericParam> new_lifetime_param (LifetimeParam ¶m); + std::unique_ptr<GenericParam> + new_const_param (ConstGenericParam ¶m) const; + static std::unique_ptr<GenericParam> new_type_param ( TypeParam ¶m, std::vector<std::unique_ptr<TypeParamBound>> extra_trait_bounds = {}); @@ -298,11 +329,13 @@ public: static GenericArgs new_generic_args (GenericArgs &args); -private: - /** - * Location of the generated AST nodes - */ + /* Location of the generated AST nodes */ location_t loc; + +private: + /* Some constexpr helpers for some of the builders */ + static constexpr std::initializer_list<const char *> discriminant_value_path + = {"core", "intrinsics", "discriminant_value"}; }; } // namespace AST diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index c850e96..3d9ea78 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -18,6 +18,7 @@ #include "rust-ast-collector.h" #include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" #include "rust-diagnostics.h" #include "rust-expr.h" #include "rust-item.h" @@ -154,20 +155,24 @@ TokenCollector::visit (Attribute &attrib) { switch (attrib.get_attr_input ().get_attr_input_type ()) { - case AST::AttrInput::AttrInputType::LITERAL: { + case AST::AttrInput::AttrInputType::LITERAL: + { visit (static_cast<AttrInputLiteral &> (attrib.get_attr_input ())); break; } - case AST::AttrInput::AttrInputType::MACRO: { + case AST::AttrInput::AttrInputType::MACRO: + { visit (static_cast<AttrInputMacro &> (attrib.get_attr_input ())); break; } - case AST::AttrInput::AttrInputType::META_ITEM: { + case AST::AttrInput::AttrInputType::META_ITEM: + { visit (static_cast<AttrInputMetaItemContainer &> ( attrib.get_attr_input ())); break; } - case AST::AttrInput::AttrInputType::TOKEN_TREE: { + case AST::AttrInput::AttrInputType::TOKEN_TREE: + { visit (static_cast<DelimTokenTree &> (attrib.get_attr_input ())); break; } @@ -634,7 +639,8 @@ TokenCollector::visit (GenericArg &arg) case GenericArg::Kind::Type: visit (arg.get_type ()); break; - case GenericArg::Kind::Either: { + case GenericArg::Kind::Either: + { auto path = arg.get_path (); push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path))); } @@ -789,7 +795,8 @@ TokenCollector::visit (Literal &lit, location_t locus) push (Rust::Token::make_float (locus, std::move (value), lit.get_type_hint ())); break; - case Literal::LitType::BOOL: { + case Literal::LitType::BOOL: + { if (value == Values::Keywords::FALSE_LITERAL) push (Rust::Token::make (FALSE_LITERAL, locus)); else if (value == Values::Keywords::TRUE_LITERAL) @@ -833,13 +840,13 @@ TokenCollector::visit (MetaItemLitExpr &item) } void -TokenCollector::visit (MetaItemPathLit &item) +TokenCollector::visit (MetaItemPathExpr &item) { - auto path = item.get_path (); - auto lit = item.get_literal (); + auto &path = item.get_path (); + auto &expr = item.get_expr (); visit (path); - push (Rust::Token::make (COLON, item.get_locus ())); - visit (lit); + push (Rust::Token::make (EQUAL, item.get_locus ())); + visit (expr); } void @@ -864,7 +871,8 @@ TokenCollector::visit (BorrowExpr &expr) push (Rust::Token::make (MUT, UNDEF_LOCATION)); } - visit (expr.get_borrowed_expr ()); + if (expr.has_borrow_expr ()) + visit (expr.get_borrowed_expr ()); } void @@ -1264,12 +1272,34 @@ TokenCollector::visit (BlockExpr &expr) } void +TokenCollector::visit (AnonConst &expr) +{ + if (!expr.is_deferred ()) + { + visit (expr.get_inner_expr ()); + return; + } + + push (Rust::Token::make_string (expr.get_locus (), "_")); +} + +void +TokenCollector::visit (ConstBlock &expr) +{ + push (Rust::Token::make (CONST, expr.get_locus ())); + + // The inner expression is already a block expr, so we don't need to add + // curlies + visit (expr.get_const_expr ()); +} + +void TokenCollector::visit (ClosureExprInnerTyped &expr) { visit_closure_common (expr); push (Rust::Token::make (RETURN_TYPE, expr.get_locus ())); visit (expr.get_return_type ()); - visit (expr.get_definition_block ()); + visit (expr.get_definition_expr ()); } void @@ -1349,6 +1379,13 @@ TokenCollector::visit (ReturnExpr &expr) } void +TokenCollector::visit (TryExpr &expr) +{ + push (Rust::Token::make (TRY, expr.get_locus ())); + visit (expr.get_block_expr ()); +} + +void TokenCollector::visit (UnsafeBlockExpr &expr) { push (Rust::Token::make (UNSAFE, expr.get_locus ())); @@ -1518,7 +1555,95 @@ TokenCollector::visit (AsyncBlockExpr &expr) void TokenCollector::visit (InlineAsm &expr) -{} +{ + push (Rust::Token::make_identifier (expr.get_locus (), "asm")); + push (Rust::Token::make (EXCLAM, expr.get_locus ())); + push (Rust::Token::make (LEFT_PAREN, expr.get_locus ())); + + for (auto &template_str : expr.get_template_strs ()) + push (Rust::Token::make_string (template_str.get_locus (), + std::move (template_str.symbol))); + + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto &operand : expr.get_operands ()) + { + using RegisterType = AST::InlineAsmOperand::RegisterType; + switch (operand.get_register_type ()) + { + case RegisterType::In: + { + visit (operand.get_in ().expr); + break; + } + case RegisterType::Out: + { + visit (operand.get_out ().expr); + break; + } + case RegisterType::InOut: + { + visit (operand.get_in_out ().expr); + break; + } + case RegisterType::SplitInOut: + { + auto split = operand.get_split_in_out (); + visit (split.in_expr); + visit (split.out_expr); + break; + } + case RegisterType::Const: + { + visit (operand.get_const ().anon_const.get_inner_expr ()); + break; + } + case RegisterType::Sym: + { + visit (operand.get_sym ().expr); + break; + } + case RegisterType::Label: + { + visit (operand.get_label ().expr); + break; + } + } + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto &clobber : expr.get_clobber_abi ()) + { + push (Rust::Token::make_string (expr.get_locus (), + std::move (clobber.symbol))); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto it = expr.named_args.begin (); it != expr.named_args.end (); ++it) + { + auto &arg = *it; + push ( + Rust::Token::make_identifier (expr.get_locus (), arg.first.c_str ())); + push (Rust::Token::make (EQUAL, expr.get_locus ())); + push (Rust::Token::make_identifier (expr.get_locus (), + std::to_string (arg.second))); + + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (COLON, expr.get_locus ())); + + for (auto &option : expr.get_options ()) + { + push (Rust::Token::make_identifier ( + expr.get_locus (), InlineAsm::option_to_string (option).c_str ())); + push (Rust::Token::make (COMMA, expr.get_locus ())); + } + + push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ())); +} void TokenCollector::visit (LlvmInlineAsm &expr) @@ -1695,7 +1820,8 @@ TokenCollector::visit (UseTreeGlob &use_tree) { switch (use_tree.get_glob_type ()) { - case UseTreeGlob::PathType::PATH_PREFIXED: { + case UseTreeGlob::PathType::PATH_PREFIXED: + { auto path = use_tree.get_path (); visit (path); push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION)); @@ -1715,7 +1841,8 @@ TokenCollector::visit (UseTreeList &use_tree) { switch (use_tree.get_path_type ()) { - case UseTreeList::PathType::PATH_PREFIXED: { + case UseTreeList::PathType::PATH_PREFIXED: + { auto path = use_tree.get_path (); visit (path); push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION)); @@ -1743,7 +1870,8 @@ TokenCollector::visit (UseTreeRebind &use_tree) visit (path); switch (use_tree.get_new_bind_type ()) { - case UseTreeRebind::NewBindType::IDENTIFIER: { + case UseTreeRebind::NewBindType::IDENTIFIER: + { push (Rust::Token::make (AS, UNDEF_LOCATION)); auto id = use_tree.get_identifier ().as_string (); push ( @@ -1964,8 +2092,7 @@ TokenCollector::visit (ConstantItem &item) } else { - auto id = item.get_identifier (); - push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id))); + push (Rust::Token::make_identifier (item.get_identifier ())); } push (Rust::Token::make (COLON, UNDEF_LOCATION)); visit (item.get_type ()); @@ -2370,10 +2497,10 @@ TokenCollector::visit (IdentifierPattern &pattern) auto id = pattern.get_ident ().as_string (); push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id))); - if (pattern.has_pattern_to_bind ()) + if (pattern.has_subpattern ()) { push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION)); - visit (pattern.get_pattern_to_bind ()); + visit (pattern.get_subpattern ()); } } @@ -2591,10 +2718,34 @@ TokenCollector::visit (GroupedPattern &pattern) } void +TokenCollector::visit (SlicePatternItemsNoRest &items) +{ + visit_items_joined_by_separator (items.get_patterns (), COMMA); +} + +void +TokenCollector::visit (SlicePatternItemsHasRest &items) +{ + if (!items.get_lower_patterns ().empty ()) + { + visit_items_joined_by_separator (items.get_lower_patterns (), COMMA); + push (Rust::Token::make (COMMA, UNDEF_LOCATION)); + } + + push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION)); + + if (!items.get_upper_patterns ().empty ()) + { + push (Rust::Token::make (COMMA, UNDEF_LOCATION)); + visit_items_joined_by_separator (items.get_upper_patterns (), COMMA); + } +} + +void TokenCollector::visit (SlicePattern &pattern) { push (Rust::Token::make (LEFT_SQUARE, pattern.get_locus ())); - visit_items_joined_by_separator (pattern.get_items (), COMMA); + visit (pattern.get_items ()); push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION)); } @@ -2862,5 +3013,23 @@ TokenCollector::visit (AST::FormatArgs &fmt) __FILE__, __LINE__); } +void +TokenCollector::visit (AST::OffsetOf &offset_of) +{ + auto loc = offset_of.get_locus (); + + push (Rust::Token::make_identifier (loc, "offset_of")); + push (Rust::Token::make (EXCLAM, loc)); + push (Rust::Token::make (LEFT_PAREN, loc)); + + visit (offset_of.get_type ()); + + push (Rust::Token::make (COMMA, loc)); + + push (Rust::Token::make_identifier (offset_of.get_field ())); + + push (Rust::Token::make (RIGHT_PAREN, loc)); +} + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h index f45e3cc..d3ab18a 100644 --- a/gcc/rust/ast/rust-ast-collector.h +++ b/gcc/rust/ast/rust-ast-collector.h @@ -246,7 +246,7 @@ public: void visit (AttrInputLiteral &attr_input); void visit (AttrInputMacro &attr_input); void visit (MetaItemLitExpr &meta_item); - void visit (MetaItemPathLit &meta_item); + void visit (MetaItemPathExpr &meta_item); void visit (BorrowExpr &expr); void visit (DereferenceExpr &expr); void visit (ErrorPropagationExpr &expr); @@ -277,6 +277,8 @@ public: void visit (ClosureParam ¶m); void visit (ClosureExprInner &expr); void visit (BlockExpr &expr); + void visit (AnonConst &expr); + void visit (ConstBlock &expr); void visit (ClosureExprInnerTyped &expr); void visit (ContinueExpr &expr); void visit (BreakExpr &expr); @@ -287,6 +289,7 @@ public: void visit (RangeFromToInclExpr &expr); void visit (RangeToInclExpr &expr); void visit (ReturnExpr &expr); + void visit (TryExpr &expr); void visit (BoxExpr &expr); void visit (UnsafeBlockExpr &expr); void visit (LoopExpr &expr); @@ -375,6 +378,8 @@ public: void visit (TuplePatternItemsRanged &tuple_items); void visit (TuplePattern &pattern); void visit (GroupedPattern &pattern); + void visit (SlicePatternItemsNoRest &items); + void visit (SlicePatternItemsHasRest &items); void visit (SlicePattern &pattern); void visit (AltPattern &pattern); @@ -400,6 +405,7 @@ public: void visit (BareFunctionType &type); void visit (FormatArgs &fmt); + void visit (OffsetOf &offset_of); }; } // namespace AST diff --git a/gcc/rust/ast/rust-ast-dump.h b/gcc/rust/ast/rust-ast-dump.h index 02c99b7..0c3875e 100644 --- a/gcc/rust/ast/rust-ast-dump.h +++ b/gcc/rust/ast/rust-ast-dump.h @@ -49,7 +49,8 @@ public: { switch (item.get_kind ()) { - case AST::CollectItem::Kind::Token: { + case AST::CollectItem::Kind::Token: + { TokenPtr current = item.get_token (); if (require_spacing (previous, current)) stream << " "; @@ -90,7 +91,6 @@ private: } // namespace Rust // In the global namespace to make it easier to call from debugger -void -debug (Rust::AST::Visitable &v); +void debug (Rust::AST::Visitable &v); #endif // !RUST_AST_DUMP_H diff --git a/gcc/rust/ast/rust-ast-formatting.h b/gcc/rust/ast/rust-ast-formatting.h index 3dfabbc..aace93f 100644 --- a/gcc/rust/ast/rust-ast-formatting.h +++ b/gcc/rust/ast/rust-ast-formatting.h @@ -35,23 +35,18 @@ enum AttrMode INNER }; -std::string -indent_spaces (enum indent_mode mode); +std::string indent_spaces (enum indent_mode mode); // Gets a string in a certain delim type. -std::string -get_string_in_delims (std::string str_input, DelimType delim_type); +std::string get_string_in_delims (std::string str_input, DelimType delim_type); -std::string -get_mode_dump_desc (AttrMode mode); +std::string get_mode_dump_desc (AttrMode mode); // Adds lines below adding attributes -std::string -append_attributes (std::vector<Attribute> attrs, AttrMode mode); +std::string append_attributes (std::vector<Attribute> attrs, AttrMode mode); // Removes the beginning and end quotes of a quoted string. -std::string -unquote_string (std::string input); +std::string unquote_string (std::string input); } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index 9359248..09706ce 100644 --- a/gcc/rust/ast/rust-ast-full-decls.h +++ b/gcc/rust/ast/rust-ast-full-decls.h @@ -78,7 +78,7 @@ class LiteralExpr; class AttrInputLiteral; class AttrInputMacro; class MetaItemLitExpr; -class MetaItemPathLit; +class MetaItemPathExpr; class OperatorExpr; class BorrowExpr; class DereferenceExpr; @@ -115,6 +115,8 @@ struct ClosureParam; class ClosureExpr; class ClosureExprInner; class BlockExpr; +class AnonConst; +class ConstBlock; class ClosureExprInnerTyped; class ContinueExpr; class BreakExpr; @@ -126,6 +128,7 @@ class RangeFullExpr; class RangeFromToInclExpr; class RangeToInclExpr; class ReturnExpr; +class TryExpr; class UnsafeBlockExpr; class LoopLabel; class BaseLoopExpr; @@ -146,7 +149,6 @@ class MatchExpr; class AwaitExpr; class AsyncBlockExpr; enum class InlineAsmOption; -struct AnonConst; struct InlineAsmRegOrRegClass; class InlineAsmOperand; struct InlineAsmPlaceHolder; @@ -246,6 +248,8 @@ class TuplePatternItemsMultiple; class TuplePatternItemsRanged; class TuplePattern; class GroupedPattern; +class SlicePatternItemsNoRest; +class SlicePatternItemsHasRest; class SlicePattern; class AltPattern; diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc index b6833f6..ab8cdbe 100644 --- a/gcc/rust/ast/rust-ast-visitor.cc +++ b/gcc/rust/ast/rust-ast-visitor.cc @@ -19,6 +19,7 @@ #include "rust-ast-visitor.h" #include "rust-ast-full-decls.h" #include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" #include "rust-path.h" #include "rust-token.h" #include "rust-expr.h" @@ -223,10 +224,10 @@ DefaultASTVisitor::visit (AST::SimplePath &path) } void -DefaultASTVisitor::visit (AST::MetaItemPathLit &meta_item) +DefaultASTVisitor::visit (AST::MetaItemPathExpr &meta_item) { visit (meta_item.get_path ()); - visit (meta_item.get_literal ()); + visit (meta_item.get_expr ()); } void @@ -449,20 +450,38 @@ DefaultASTVisitor::visit (AST::BlockExpr &expr) { visit_outer_attrs (expr); visit_inner_attrs (expr); + + if (expr.has_label ()) + visit (expr.get_label ()); + for (auto &stmt : expr.get_statements ()) visit (stmt); + if (expr.has_tail_expr ()) visit (expr.get_tail_expr ()); } void +DefaultASTVisitor::visit (AST::ConstBlock &expr) +{ + visit (expr.get_const_expr ()); +} + +void +DefaultASTVisitor::visit (AST::AnonConst &expr) +{ + if (!expr.is_deferred ()) + visit (expr.get_inner_expr ()); +} + +void DefaultASTVisitor::visit (AST::ClosureExprInnerTyped &expr) { visit_outer_attrs (expr); for (auto ¶m : expr.get_params ()) visit (param); visit (expr.get_return_type ()); - visit (expr.get_definition_block ()); + visit (expr.get_definition_expr ()); } void @@ -538,6 +557,13 @@ DefaultASTVisitor::visit (AST::ReturnExpr &expr) } void +DefaultASTVisitor::visit (AST::TryExpr &expr) +{ + visit_outer_attrs (expr); + visit (expr.get_block_expr ()); +} + +void DefaultASTVisitor::visit (AST::BoxExpr &expr) { visit_outer_attrs (expr); @@ -582,7 +608,10 @@ DefaultASTVisitor::visit (AST::WhileLetLoopExpr &expr) visit_outer_attrs (expr); for (auto &pattern : expr.get_patterns ()) visit (pattern); - visit (expr.get_loop_label ()); + + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); + visit (expr.get_scrutinee_expr ()); visit (expr.get_loop_block ()); } @@ -680,33 +709,40 @@ DefaultASTVisitor::visit (AST::InlineAsm &expr) { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { visit (operand.get_in ().expr); break; } - case RegisterType::Out: { + case RegisterType::Out: + { visit (operand.get_out ().expr); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { visit (operand.get_in_out ().expr); break; } - case RegisterType::SplitInOut: { + case RegisterType::SplitInOut: + { auto split = operand.get_split_in_out (); visit (split.in_expr); visit (split.out_expr); break; } - case RegisterType::Const: { - visit (operand.get_const ().anon_const.expr); + case RegisterType::Const: + { + visit (operand.get_const ().anon_const.get_inner_expr ()); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { visit (operand.get_sym ().expr); break; } - case RegisterType::Label: { + case RegisterType::Label: + { visit (operand.get_label ().expr); break; } @@ -755,7 +791,8 @@ DefaultASTVisitor::visit (AST::TypeBoundWhereClauseItem &item) void DefaultASTVisitor::visit (AST::Visibility &vis) { - visit (vis.get_path ()); + if (vis.has_path ()) + visit (vis.get_path ()); } void @@ -922,7 +959,7 @@ DefaultASTVisitor::visit (AST::EnumItem &item) void DefaultASTVisitor::visit (AST::EnumItemTuple &item) { - visit (reinterpret_cast<EnumItem &> (item)); + DefaultASTVisitor::visit (static_cast<EnumItem &> (item)); for (auto &field : item.get_tuple_fields ()) visit (field); } @@ -930,7 +967,7 @@ DefaultASTVisitor::visit (AST::EnumItemTuple &item) void DefaultASTVisitor::visit (AST::EnumItemStruct &item) { - visit (reinterpret_cast<EnumItem &> (item)); + DefaultASTVisitor::visit (static_cast<EnumItem &> (item)); for (auto &field : item.get_struct_fields ()) visit (field); } @@ -938,7 +975,7 @@ DefaultASTVisitor::visit (AST::EnumItemStruct &item) void DefaultASTVisitor::visit (AST::EnumItemDiscriminant &item) { - visit (reinterpret_cast<EnumItem &> (item)); + DefaultASTVisitor::visit (static_cast<EnumItem &> (item)); visit (item.get_expr ()); } @@ -1179,8 +1216,8 @@ DefaultASTVisitor::visit (AST::LiteralPattern &pattern) void DefaultASTVisitor::visit (AST::IdentifierPattern &pattern) { - if (pattern.has_pattern_to_bind ()) - visit (pattern.get_pattern_to_bind ()); + if (pattern.has_subpattern ()) + visit (pattern.get_subpattern ()); } void @@ -1310,13 +1347,28 @@ DefaultASTVisitor::visit (AST::GroupedPattern &pattern) } void -DefaultASTVisitor::visit (AST::SlicePattern &pattern) +DefaultASTVisitor::visit (AST::SlicePatternItemsNoRest &items) +{ + for (auto &item : items.get_patterns ()) + visit (item); +} + +void +DefaultASTVisitor::visit (AST::SlicePatternItemsHasRest &items) { - for (auto &item : pattern.get_items ()) + for (auto &item : items.get_lower_patterns ()) + visit (item); + for (auto &item : items.get_upper_patterns ()) visit (item); } void +DefaultASTVisitor::visit (AST::SlicePattern &pattern) +{ + visit (pattern.get_items ()); +} + +void DefaultASTVisitor::visit (AST::AltPattern &pattern) { for (auto &alt : pattern.get_alts ()) @@ -1454,6 +1506,12 @@ DefaultASTVisitor::visit (AST::FormatArgs &) } void +DefaultASTVisitor::visit (AST::OffsetOf &offset_of) +{ + visit (offset_of.get_type ()); +} + +void DefaultASTVisitor::visit (AST::VariadicParam ¶m) { if (param.has_pattern ()) diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h index b1fc504..2d81aa1 100644 --- a/gcc/rust/ast/rust-ast-visitor.h +++ b/gcc/rust/ast/rust-ast-visitor.h @@ -73,7 +73,7 @@ public: virtual void visit (AttrInputLiteral &attr_input) = 0; virtual void visit (AttrInputMacro &attr_input) = 0; virtual void visit (MetaItemLitExpr &meta_item) = 0; - virtual void visit (MetaItemPathLit &meta_item) = 0; + virtual void visit (MetaItemPathExpr &meta_item) = 0; virtual void visit (BorrowExpr &expr) = 0; virtual void visit (DereferenceExpr &expr) = 0; virtual void visit (ErrorPropagationExpr &expr) = 0; @@ -104,6 +104,8 @@ public: virtual void visit (FieldAccessExpr &expr) = 0; virtual void visit (ClosureExprInner &expr) = 0; virtual void visit (BlockExpr &expr) = 0; + virtual void visit (AnonConst &expr) = 0; + virtual void visit (ConstBlock &expr) = 0; virtual void visit (ClosureExprInnerTyped &expr) = 0; virtual void visit (ContinueExpr &expr) = 0; virtual void visit (BreakExpr &expr) = 0; @@ -114,6 +116,7 @@ public: virtual void visit (RangeFromToInclExpr &expr) = 0; virtual void visit (RangeToInclExpr &expr) = 0; virtual void visit (ReturnExpr &expr) = 0; + virtual void visit (TryExpr &expr) = 0; virtual void visit (BoxExpr &expr) = 0; virtual void visit (UnsafeBlockExpr &expr) = 0; virtual void visit (LoopExpr &expr) = 0; @@ -209,6 +212,8 @@ public: virtual void visit (TuplePatternItemsRanged &tuple_items) = 0; virtual void visit (TuplePattern &pattern) = 0; virtual void visit (GroupedPattern &pattern) = 0; + virtual void visit (SlicePatternItemsNoRest &items) = 0; + virtual void visit (SlicePatternItemsHasRest &items) = 0; virtual void visit (SlicePattern &pattern) = 0; virtual void visit (AltPattern &pattern) = 0; @@ -235,6 +240,7 @@ public: // special AST nodes for certain builtin macros such as `asm!()` virtual void visit (FormatArgs &fmt) = 0; + virtual void visit (OffsetOf &fmt) = 0; // TODO: rust-cond-compilation.h visiting? not currently used }; @@ -264,7 +270,7 @@ public: virtual void visit (AST::AttrInputLiteral &attr_input) override; virtual void visit (AST::AttrInputMacro &attr_input) override; virtual void visit (AST::MetaItemLitExpr &meta_item) override; - virtual void visit (AST::MetaItemPathLit &meta_item) override; + virtual void visit (AST::MetaItemPathExpr &meta_item) override; virtual void visit (AST::BorrowExpr &expr) override; virtual void visit (AST::DereferenceExpr &expr) override; virtual void visit (AST::ErrorPropagationExpr &expr) override; @@ -293,6 +299,8 @@ public: virtual void visit (AST::FieldAccessExpr &expr) override; virtual void visit (AST::ClosureExprInner &expr) override; virtual void visit (AST::BlockExpr &expr) override; + virtual void visit (AST::AnonConst &expr) override; + virtual void visit (AST::ConstBlock &expr) override; virtual void visit (AST::ClosureExprInnerTyped &expr) override; virtual void visit (AST::ContinueExpr &expr) override; virtual void visit (AST::BreakExpr &expr) override; @@ -303,6 +311,7 @@ public: virtual void visit (AST::RangeFromToInclExpr &expr) override; virtual void visit (AST::RangeToInclExpr &expr) override; virtual void visit (AST::ReturnExpr &expr) override; + virtual void visit (AST::TryExpr &expr) override; virtual void visit (AST::BoxExpr &expr) override; virtual void visit (AST::UnsafeBlockExpr &expr) override; virtual void visit (AST::LoopExpr &expr) override; @@ -379,6 +388,8 @@ public: virtual void visit (AST::TuplePatternItemsRanged &tuple_items) override; virtual void visit (AST::TuplePattern &pattern) override; virtual void visit (AST::GroupedPattern &pattern) override; + virtual void visit (AST::SlicePatternItemsNoRest &items) override; + virtual void visit (AST::SlicePatternItemsHasRest &items) override; virtual void visit (AST::SlicePattern &pattern) override; virtual void visit (AST::AltPattern &pattern) override; virtual void visit (AST::EmptyStmt &stmt) override; @@ -402,6 +413,7 @@ public: virtual void visit (AST::FunctionParam ¶m) override; virtual void visit (AST::VariadicParam ¶m) override; virtual void visit (AST::FormatArgs &fmt) override; + virtual void visit (AST::OffsetOf &fmt) override; template <typename T> void visit (T &node) { node.accept_vis (*this); } diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 4e82be4..8e856fb 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "rust-operators.h" #include "rust-dir-owner.h" #include "rust-attribute-values.h" +#include "rust-macro-invoc-lexer.h" /* Compilation unit used for various AST-related functions that would make * the headers too long if they were defined inline and don't receive any @@ -249,27 +250,31 @@ Attribute::get_traits_to_derive () auto &input = get_attr_input (); switch (input.get_attr_input_type ()) { - case AST::AttrInput::META_ITEM: { + case AST::AttrInput::META_ITEM: + { auto &meta = static_cast<AST::AttrInputMetaItemContainer &> (input); for (auto ¤t : meta.get_items ()) { // HACK: Find a better way to achieve the downcast. switch (current->get_kind ()) { - case AST::MetaItemInner::Kind::MetaItem: { + case AST::MetaItemInner::Kind::MetaItem: + { // Let raw pointer go out of scope without freeing, it doesn't // own the data anyway auto meta_item = static_cast<AST::MetaItem *> (current.get ()); switch (meta_item->get_item_kind ()) { - case AST::MetaItem::ItemKind::Path: { + case AST::MetaItem::ItemKind::Path: + { auto path = static_cast<AST::MetaItemPath *> (meta_item); result.push_back (path->get_path ()); } break; - case AST::MetaItem::ItemKind::Word: { + case AST::MetaItem::ItemKind::Word: + { auto word = static_cast<AST::MetaWord *> (meta_item); // Convert current word to path current = std::make_unique<AST::MetaItemPath> ( @@ -283,7 +288,7 @@ Attribute::get_traits_to_derive () break; case AST::MetaItem::ItemKind::ListPaths: case AST::MetaItem::ItemKind::NameValueStr: - case AST::MetaItem::ItemKind::PathLit: + case AST::MetaItem::ItemKind::PathExpr: case AST::MetaItem::ItemKind::Seq: case AST::MetaItem::ItemKind::ListNameValueStr: default: @@ -620,7 +625,7 @@ ConstantItem::as_string () const { std::string str = VisItem::as_string (); - str += "const " + identifier; + str += "const " + identifier.as_string (); // DEBUG: null pointer check if (type == nullptr) @@ -782,7 +787,8 @@ UseTreeGlob::as_string () const return "*"; case GLOBAL: return "::*"; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { std::string path_str = path.as_string (); return path_str + "::*"; } @@ -805,7 +811,8 @@ UseTreeList::as_string () const case GLOBAL: path_str = "::{"; break; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { path_str = path.as_string () + "::{"; break; } @@ -1272,6 +1279,25 @@ BlockExpr::as_string () const } std::string +AnonConst::as_string () const +{ + std::string str = "AnonConst: "; + + if (kind == AnonConst::Kind::DeferredInference) + str += "_"; + else + str += expr.value ()->as_string (); + + return str; +} + +std::string +ConstBlock::as_string () const +{ + return "ConstBlock: " + expr.as_string (); +} + +std::string TraitImpl::as_string () const { std::string str = VisItem::as_string (); @@ -1619,6 +1645,19 @@ ReturnExpr::as_string () const } std::string +TryExpr::as_string () const +{ + /* TODO: find way to incorporate outer attrs - may have to represent in + * different style (i.e. something more like BorrowExpr: \n outer attrs) */ + + std::string str ("try "); + + str += block_expr->as_string (); + + return str; +} + +std::string RangeToExpr::as_string () const { return ".." + to->as_string (); @@ -2714,7 +2753,7 @@ ImplTraitTypeOneBound::as_string () const { std::string str ("ImplTraitTypeOneBound: \n TraitBound: "); - return str + trait_bound.as_string (); + return str + trait_bound->as_string (); } std::string @@ -2736,7 +2775,7 @@ std::string ArrayType::as_string () const { // TODO: rewrite to work with non-linearisable types and exprs - return "[" + elem_type->as_string () + "; " + size->as_string () + "]"; + return "[" + elem_type->as_string () + "; " + size.as_string () + "]"; } std::string @@ -3477,13 +3516,24 @@ DelimTokenTree::parse_to_meta_item () const return new AttrInputMetaItemContainer (std::move (meta_items)); } +AttributeParser::AttributeParser ( + std::vector<std::unique_ptr<Token>> token_stream, int stream_start_pos) + : lexer (new MacroInvocLexer (std::move (token_stream))), + parser (new Parser<MacroInvocLexer> (*lexer)) +{ + if (stream_start_pos) + lexer->skip_token (stream_start_pos - 1); +} + +AttributeParser::~AttributeParser () {} + std::unique_ptr<MetaItemInner> AttributeParser::parse_meta_item_inner () { // if first tok not identifier, not a "special" case one - if (peek_token ()->get_id () != IDENTIFIER) + if (lexer->peek_token ()->get_id () != IDENTIFIER) { - switch (peek_token ()->get_id ()) + switch (lexer->peek_token ()->get_id ()) { case CHAR_LITERAL: case STRING_LITERAL: @@ -3504,48 +3554,46 @@ AttributeParser::parse_meta_item_inner () return parse_path_meta_item (); default: - rust_error_at (peek_token ()->get_locus (), + rust_error_at (lexer->peek_token ()->get_locus (), "unrecognised token '%s' in meta item", - get_token_description (peek_token ()->get_id ())); + get_token_description ( + lexer->peek_token ()->get_id ())); return nullptr; } } // else, check for path - if (peek_token (1)->get_id () == SCOPE_RESOLUTION) + if (lexer->peek_token (1)->get_id () == SCOPE_RESOLUTION) { // path return parse_path_meta_item (); } - auto ident = peek_token ()->as_string (); - auto ident_locus = peek_token ()->get_locus (); + auto ident = lexer->peek_token ()->get_str (); + auto ident_locus = lexer->peek_token ()->get_locus (); - if (is_end_meta_item_tok (peek_token (1)->get_id ())) + if (is_end_meta_item_tok (lexer->peek_token (1)->get_id ())) { // meta word syntax - skip_token (); + lexer->skip_token (); return std::unique_ptr<MetaWord> (new MetaWord (ident, ident_locus)); } - if (peek_token (1)->get_id () == EQUAL) + if (lexer->peek_token (1)->get_id () == EQUAL) { // maybe meta name value str syntax - check next 2 tokens - if (peek_token (2)->get_id () == STRING_LITERAL - && is_end_meta_item_tok (peek_token (3)->get_id ())) + if (lexer->peek_token (2)->get_id () == STRING_LITERAL + && is_end_meta_item_tok (lexer->peek_token (3)->get_id ())) { // meta name value str syntax - auto &value_tok = peek_token (2); - auto value = value_tok->as_string (); + const_TokenPtr value_tok = lexer->peek_token (2); + auto value = value_tok->get_str (); auto locus = value_tok->get_locus (); - skip_token (2); - - // remove the quotes from the string value - std::string raw_value = unquote_string (std::move (value)); + lexer->skip_token (2); return std::unique_ptr<MetaNameValueStr> ( - new MetaNameValueStr (ident, ident_locus, std::move (raw_value), + new MetaNameValueStr (ident, ident_locus, std::move (value), locus)); } else @@ -3555,16 +3603,16 @@ AttributeParser::parse_meta_item_inner () } } - if (peek_token (1)->get_id () != LEFT_PAREN) + if (lexer->peek_token (1)->get_id () != LEFT_PAREN) { - rust_error_at (peek_token (1)->get_locus (), + rust_error_at (lexer->peek_token (1)->get_locus (), "unexpected token '%s' after identifier in attribute", - get_token_description (peek_token (1)->get_id ())); + get_token_description (lexer->peek_token (1)->get_id ())); return nullptr; } // is it one of those special cases like not? - if (peek_token ()->get_id () == IDENTIFIER) + if (lexer->peek_token ()->get_id () == IDENTIFIER) { return parse_path_meta_item (); } @@ -3643,49 +3691,46 @@ AttributeParser::is_end_meta_item_tok (TokenId id) const std::unique_ptr<MetaItem> AttributeParser::parse_path_meta_item () { - SimplePath path = parse_simple_path (); + SimplePath path = parser->parse_simple_path (); if (path.is_empty ()) { - rust_error_at (peek_token ()->get_locus (), + rust_error_at (lexer->peek_token ()->get_locus (), "failed to parse simple path in attribute"); return nullptr; } - switch (peek_token ()->get_id ()) + switch (lexer->peek_token ()->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { std::vector<std::unique_ptr<MetaItemInner>> meta_items = parse_meta_item_seq (); return std::unique_ptr<MetaItemSeq> ( new MetaItemSeq (std::move (path), std::move (meta_items))); } - case EQUAL: { - skip_token (); + case EQUAL: + { + lexer->skip_token (); - location_t locus = peek_token ()->get_locus (); - Literal lit = parse_literal (); - if (lit.is_error ()) - { - rust_error_at (peek_token ()->get_locus (), - "failed to parse literal in attribute"); - return nullptr; - } - LiteralExpr expr (std::move (lit), {}, locus); - // stream_pos++; - /* shouldn't be required anymore due to parsing literal actually - * skipping the token */ - return std::unique_ptr<MetaItemPathLit> ( - new MetaItemPathLit (std::move (path), std::move (expr))); + std::unique_ptr<Expr> expr = parser->parse_expr (); + + // handle error + // parse_expr should already emit an error and return nullptr + if (!expr) + return nullptr; + + return std::unique_ptr<MetaItemPathExpr> ( + new MetaItemPathExpr (std::move (path), std::move (expr))); } case COMMA: // just simple path return std::unique_ptr<MetaItemPath> ( new MetaItemPath (std::move (path))); default: - rust_error_at (peek_token ()->get_locus (), + rust_error_at (lexer->peek_token ()->get_locus (), "unrecognised token '%s' in meta item", - get_token_description (peek_token ()->get_id ())); + get_token_description (lexer->peek_token ()->get_id ())); return nullptr; } } @@ -3695,41 +3740,41 @@ AttributeParser::parse_path_meta_item () std::vector<std::unique_ptr<MetaItemInner>> AttributeParser::parse_meta_item_seq () { - int vec_length = token_stream.size (); std::vector<std::unique_ptr<MetaItemInner>> meta_items; - if (peek_token ()->get_id () != LEFT_PAREN) + if (lexer->peek_token ()->get_id () != LEFT_PAREN) { - rust_error_at (peek_token ()->get_locus (), + rust_error_at (lexer->peek_token ()->get_locus (), "missing left paren in delim token tree"); return {}; } - skip_token (); + lexer->skip_token (); - while (stream_pos < vec_length && peek_token ()->get_id () != RIGHT_PAREN) + while (lexer->peek_token ()->get_id () != END_OF_FILE + && lexer->peek_token ()->get_id () != RIGHT_PAREN) { std::unique_ptr<MetaItemInner> inner = parse_meta_item_inner (); if (inner == nullptr) { - rust_error_at (peek_token ()->get_locus (), + rust_error_at (lexer->peek_token ()->get_locus (), "failed to parse inner meta item in attribute"); return {}; } meta_items.push_back (std::move (inner)); - if (peek_token ()->get_id () != COMMA) + if (lexer->peek_token ()->get_id () != COMMA) break; - skip_token (); + lexer->skip_token (); } - if (peek_token ()->get_id () != RIGHT_PAREN) + if (lexer->peek_token ()->get_id () != RIGHT_PAREN) { - rust_error_at (peek_token ()->get_locus (), + rust_error_at (lexer->peek_token ()->get_locus (), "missing right paren in delim token tree"); return {}; } - skip_token (); + lexer->skip_token (); return meta_items; } @@ -3752,130 +3797,19 @@ DelimTokenTree::to_token_stream () const return tokens; } -Literal -AttributeParser::parse_literal () -{ - const std::unique_ptr<Token> &tok = peek_token (); - switch (tok->get_id ()) - { - case CHAR_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::CHAR, tok->get_type_hint ()); - case STRING_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::STRING, - tok->get_type_hint ()); - case BYTE_CHAR_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::BYTE, tok->get_type_hint ()); - case BYTE_STRING_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::BYTE_STRING, - tok->get_type_hint ()); - case RAW_STRING_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::RAW_STRING, - tok->get_type_hint ()); - case INT_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::INT, tok->get_type_hint ()); - case FLOAT_LITERAL: - skip_token (); - return Literal (tok->as_string (), Literal::FLOAT, tok->get_type_hint ()); - case TRUE_LITERAL: - skip_token (); - return Literal ("true", Literal::BOOL, tok->get_type_hint ()); - case FALSE_LITERAL: - skip_token (); - return Literal ("false", Literal::BOOL, tok->get_type_hint ()); - default: - rust_error_at (tok->get_locus (), "expected literal - found '%s'", - get_token_description (tok->get_id ())); - return Literal::create_error (); - } -} - -SimplePath -AttributeParser::parse_simple_path () -{ - bool has_opening_scope_res = false; - if (peek_token ()->get_id () == SCOPE_RESOLUTION) - { - has_opening_scope_res = true; - skip_token (); - } - - std::vector<SimplePathSegment> segments; - - SimplePathSegment segment = parse_simple_path_segment (); - if (segment.is_error ()) - { - rust_error_at ( - peek_token ()->get_locus (), - "failed to parse simple path segment in attribute simple path"); - return SimplePath::create_empty (); - } - segments.push_back (std::move (segment)); - - while (peek_token ()->get_id () == SCOPE_RESOLUTION) - { - skip_token (); - - SimplePathSegment segment = parse_simple_path_segment (); - if (segment.is_error ()) - { - rust_error_at ( - peek_token ()->get_locus (), - "failed to parse simple path segment in attribute simple path"); - return SimplePath::create_empty (); - } - segments.push_back (std::move (segment)); - } - segments.shrink_to_fit (); - - return SimplePath (std::move (segments), has_opening_scope_res); -} - -SimplePathSegment -AttributeParser::parse_simple_path_segment () -{ - const std::unique_ptr<Token> &tok = peek_token (); - switch (tok->get_id ()) - { - case IDENTIFIER: - skip_token (); - return SimplePathSegment (tok->as_string (), tok->get_locus ()); - case SUPER: - skip_token (); - return SimplePathSegment ("super", tok->get_locus ()); - case SELF: - skip_token (); - return SimplePathSegment ("self", tok->get_locus ()); - case CRATE: - skip_token (); - return SimplePathSegment ("crate", tok->get_locus ()); - case DOLLAR_SIGN: - if (peek_token (1)->get_id () == CRATE) - { - skip_token (1); - return SimplePathSegment ("$crate", tok->get_locus ()); - } - gcc_fallthrough (); - default: - rust_error_at (tok->get_locus (), - "unexpected token '%s' in simple path segment", - get_token_description (tok->get_id ())); - return SimplePathSegment::create_error (); - } -} - std::unique_ptr<MetaItemLitExpr> AttributeParser::parse_meta_item_lit () { - location_t locus = peek_token ()->get_locus (); - LiteralExpr lit_expr (parse_literal (), {}, locus); + std::unique_ptr<LiteralExpr> lit_expr = parser->parse_literal_expr ({}); + + // TODO: return nullptr instead? + if (!lit_expr) + lit_expr = std::unique_ptr<LiteralExpr> ( + new LiteralExpr (Literal::create_error (), {}, + lexer->peek_token ()->get_locus ())); + return std::unique_ptr<MetaItemLitExpr> ( - new MetaItemLitExpr (std::move (lit_expr))); + new MetaItemLitExpr (std::move (*lit_expr))); } bool @@ -4084,10 +4018,12 @@ MetaNameValueStr::check_cfg_predicate (const Session &session) const } bool -MetaItemPathLit::check_cfg_predicate (const Session &session) const +MetaItemPathExpr::check_cfg_predicate (const Session &session) const { + // FIXME: Accept path expressions + rust_assert (expr->is_literal ()); return session.options.target_data.has_key_value_pair (path.as_string (), - lit.as_string ()); + expr->as_string ()); } std::vector<std::unique_ptr<Token>> @@ -4175,8 +4111,10 @@ MetaListNameValueStr::to_attribute () const } Attribute -MetaItemPathLit::to_attribute () const +MetaItemPathExpr::to_attribute () const { + rust_assert (expr->is_literal ()); + auto &lit = static_cast<LiteralExpr &> (*expr); return Attribute (path, std::unique_ptr<AttrInputLiteral> ( new AttrInputLiteral (lit))); } @@ -4279,11 +4217,12 @@ AttrInputMacro::AttrInputMacro (const AttrInputMacro &oth) : macro (oth.macro->clone_macro_invocation_impl ()) {} -void +AttrInputMacro & AttrInputMacro::operator= (const AttrInputMacro &oth) { macro = std::unique_ptr<MacroInvocation> ( oth.macro->clone_macro_invocation_impl ()); + return *this; } /* Visitor implementations - these are short but inlining can't happen anyway @@ -4345,7 +4284,7 @@ MetaItemLitExpr::accept_vis (ASTVisitor &vis) } void -MetaItemPathLit::accept_vis (ASTVisitor &vis) +MetaItemPathExpr::accept_vis (ASTVisitor &vis) { vis.visit (*this); } @@ -4513,6 +4452,18 @@ BlockExpr::accept_vis (ASTVisitor &vis) } void +AnonConst::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstBlock::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void ClosureExprInnerTyped::accept_vis (ASTVisitor &vis) { vis.visit (*this); @@ -4573,6 +4524,12 @@ ReturnExpr::accept_vis (ASTVisitor &vis) } void +TryExpr::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void UnsafeBlockExpr::accept_vis (ASTVisitor &vis) { vis.visit (*this); @@ -5010,6 +4967,12 @@ FormatArgs::accept_vis (ASTVisitor &vis) vis.visit (*this); } +void +OffsetOf::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + std::string FormatArgs::as_string () const { @@ -5017,6 +4980,12 @@ FormatArgs::as_string () const return "FormatArgs"; } +std::string +OffsetOf::as_string () const +{ + return "OffsetOf(" + type->as_string () + ", " + field.as_string () + ")"; +} + location_t FormatArgs::get_locus () const { @@ -5047,7 +5016,8 @@ FormatArgs::get_outer_attrs () rust_unreachable (); } -void FormatArgs::set_outer_attrs (std::vector<Attribute>) +void +FormatArgs::set_outer_attrs (std::vector<Attribute>) { rust_unreachable (); } @@ -5060,6 +5030,24 @@ FormatArgs::clone_expr_impl () const return new FormatArgs (*this); } +std::vector<Attribute> & +OffsetOf::get_outer_attrs () +{ + rust_unreachable (); +} + +void +OffsetOf::set_outer_attrs (std::vector<Attribute>) +{ + rust_unreachable (); +} + +Expr * +OffsetOf::clone_expr_impl () const +{ + return new OffsetOf (*this); +} + } // namespace AST std::ostream & diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index aa6ad50..2d2c5d0 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -62,13 +62,14 @@ public: return ident == other.ident; } + operator const std::string & () const { return ident; } + private: std::string ident; location_t loc; }; -std::ostream & -operator<< (std::ostream &os, Identifier const &i); +std::ostream &operator<< (std::ostream &os, Identifier const &i); namespace AST { // foward decl: ast visitor @@ -82,6 +83,38 @@ public: virtual void accept_vis (ASTVisitor &vis) = 0; }; +/** + * Base function for reconstructing and asserting that the new NodeId is + * different from the old NodeId. It then wraps the given pointer into a unique + * pointer and returns it. + */ +template <typename T> +std::unique_ptr<T> +reconstruct_base (const T *instance) +{ + auto *reconstructed = instance->reconstruct_impl (); + + rust_assert (reconstructed->get_node_id () != instance->get_node_id ()); + + return std::unique_ptr<T> (reconstructed); +} + +/** + * Reconstruct multiple items in a vector + */ +template <typename T> +std::vector<std::unique_ptr<T>> +reconstruct_vec (const std::vector<std::unique_ptr<T>> &to_reconstruct) +{ + std::vector<std::unique_ptr<T>> reconstructed; + reconstructed.reserve (to_reconstruct.size ()); + + for (const auto &elt : to_reconstruct) + reconstructed.emplace_back (std::unique_ptr<T> (elt->reconstruct_impl ())); + + return reconstructed; +} + // Delimiter types - used in macros and whatever. enum DelimType { @@ -250,6 +283,7 @@ public: std::vector<std::unique_ptr<Token>> to_token_stream () const override; TokenId get_id () const { return tok_ref->get_id (); } + bool has_str () const { return tok_ref->has_str (); } const std::string &get_str () const { return tok_ref->get_str (); } location_t get_locus () const { return tok_ref->get_locus (); } @@ -403,15 +437,15 @@ class SimplePath public: // Constructor - SimplePath (std::vector<SimplePathSegment> path_segments, - bool has_opening_scope_resolution = false, - location_t locus = UNDEF_LOCATION) + explicit SimplePath (std::vector<SimplePathSegment> path_segments, + bool has_opening_scope_resolution = false, + location_t locus = UNDEF_LOCATION) : opening_scope_resolution (has_opening_scope_resolution), segments (std::move (path_segments)), locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} - SimplePath (Identifier ident) + explicit SimplePath (Identifier ident) : opening_scope_resolution (false), segments ({SimplePathSegment (ident.as_string (), ident.get_locus ())}), locus (ident.get_locus ()), @@ -1039,7 +1073,7 @@ public: Path, Word, NameValueStr, - PathLit, + PathExpr, Seq, ListPaths, ListNameValueStr, @@ -1057,7 +1091,7 @@ public: class MetaItemLitExpr; // Forward decl - defined in rust-expr.h -class MetaItemPathLit; +class MetaItemPathExpr; // Forward decl - defined in rust-macro.h class MetaItemPath; @@ -1256,6 +1290,8 @@ public: FieldAccess, Closure, Block, + ConstExpr, + ConstBlock, Continue, Break, Range, @@ -1272,6 +1308,7 @@ public: LlvmInlineAsm, Identifier, FormatArgs, + OffsetOf, MacroInvocation, Borrow, Dereference, @@ -1283,6 +1320,7 @@ public: TypeCast, Assignment, CompoundAssignment, + Try, }; virtual Kind get_expr_kind () const = 0; @@ -1477,6 +1515,10 @@ public: return std::unique_ptr<Type> (clone_type_impl ()); } + // Similar to `clone_type`, but generates a new instance of the node with a + // different NodeId + std::unique_ptr<Type> reconstruct () const { return reconstruct_base (this); } + // virtual destructor virtual ~Type () {} @@ -1495,11 +1537,13 @@ public: virtual location_t get_locus () const = 0; NodeId get_node_id () const { return node_id; } + virtual Type *reconstruct_impl () const = 0; protected: Type () : node_id (Analysis::Mappings::get ().get_next_node_id ()) {} + Type (NodeId node_id) : node_id (node_id) {} - // Clone function implementation as pure virtual method + // Clone and reconstruct function implementations as pure virtual methods virtual Type *clone_type_impl () const = 0; NodeId node_id; @@ -1515,6 +1559,13 @@ public: return std::unique_ptr<TypeNoBounds> (clone_type_no_bounds_impl ()); } + std::unique_ptr<TypeNoBounds> reconstruct () const + { + return reconstruct_base (this); + } + + virtual TypeNoBounds *reconstruct_impl () const override = 0; + protected: // Clone function implementation as pure virtual method virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0; @@ -1549,6 +1600,11 @@ public: return std::unique_ptr<TypeParamBound> (clone_type_param_bound_impl ()); } + std::unique_ptr<TypeParamBound> reconstruct () const + { + return reconstruct_base (this); + } + virtual std::string as_string () const = 0; NodeId get_node_id () const { return node_id; } @@ -1557,10 +1613,14 @@ public: virtual TypeParamBoundType get_bound_type () const = 0; + virtual TypeParamBound *reconstruct_impl () const = 0; + protected: // Clone function implementation as pure virtual method virtual TypeParamBound *clone_type_param_bound_impl () const = 0; + TypeParamBound () : node_id (Analysis::Mappings::get ().get_next_node_id ()) + {} TypeParamBound (NodeId node_id) : node_id (node_id) {} NodeId node_id; @@ -1622,6 +1682,10 @@ protected: { return new Lifetime (node_id, lifetime_type, lifetime_name, locus); } + Lifetime *reconstruct_impl () const override + { + return new Lifetime (lifetime_type, lifetime_name, locus); + } }; /* Base generic parameter in AST. Abstract - can be represented by a Lifetime diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h index 3684092..2893e7b 100644 --- a/gcc/rust/ast/rust-builtin-ast-nodes.h +++ b/gcc/rust/ast/rust-builtin-ast-nodes.h @@ -225,6 +225,59 @@ protected: virtual Expr *clone_expr_impl () const override; }; +/** + * The node associated with the builtin offset_of!() macro + */ +class OffsetOf : public Expr +{ +public: + OffsetOf (std::unique_ptr<Type> &&type, Identifier field, location_t loc) + : type (std::move (type)), field (field), loc (loc) + {} + + OffsetOf (const OffsetOf &other) + : type (other.type->clone_type ()), field (other.field), loc (other.loc), + marked_for_strip (other.marked_for_strip) + {} + + OffsetOf &operator= (const OffsetOf &other) + { + type = other.type->clone_type (); + field = other.field; + loc = other.loc; + marked_for_strip = other.marked_for_strip; + + return *this; + } + + void accept_vis (AST::ASTVisitor &vis) override; + + virtual location_t get_locus () const override { return loc; } + const Type &get_type () const { return *type; } + Type &get_type () { return *type; } + const Identifier &get_field () const { return field; } + + bool is_expr_without_block () const override { return false; } + + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + std::string as_string () const override; + + std::vector<Attribute> &get_outer_attrs () override; + void set_outer_attrs (std::vector<Attribute>) override; + Expr *clone_expr_impl () const override; + + Expr::Kind get_expr_kind () const override { return Expr::Kind::OffsetOf; } + +private: + std::unique_ptr<Type> type; + Identifier field; + + location_t loc; + bool marked_for_strip = false; +}; + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-collect-lang-items.cc b/gcc/rust/ast/rust-collect-lang-items.cc index cd6be7f..306c6f7 100644 --- a/gcc/rust/ast/rust-collect-lang-items.cc +++ b/gcc/rust/ast/rust-collect-lang-items.cc @@ -109,5 +109,29 @@ CollectLangItems::visit (AST::EnumItem &item) DefaultASTVisitor::visit (item); } +void +CollectLangItems::visit (AST::EnumItemTuple &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::EnumItemStruct &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + +void +CollectLangItems::visit (AST::EnumItemDiscriminant &item) +{ + maybe_add_lang_item (item); + + DefaultASTVisitor::visit (item); +} + } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-collect-lang-items.h b/gcc/rust/ast/rust-collect-lang-items.h index ddb34a9..ddc7b51 100644 --- a/gcc/rust/ast/rust-collect-lang-items.h +++ b/gcc/rust/ast/rust-collect-lang-items.h @@ -50,6 +50,9 @@ public: void visit (AST::Function &item) override; void visit (AST::StructStruct &item) override; void visit (AST::EnumItem &item) override; + void visit (AST::EnumItemTuple &item) override; + void visit (AST::EnumItemStruct &item) override; + void visit (AST::EnumItemDiscriminant &item) override; private: template <typename T> void maybe_add_lang_item (const T &item); diff --git a/gcc/rust/ast/rust-cond-compilation.h b/gcc/rust/ast/rust-cond-compilation.h index 610b904..56a5646 100644 --- a/gcc/rust/ast/rust-cond-compilation.h +++ b/gcc/rust/ast/rust-cond-compilation.h @@ -42,8 +42,8 @@ public: protected: // Clone function impl to be overriden in base classes - virtual ConfigurationPredicate * - clone_configuration_predicate_impl () const = 0; + virtual ConfigurationPredicate *clone_configuration_predicate_impl () const + = 0; }; // A configuration option - true if option is set, false if option is not set. diff --git a/gcc/rust/ast/rust-desugar-apit.cc b/gcc/rust/ast/rust-desugar-apit.cc new file mode 100644 index 0000000..bca14ee --- /dev/null +++ b/gcc/rust/ast/rust-desugar-apit.cc @@ -0,0 +1,522 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-desugar-apit.h" +#include "rust-ast.h" +#include "rust-type.h" + +namespace Rust { +namespace AST { + +class DesugarApitType : public DefaultASTVisitor +{ + using DefaultASTVisitor::visit; + +public: + static std::pair<AST::Type *, std::vector<std::unique_ptr<GenericParam>>> + Desugar (AST::Type &type) + { + DesugarApitType visitor (&type); + type.accept_vis (visitor); + rust_assert (visitor.translated != nullptr); + return std::make_pair (visitor.translated, + std::move (visitor.implicit_generic_params)); + } + + // Generate a unique impl trait parameter name + static Identifier get_impl_name () + { + static size_t counter = 0; + return Identifier ("Impl_" + std::to_string (counter++)); + } + + // these can hold other types + void visit (AST::TupleType &tuple) override + { + for (auto &elem : tuple.get_elems ()) + { + auto &type = *elem.get (); + auto desugar = Desugar (type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + continue; + + if (tt != elem.get ()) + elem = std::unique_ptr<Type> (tt); + + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + } + + void visit (AST::ArrayType &type) override + { + auto &element_type = type.get_element_type (); + auto desugar = Desugar (*element_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + if (tt != element_type.get ()) + element_type = std::unique_ptr<AST::Type> (tt); + + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::ReferenceType &type) override + { + // Get a reference to the current type for in-place modification + auto &referenced_type = type.get_type_referenced (); + auto desugar = Desugar (referenced_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + // Update the reference type's contents rather than creating a new one + if (&referenced_type != tt) + { + std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds ( + static_cast<AST::TypeNoBounds *> (tt)); + type.get_type_ptr () = std::move (new_type_no_bounds); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::RawPointerType &type) override + { + auto &pointed_type = type.get_type_pointed_to (); + auto desugar = Desugar (pointed_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + // Update the pointer's inner type directly using the new accessor + if (&pointed_type != tt) + { + std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds ( + static_cast<AST::TypeNoBounds *> (tt)); + type.get_type_ptr () = std::move (new_type_no_bounds); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::SliceType &type) override + { + auto &element_type = type.get_elem_type (); + auto desugar = Desugar (element_type); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + if (&element_type != tt) + { + std::unique_ptr<AST::Type> new_elem_type (tt); + type.get_elem_type_ptr () = std::move (new_elem_type); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + void visit (AST::ParenthesisedType &type) override + { + auto &inner_type_ptr = type.get_type_in_parens (); + auto desugar = Desugar (*inner_type_ptr); + auto tt = desugar.first; + + auto &implicit_generics = desugar.second; + if (implicit_generics.empty ()) + return; + + if (inner_type_ptr.get () != tt) + { + std::unique_ptr<AST::Type> new_inner_type (tt); + inner_type_ptr = std::move (new_inner_type); + } + + // Collect all the implicit generic parameters we found + for (auto &implicit_generic : implicit_generics) + implicit_generic_params.push_back (std::move (implicit_generic)); + } + + // this is where the desugar happens + void visit (AST::ImplTraitType &type) override + { + // Generate a unique name using the static method + auto ident = get_impl_name (); + + // Create a type path for the new generic parameter + // Create a SimplePathSegment with the identifier string + auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ()); + // Create a vector of SimplePathSegments for SimplePath constructor + std::vector<SimplePathSegment> simple_segs = {simple_seg}; + // Create a SimplePath + auto simple_path = SimplePath (simple_segs, false, type.get_locus ()); + + // Convert to TypePath by creating path segments + std::vector<std::unique_ptr<TypePathSegment>> segments; + segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment ( + PathIdentSegment (ident.as_string (), type.get_locus ()), false, + type.get_locus ()))); + + // Create TypePath from segments + auto type_path + = new TypePath (std::move (segments), type.get_locus (), false); + + // Convert bounds from impl trait to generic parameter bounds + std::vector<std::unique_ptr<TypeParamBound>> bounds; + for (auto &bound : type.get_type_param_bounds ()) + bounds.push_back (bound->clone_type_param_bound ()); + + // Create the new generic parameter + auto generic_param = std::unique_ptr<TypeParam> ( + new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {}, + true /*from impl trait*/)); + + // Store the generic parameter to be added to the function signature + implicit_generic_params.push_back (std::move (generic_param)); + + // Replace impl trait with the new type parameter + translated = type_path; + } + + void visit (AST::ImplTraitTypeOneBound &type) override + { + // Generate a unique name using the static method + auto ident = get_impl_name (); + + // Create a type path for the new generic parameter + // Create a SimplePathSegment with the identifier string + auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus ()); + // Create a vector of SimplePathSegments for SimplePath constructor + std::vector<SimplePathSegment> simple_segs = {simple_seg}; + // Create a SimplePath + auto simple_path = SimplePath (simple_segs, false, type.get_locus ()); + + // Convert to TypePath by creating path segments + std::vector<std::unique_ptr<TypePathSegment>> segments; + segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment ( + PathIdentSegment (ident.as_string (), type.get_locus ()), false, + type.get_locus ()))); + + // Create TypePath from segments + auto type_path + = new TypePath (std::move (segments), type.get_locus (), false); + + // Convert the bound to a generic parameter bound + std::vector<std::unique_ptr<TypeParamBound>> bounds; + bounds.push_back (std::move (type.get_trait_bound ())); + + // Create the new generic parameter + auto generic_param = std::unique_ptr<TypeParam> ( + new TypeParam (ident, type.get_locus (), std::move (bounds), nullptr, {}, + true /*from impl trait*/)); + + // Store the generic parameter to be added to the function signature + implicit_generic_params.push_back (std::move (generic_param)); + + // Replace impl trait with the new type parameter + translated = type_path; + } + +private: + DesugarApitType (AST::Type *base) + : translated (base), implicit_generic_params () + {} + + AST::Type *translated; + std::vector<std::unique_ptr<GenericParam>> implicit_generic_params; +}; + +// --------- + +class ApitBoundProcessor +{ +public: + ApitBoundProcessor ( + WhereClause &where_clause, + std::vector<std::unique_ptr<GenericParam>> &generic_params) + : where_clause (where_clause), generic_params (generic_params) + {} + + void go (std::vector<std::unique_ptr<GenericParam>> &implicit_generics) + { + // some desugars are more complex so imagine this case + // + // pub fn foo(_value: impl Bar<Baz = impl Foo>) -> i32 { + // 15 + // } + // + // this needs to become: + // + // pub fn foo<T, U>(_value: T) -> i32 + // where + // T: Bar<Baz = U>, + // U: Foo, + // { + // 15 + // } + // + // so we need to walk all the implicit generics and the trait bounds paths + // for more generics + + for (auto &implicit_generic : implicit_generics) + { + switch (implicit_generic->get_kind ()) + { + case GenericParam::Kind::Type: + { + TypeParam &p + = *static_cast<TypeParam *> (implicit_generic.get ()); + + process_type_param (p); + generic_params.push_back (std::move (implicit_generic)); + for (auto &synth : synthetic_params) + generic_params.push_back (std::move (synth)); + synthetic_params.clear (); + } + break; + + default: + generic_params.push_back (std::move (implicit_generic)); + break; + } + } + } + +private: + void process_type_param (TypeParam &p) + { + auto &bounds = p.get_type_param_bounds (); + std::vector<size_t> bounds_to_remove; + for (size_t i = 0; i < bounds.size (); i++) + { + auto &tb = bounds[i]; + switch (tb->get_bound_type ()) + { + case TypeParamBound::TypeParamBoundType::TRAIT: + { + TraitBound &ttb = *static_cast<TraitBound *> (tb.get ()); + TypePath &path = ttb.get_type_path (); + bool deusgared = process_type_path (p, ttb, path); + if (deusgared) + bounds_to_remove.push_back (i); + } + + default: + break; + } + } + for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend (); + ++it) + bounds.erase (bounds.begin () + *it); + } + + bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path) + { + bool desugared = false; + for (auto &segment : path.get_segments ()) + { + switch (segment->get_type ()) + { + case TypePathSegment::SegmentType::GENERIC: + { + TypePathSegmentGeneric &seg + = *static_cast<TypePathSegmentGeneric *> (segment.get ()); + desugared |= process_generic_segment (p, parent, path, seg); + } + + default: + break; + } + } + return desugared; + } + + bool process_generic_segment (TypeParam &p, TraitBound &parent, + TypePath &path, TypePathSegmentGeneric &seg) + { + // we need to look for any impl types as default arguments in any generics + // and remove this index from the generic arguments by using a where + // constraint instead + + std::vector<std::unique_ptr<WhereClauseItem>> new_clauses; + GenericArgs &generic_args = seg.get_generic_args (); + std::vector<std::reference_wrapper<const GenericArgsBinding>> + bindings_desugared; + std::vector<GenericArgsBinding> &bindings + = generic_args.get_binding_args (); + + for (auto &generic : bindings) + { + auto &t = generic.get_type (); + auto translated = DesugarApitType::Desugar (t); + auto tt = translated.first; + + auto &implicit_generics = translated.second; + if (implicit_generics.empty ()) + continue; + + if (tt != &t) + { + bindings_desugared.push_back (generic); + generic.get_type_ptr () = std::unique_ptr<Type> (tt); + } + + for (auto &implicit_generic : implicit_generics) + { + switch (implicit_generic->get_kind ()) + { + case GenericParam::Kind::Type: + { + TypeParam &tp + = *static_cast<TypeParam *> (implicit_generic.get ()); + + std::vector<std::unique_ptr<TypeParamBound>> + type_param_bounds; + for (auto &b : tp.get_type_param_bounds ()) + type_param_bounds.push_back (std::move (b)); + tp.get_type_param_bounds ().clear (); + + // add synthetic parameter for this + synthetic_params.push_back (std::move (implicit_generic)); + + auto bound_type_path + = get_type_for_identifier (tp.get_type_representation ()); + + auto clause = new TypeBoundWhereClauseItem ( + {}, std::move (bound_type_path), + std::move (type_param_bounds), tp.get_locus ()); + std::unique_ptr<WhereClauseItem> clause_item + = std::unique_ptr<WhereClauseItem> (clause); + new_clauses.push_back (std::move (clause_item)); + } + break; + + default: + synthetic_params.push_back (std::move (implicit_generic)); + break; + } + } + } + + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; + auto bound = std::unique_ptr<TypeParamBound> (new TraitBound (parent)); + type_param_bounds.push_back (std::move (bound)); + auto parent_type_path + = get_type_for_identifier (p.get_type_representation ()); + auto clause + = new TypeBoundWhereClauseItem ({}, std::move (parent_type_path), + std::move (type_param_bounds), + parent.get_locus ()); + std::unique_ptr<WhereClauseItem> clause_item + = std::unique_ptr<WhereClauseItem> (clause); + where_clause.get_items ().push_back (std::move (clause_item)); + + for (auto &where_item : new_clauses) + where_clause.get_items ().push_back (std::move (where_item)); + + return !bindings_desugared.empty (); + } + + static std::unique_ptr<Type> get_type_for_identifier (const Identifier &ident) + { + auto simple_seg + = SimplePathSegment (ident.as_string (), ident.get_locus ()); + std::vector<SimplePathSegment> simple_segs = {simple_seg}; + auto simple_path = SimplePath (simple_segs, false, ident.get_locus ()); + std::vector<std::unique_ptr<TypePathSegment>> segments; + segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment ( + PathIdentSegment (ident.as_string (), ident.get_locus ()), false, + ident.get_locus ()))); + auto type_path = new TypePath (std::move (segments), ident.get_locus ()); + return std::unique_ptr<Type> (type_path); + } + +private: + WhereClause &where_clause; + std::vector<std::unique_ptr<GenericParam>> &generic_params; + + // mutates + std::vector<std::unique_ptr<GenericParam>> synthetic_params; +}; + +// --------- + +DesugarApit::DesugarApit () {} + +void +DesugarApit::go (AST::Crate &crate) +{ + DefaultASTVisitor::visit (crate); +} + +void +DesugarApit::visit (AST::Function &function) +{ + if (!function.has_function_params ()) + return; + + auto &fn_params = function.get_function_params (); + for (auto ¶m : fn_params) + { + if (param->is_variadic () || param->is_self ()) + continue; + + auto *p = param.get (); + auto &fp = *static_cast<AST::FunctionParam *> (p); + auto &type = fp.get_type (); + + auto translated = DesugarApitType::Desugar (type); + auto tt = translated.first; + + auto &implicit_generics = translated.second; + if (implicit_generics.empty ()) + continue; + + if (fp.get_type_ptr ().get () != tt) + { + fp.get_type_ptr () = std::unique_ptr<AST::Type> (tt); + } + + ApitBoundProcessor processor (function.get_where_clause (), + function.get_generic_params ()); + processor.go (implicit_generics); + } +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-desugar-apit.h b/gcc/rust/ast/rust-desugar-apit.h new file mode 100644 index 0000000..07c25e2 --- /dev/null +++ b/gcc/rust/ast/rust-desugar-apit.h @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_DESUGAR_APIT_H +#define RUST_DESUGAR_APIT_H + +#include "rust-ast-visitor.h" + +namespace Rust { +namespace AST { + +class DesugarApit : public DefaultASTVisitor +{ + using DefaultASTVisitor::visit; + +public: + DesugarApit (); + void go (AST::Crate &); + +private: + void visit (AST::Function &) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DESUGAR_APIT_H diff --git a/gcc/rust/ast/rust-desugar-for-loops.cc b/gcc/rust/ast/rust-desugar-for-loops.cc index ffc3470..5cc1c19 100644 --- a/gcc/rust/ast/rust-desugar-for-loops.cc +++ b/gcc/rust/ast/rust-desugar-for-loops.cc @@ -17,7 +17,6 @@ // <http://www.gnu.org/licenses/>. #include "rust-desugar-for-loops.h" -#include "rust-ast-visitor.h" #include "rust-ast.h" #include "rust-hir-map.h" #include "rust-path.h" @@ -31,32 +30,10 @@ namespace AST { DesugarForLoops::DesugarForLoops () {} -void -DesugarForLoops::go (AST::Crate &crate) -{ - DefaultASTVisitor::visit (crate); -} - -static void -replace_for_loop (std::unique_ptr<Expr> &for_loop, - std::unique_ptr<Expr> &&expanded) -{ - for_loop = std::move (expanded); -} - -MatchArm -DesugarForLoops::DesugarCtx::make_match_arm (std::unique_ptr<Pattern> &&path) -{ - auto patterns = std::vector<std::unique_ptr<Pattern>> (); - patterns.emplace_back (std::move (path)); - - return MatchArm (std::move (patterns), loc); -} - MatchCase DesugarForLoops::DesugarCtx::make_break_arm () { - auto arm = make_match_arm (std::unique_ptr<Pattern> (new PathInExpression ( + auto arm = builder.match_arm (std::unique_ptr<Pattern> (new PathInExpression ( builder.path_in_expression (LangItem::Kind::OPTION_NONE)))); auto break_expr @@ -79,7 +56,7 @@ DesugarForLoops::DesugarCtx::make_continue_arm () builder.path_in_expression (LangItem::Kind::OPTION_SOME), std::move (pattern_item))); - auto val_arm = make_match_arm (std::move (pattern)); + auto val_arm = builder.match_arm (std::move (pattern)); auto next = builder.identifier (DesugarCtx::next_value_id); @@ -91,14 +68,8 @@ DesugarForLoops::DesugarCtx::make_continue_arm () return MatchCase (std::move (val_arm), std::move (assignment)); } -std::unique_ptr<Stmt> -DesugarForLoops::DesugarCtx::statementify (std::unique_ptr<Expr> &&expr) -{ - return std::unique_ptr<Stmt> (new ExprStmt (std::move (expr), loc, true)); -} - std::unique_ptr<Expr> -DesugarForLoops::desugar (AST::ForLoopExpr &expr) +DesugarForLoops::desugar (ForLoopExpr &expr) { auto ctx = DesugarCtx (expr.get_locus ()); @@ -140,10 +111,10 @@ DesugarForLoops::desugar (AST::ForLoopExpr &expr) auto loop_stmts = std::vector<std::unique_ptr<Stmt>> (); loop_stmts.emplace_back (std::move (let_next)); - loop_stmts.emplace_back (ctx.statementify (std::move (match_next))); + loop_stmts.emplace_back (ctx.builder.statementify (std::move (match_next))); loop_stmts.emplace_back (std::move (let_pat)); loop_stmts.emplace_back ( - ctx.statementify (expr.get_loop_block ().clone_expr ())); + ctx.builder.statementify (expr.get_loop_block ().clone_expr ())); // loop { // <let_next>; @@ -170,34 +141,18 @@ DesugarForLoops::desugar (AST::ForLoopExpr &expr) } void -DesugarForLoops::maybe_desugar_expr (std::unique_ptr<Expr> &expr) +DesugarForLoops::go (std::unique_ptr<Expr> &ptr) { - if (expr->get_expr_kind () == AST::Expr::Kind::Loop) - { - auto &loop = static_cast<AST::BaseLoopExpr &> (*expr); + rust_assert (ptr->get_expr_kind () == Expr::Kind::Loop); - if (loop.get_loop_kind () == AST::BaseLoopExpr::Kind::For) - { - auto &for_loop = static_cast<AST::ForLoopExpr &> (loop); + auto &loop = static_cast<BaseLoopExpr &> (*ptr); - auto desugared = desugar (for_loop); - - replace_for_loop (expr, std::move (desugared)); - } - } -} - -void -DesugarForLoops::visit (AST::BlockExpr &block) -{ - for (auto &stmt : block.get_statements ()) - if (stmt->get_stmt_kind () == AST::Stmt::Kind::Expr) - maybe_desugar_expr (static_cast<AST::ExprStmt &> (*stmt).get_expr_ptr ()); + rust_assert (loop.get_loop_kind () == BaseLoopExpr::Kind::For); - if (block.has_tail_expr ()) - maybe_desugar_expr (block.get_tail_expr_ptr ()); + auto &for_loop = static_cast<ForLoopExpr &> (loop); + auto desugared = DesugarForLoops ().desugar (for_loop); - DefaultASTVisitor::visit (block); + ptr = std::move (desugared); } } // namespace AST diff --git a/gcc/rust/ast/rust-desugar-for-loops.h b/gcc/rust/ast/rust-desugar-for-loops.h index 7beb692..96b63ff 100644 --- a/gcc/rust/ast/rust-desugar-for-loops.h +++ b/gcc/rust/ast/rust-desugar-for-loops.h @@ -20,7 +20,6 @@ #define RUST_DESUGAR_FOR_LOOPS_H #include "rust-ast-builder.h" -#include "rust-ast-visitor.h" #include "rust-expr.h" namespace Rust { @@ -69,15 +68,14 @@ namespace AST { // of the way the typechecker is currently structured, where it will fetch name // resolution information in order to typecheck paths - which technically isn't // necessary. -class DesugarForLoops : public DefaultASTVisitor +class DesugarForLoops { - using DefaultASTVisitor::visit; - public: - DesugarForLoops (); - void go (AST::Crate &); + static void go (std::unique_ptr<Expr> &ptr); private: + DesugarForLoops (); + struct DesugarCtx { DesugarCtx (location_t loc) : builder (Builder (loc)), loc (loc) {} @@ -85,10 +83,8 @@ private: Builder builder; location_t loc; - MatchArm make_match_arm (std::unique_ptr<Pattern> &&pattern); MatchCase make_break_arm (); MatchCase make_continue_arm (); - std::unique_ptr<Stmt> statementify (std::unique_ptr<Expr> &&expr); constexpr static const char *continue_pattern_id = "#val"; constexpr static const char *next_value_id = "#__next"; @@ -96,10 +92,7 @@ private: constexpr static const char *result_id = "#result"; }; - std::unique_ptr<Expr> desugar (AST::ForLoopExpr &expr); - void maybe_desugar_expr (std::unique_ptr<Expr> &expr); - - void visit (AST::BlockExpr &) override; + std::unique_ptr<Expr> desugar (ForLoopExpr &expr); }; } // namespace AST diff --git a/gcc/rust/ast/rust-desugar-question-mark.cc b/gcc/rust/ast/rust-desugar-question-mark.cc index 4d2933b..01400d8 100644 --- a/gcc/rust/ast/rust-desugar-question-mark.cc +++ b/gcc/rust/ast/rust-desugar-question-mark.cc @@ -18,7 +18,6 @@ #include "rust-desugar-question-mark.h" #include "rust-ast-builder.h" -#include "rust-ast-visitor.h" namespace Rust { namespace AST { @@ -26,42 +25,14 @@ namespace AST { DesugarQuestionMark::DesugarQuestionMark () {} void -DesugarQuestionMark::go (AST::Crate &crate) +DesugarQuestionMark::go (std::unique_ptr<Expr> &ptr) { - DesugarQuestionMark::visit (crate); -} - -void -DesugarQuestionMark::visit (ExprStmt &stmt) -{ - if (stmt.get_expr ().get_expr_kind () == Expr::Kind::ErrorPropagation) - desugar_and_replace (stmt.get_expr_ptr ()); - - DefaultASTVisitor::visit (stmt); -} - -void -DesugarQuestionMark::visit (CallExpr &call) -{ - if (call.get_function_expr ().get_expr_kind () - == Expr::Kind::ErrorPropagation) - desugar_and_replace (call.get_function_expr_ptr ()); - - for (auto &arg : call.get_params ()) - if (arg->get_expr_kind () == Expr::Kind::ErrorPropagation) - desugar_and_replace (arg); - - DefaultASTVisitor::visit (call); -} + rust_assert (ptr->get_expr_kind () == Expr::Kind::ErrorPropagation); -void -DesugarQuestionMark::visit (LetStmt &stmt) -{ - if (stmt.has_init_expr () - && stmt.get_init_expr ().get_expr_kind () == Expr::Kind::ErrorPropagation) - desugar_and_replace (stmt.get_init_expr_ptr ()); + auto original = static_cast<ErrorPropagationExpr &> (*ptr); + auto desugared = DesugarQuestionMark ().desugar (original); - DefaultASTVisitor::visit (stmt); + ptr = std::move (desugared); } MatchArm @@ -99,6 +70,12 @@ ok_case (Builder &builder) MatchCase err_case (Builder &builder) { + // TODO: We need to handle the case where there is an enclosing `try {}` + // block, as that will create an additional block label that we can break to. + // This allows try blocks to use the question mark operator without having the + // offending statement early return from the enclosing function + // FIXME: How to mark that there is an enclosing block label? + auto val = builder.identifier_pattern ("err"); auto patterns = std::vector<std::unique_ptr<Pattern>> (); @@ -154,14 +131,5 @@ DesugarQuestionMark::desugar (ErrorPropagationExpr &expr) expr.get_locus ())); } -void -DesugarQuestionMark::desugar_and_replace (std::unique_ptr<Expr> &ptr) -{ - auto original = static_cast<ErrorPropagationExpr &> (*ptr); - auto desugared = desugar (original); - - ptr = std::move (desugared); -} - } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-desugar-question-mark.h b/gcc/rust/ast/rust-desugar-question-mark.h index e4c513f..542c52b 100644 --- a/gcc/rust/ast/rust-desugar-question-mark.h +++ b/gcc/rust/ast/rust-desugar-question-mark.h @@ -19,9 +19,7 @@ #ifndef RUST_DESUGAR_QUESTION_MARK #define RUST_DESUGAR_QUESTION_MARK -#include "rust-ast-visitor.h" #include "rust-expr.h" -#include "rust-stmt.h" namespace Rust { namespace AST { @@ -56,21 +54,15 @@ namespace AST { // } // } // ``` -class DesugarQuestionMark : public DefaultASTVisitor +class DesugarQuestionMark { - using DefaultASTVisitor::visit; - public: - DesugarQuestionMark (); - void go (AST::Crate &); + static void go (std::unique_ptr<Expr> &ptr); private: - void desugar_and_replace (std::unique_ptr<Expr> &ptr); - std::unique_ptr<Expr> desugar (ErrorPropagationExpr &); + DesugarQuestionMark (); - void visit (AST::ExprStmt &) override; - void visit (AST::CallExpr &) override; - void visit (AST::LetStmt &) override; + std::unique_ptr<Expr> desugar (ErrorPropagationExpr &); }; } // namespace AST diff --git a/gcc/rust/ast/rust-desugar-try-block.cc b/gcc/rust/ast/rust-desugar-try-block.cc new file mode 100644 index 0000000..07f06aa --- /dev/null +++ b/gcc/rust/ast/rust-desugar-try-block.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-desugar-try-block.h" +#include "rust-ast-builder.h" +#include "rust-expr.h" + +namespace Rust { +namespace AST { + +DesugarTryBlock::DesugarTryBlock () {} + +void +DesugarTryBlock::go (std::unique_ptr<Expr> &ptr) +{ + rust_assert (ptr->get_expr_kind () == Expr::Kind::Try); + + auto original = static_cast<TryExpr &> (*ptr); + auto desugared = DesugarTryBlock ().desugar (original); + + ptr = std::move (desugared); +} + +std::unique_ptr<Expr> +DesugarTryBlock::desugar (TryExpr &expr) +{ + auto builder = Builder (expr.get_locus ()); + auto &block = expr.get_block_expr (); + + if (block.has_statements ()) + rust_sorry_at (expr.get_locus (), + "cannot desugar try-blocks with statements"); + + auto tail_expr = builder.tuple (); + + if (block.has_tail_expr ()) + tail_expr = block.get_tail_expr ().clone_expr (); + + // Wrap in Try::from_ok call + auto from_ok = builder.path_in_expression (LangItem::Kind::TRY_FROM_OK); + auto call = builder.call (ptrify (from_ok), std::move (tail_expr)); + + return builder.block (std::move (call)); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-desugar-try-block.h b/gcc/rust/ast/rust-desugar-try-block.h new file mode 100644 index 0000000..bfd0463 --- /dev/null +++ b/gcc/rust/ast/rust-desugar-try-block.h @@ -0,0 +1,42 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_DESUGAR_TRY_BLOCK +#define RUST_DESUGAR_TRY_BLOCK + +#include "rust-expr.h" + +namespace Rust { +namespace AST { + +// FIXME: Add documentation +class DesugarTryBlock +{ +public: + static void go (std::unique_ptr<Expr> &ptr); + +private: + DesugarTryBlock (); + + std::unique_ptr<Expr> desugar (TryExpr &); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DESUGAR_TRY_BLOCK diff --git a/gcc/rust/ast/rust-desugar-while-let.cc b/gcc/rust/ast/rust-desugar-while-let.cc new file mode 100644 index 0000000..5eadc59 --- /dev/null +++ b/gcc/rust/ast/rust-desugar-while-let.cc @@ -0,0 +1,104 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-desugar-while-let.h" +#include "rust-ast.h" +#include "rust-hir-map.h" +#include "rust-path.h" +#include "rust-pattern.h" +#include "rust-stmt.h" +#include "rust-expr.h" +#include "rust-ast-builder.h" + +namespace Rust { +namespace AST { + +DesugarWhileLet::DesugarWhileLet () {} + +MatchCase +DesugarWhileLet::DesugarCtx::make_break_arm () +{ + auto arm = builder.match_arm (builder.wildcard ()); + + auto break_expr + = std::unique_ptr<Expr> (new BreakExpr (tl::nullopt, nullptr, {}, loc)); + + return MatchCase (std::move (arm), std::move (break_expr)); +} + +MatchCase +DesugarWhileLet::DesugarCtx::make_continue_arm ( + std::unique_ptr<Pattern> &&pattern, std::unique_ptr<BlockExpr> &&body) +{ + auto arm = builder.match_arm (std::move (pattern)); + + return MatchCase (std::move (arm), std::move (body)); +} + +std::unique_ptr<Expr> +DesugarWhileLet::desugar (WhileLetLoopExpr &expr) +{ + rust_assert (expr.get_patterns ().size () == 1); + + auto pattern = expr.get_patterns ()[0]->clone_pattern (); + auto body = expr.get_loop_block ().clone_block_expr (); + auto scrutinee = expr.get_scrutinee_expr ().clone_expr (); + + auto ctx = DesugarCtx (expr.get_locus ()); + + // _ => break, + auto break_arm = ctx.make_break_arm (); + + // <pattern> => <body>, + auto continue_arm + = ctx.make_continue_arm (std::move (pattern), std::move (body)); + + // match <scrutinee> { + // <continue_arm> + // <break_arm> + // } + auto match_expr + = ctx.builder.match (std::move (scrutinee), + {std::move (continue_arm), std::move (break_arm)}); + + auto loop_stmts = std::vector<std::unique_ptr<Stmt>> (); + loop_stmts.emplace_back (ctx.builder.statementify (std::move (match_expr))); + + // loop { + // <match_expr> + // } + return ctx.builder.loop (std::move (loop_stmts)); +} + +void +DesugarWhileLet::go (std::unique_ptr<Expr> &ptr) +{ + rust_assert (ptr->get_expr_kind () == Expr::Kind::Loop); + + auto &loop = static_cast<BaseLoopExpr &> (*ptr); + + rust_assert (loop.get_loop_kind () == BaseLoopExpr::Kind::WhileLet); + + auto &while_let = static_cast<WhileLetLoopExpr &> (loop); + auto desugared = DesugarWhileLet ().desugar (while_let); + + ptr = std::move (desugared); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-desugar-while-let.h b/gcc/rust/ast/rust-desugar-while-let.h new file mode 100644 index 0000000..60e0693 --- /dev/null +++ b/gcc/rust/ast/rust-desugar-while-let.h @@ -0,0 +1,71 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_DESUGAR_WHILE_LET_H +#define RUST_DESUGAR_WHILE_LET_H + +#include "rust-ast-builder.h" +#include "rust-expr.h" + +namespace Rust { +namespace AST { + +// Desugar while-let into a set of other AST nodes. The desugar is of the +// following form: +// +// ``` +// whilet let <pat> = <expr> <body> +// ``` +// +// becomes: +// +// ``` +// loop { +// match <expr> { +// <pat> => <body>, +// _ => break +// } +// } +// ``` +class DesugarWhileLet +{ +public: + static void go (std::unique_ptr<Expr> &ptr); + +private: + DesugarWhileLet (); + + struct DesugarCtx + { + DesugarCtx (location_t loc) : builder (Builder (loc)), loc (loc) {} + + Builder builder; + location_t loc; + + MatchCase make_break_arm (); + MatchCase make_continue_arm (std::unique_ptr<Pattern> &&pattern, + std::unique_ptr<BlockExpr> &&body); + }; + + std::unique_ptr<Expr> desugar (WhileLetLoopExpr &expr); +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DESUGAR_WHILE_LET_H diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h index fdb6360..7b0df25 100644 --- a/gcc/rust/ast/rust-expr.h +++ b/gcc/rust/ast/rust-expr.h @@ -1,6 +1,7 @@ #ifndef RUST_AST_EXPR_H #define RUST_AST_EXPR_H +#include "optional.h" #include "rust-ast.h" #include "rust-common.h" #include "rust-path.h" @@ -182,9 +183,13 @@ public: AttrInputMacro (AttrInputMacro &&oth) : macro (std::move (oth.macro)) {} - void operator= (const AttrInputMacro &oth); + AttrInputMacro &operator= (const AttrInputMacro &oth); - void operator= (AttrInputMacro &&oth) { macro = std::move (oth.macro); } + AttrInputMacro &operator= (AttrInputMacro &&oth) + { + macro = std::move (oth.macro); + return *this; + } std::string as_string () const override; @@ -244,36 +249,50 @@ protected: } }; -// more generic meta item "path = lit" form -class MetaItemPathLit : public MetaItem +// more generic meta item "path = expr" form +class MetaItemPathExpr : public MetaItem { SimplePath path; - LiteralExpr lit; + std::unique_ptr<Expr> expr; public: - MetaItemPathLit (SimplePath path, LiteralExpr lit_expr) - : path (std::move (path)), lit (std::move (lit_expr)) + MetaItemPathExpr (SimplePath path, std::unique_ptr<Expr> expr) + : path (std::move (path)), expr (std::move (expr)) {} + MetaItemPathExpr (const MetaItemPathExpr &other) + : MetaItem (other), path (other.path), expr (other.expr->clone_expr ()) + {} + + MetaItemPathExpr (MetaItemPathExpr &&) = default; + + MetaItemPathExpr &operator= (MetaItemPathExpr &&) = default; + + MetaItemPathExpr operator= (const MetaItemPathExpr &other) + { + MetaItem::operator= (other); + path = other.path; + expr = other.expr->clone_expr (); + return *this; + } + SimplePath get_path () const { return path; } SimplePath &get_path () { return path; } - LiteralExpr get_literal () const { return lit; } - - LiteralExpr &get_literal () { return lit; } + Expr &get_expr () { return *expr; } std::string as_string () const override { - return path.as_string () + " = " + lit.as_string (); + return path.as_string () + " = " + expr->as_string (); } MetaItem::ItemKind get_item_kind () const override { - return MetaItem::ItemKind::PathLit; + return MetaItem::ItemKind::PathExpr; } - // There are two Locations in MetaItemPathLit (path and lit_expr), + // There are two Locations in MetaItemPathExpr (path and expr), // we have no idea use which of them, just simply return UNKNOWN_LOCATION // now. // Maybe we will figure out when we really need the location in the future. @@ -289,9 +308,9 @@ public: protected: // Use covariance to implement clone function as returning this type - MetaItemPathLit *clone_meta_item_inner_impl () const override + MetaItemPathExpr *clone_meta_item_inner_impl () const override { - return new MetaItemPathLit (*this); + return new MetaItemPathExpr (*this); } }; @@ -395,6 +414,8 @@ public: return *main_or_left_expr; } + bool has_borrow_expr () const { return main_or_left_expr != nullptr; } + bool get_is_mut () const { return mutability == Mutability::Mut; } Mutability get_mutability () const { return mutability; } @@ -1160,11 +1181,11 @@ protected: // Value array elements class ArrayElemsValues : public ArrayElems { - std::vector<std::unique_ptr<Expr> > values; + std::vector<std::unique_ptr<Expr>> values; location_t locus; public: - ArrayElemsValues (std::vector<std::unique_ptr<Expr> > elems, location_t locus) + ArrayElemsValues (std::vector<std::unique_ptr<Expr>> elems, location_t locus) : ArrayElems (), values (std::move (elems)), locus (locus) {} @@ -1192,14 +1213,16 @@ public: std::string as_string () const override; + location_t get_locus () const { return locus; } + void accept_vis (ASTVisitor &vis) override; // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Expr> > &get_values () const + const std::vector<std::unique_ptr<Expr>> &get_values () const { return values; } - std::vector<std::unique_ptr<Expr> > &get_values () { return values; } + std::vector<std::unique_ptr<Expr>> &get_values () { return values; } size_t get_num_values () const { return values.size (); } @@ -1214,6 +1237,8 @@ protected: class ArrayElemsCopied : public ArrayElems { std::unique_ptr<Expr> elem_to_copy; + + // TODO: This should be replaced by a ConstExpr std::unique_ptr<Expr> num_copies; location_t locus; @@ -1246,6 +1271,8 @@ public: std::string as_string () const override; + location_t get_locus () const { return locus; } + void accept_vis (ASTVisitor &vis) override; // TODO: is this better? Or is a "vis_block" better? @@ -1472,7 +1499,7 @@ class TupleExpr : public ExprWithoutBlock { std::vector<Attribute> outer_attrs; std::vector<Attribute> inner_attrs; - std::vector<std::unique_ptr<Expr> > tuple_elems; + std::vector<std::unique_ptr<Expr>> tuple_elems; location_t locus; // TODO: find another way to store this to save memory? @@ -1492,7 +1519,7 @@ public: outer_attrs = std::move (new_attrs); } - TupleExpr (std::vector<std::unique_ptr<Expr> > tuple_elements, + TupleExpr (std::vector<std::unique_ptr<Expr>> tuple_elements, std::vector<Attribute> inner_attribs, std::vector<Attribute> outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), @@ -1543,14 +1570,11 @@ public: bool is_marked_for_strip () const override { return marked_for_strip; } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Expr> > &get_tuple_elems () const - { - return tuple_elems; - } - std::vector<std::unique_ptr<Expr> > &get_tuple_elems () + const std::vector<std::unique_ptr<Expr>> &get_tuple_elems () const { return tuple_elems; } + std::vector<std::unique_ptr<Expr>> &get_tuple_elems () { return tuple_elems; } bool is_unit () const { return tuple_elems.size () == 0; } @@ -1775,6 +1799,8 @@ public: std::string as_string () const; + location_t get_locus () const { return locus; } + // TODO: is this better? Or is a "vis_block" better? Expr &get_base_struct () { @@ -1972,7 +1998,7 @@ protected: class StructExprStructFields : public StructExprStruct { // std::vector<StructExprField> fields; - std::vector<std::unique_ptr<StructExprField> > fields; + std::vector<std::unique_ptr<StructExprField>> fields; // bool has_struct_base; StructBase struct_base; @@ -1985,8 +2011,8 @@ public: // Constructor for StructExprStructFields when no struct base is used StructExprStructFields ( PathInExpression struct_path, - std::vector<std::unique_ptr<StructExprField> > expr_fields, - location_t locus, StructBase base_struct = StructBase::error (), + std::vector<std::unique_ptr<StructExprField>> expr_fields, location_t locus, + StructBase base_struct = StructBase::error (), std::vector<Attribute> inner_attribs = std::vector<Attribute> (), std::vector<Attribute> outer_attribs = std::vector<Attribute> ()) : StructExprStruct (std::move (struct_path), std::move (inner_attribs), @@ -2023,11 +2049,11 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: this mutable getter seems really dodgy. Think up better way. - std::vector<std::unique_ptr<StructExprField> > &get_fields () + std::vector<std::unique_ptr<StructExprField>> &get_fields () { return fields; } - const std::vector<std::unique_ptr<StructExprField> > &get_fields () const + const std::vector<std::unique_ptr<StructExprField>> &get_fields () const { return fields; } @@ -2084,7 +2110,7 @@ class CallExpr : public ExprWithoutBlock { std::vector<Attribute> outer_attrs; std::unique_ptr<Expr> function; - std::vector<std::unique_ptr<Expr> > params; + std::vector<std::unique_ptr<Expr>> params; location_t locus; public: @@ -2093,7 +2119,7 @@ public: std::string as_string () const override; CallExpr (std::unique_ptr<Expr> function_expr, - std::vector<std::unique_ptr<Expr> > function_params, + std::vector<std::unique_ptr<Expr>> function_params, std::vector<Attribute> outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), function (std::move (function_expr)), @@ -2150,11 +2176,11 @@ public: bool is_marked_for_strip () const override { return function == nullptr; } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Expr> > &get_params () const + const std::vector<std::unique_ptr<Expr>> &get_params () const { return params; } - std::vector<std::unique_ptr<Expr> > &get_params () { return params; } + std::vector<std::unique_ptr<Expr>> &get_params () { return params; } // TODO: is this better? Or is a "vis_block" better? Expr &get_function_expr () @@ -2190,7 +2216,7 @@ class MethodCallExpr : public ExprWithoutBlock std::vector<Attribute> outer_attrs; std::unique_ptr<Expr> receiver; PathExprSegment method_name; - std::vector<std::unique_ptr<Expr> > params; + std::vector<std::unique_ptr<Expr>> params; location_t locus; public: @@ -2198,7 +2224,7 @@ public: MethodCallExpr (std::unique_ptr<Expr> call_receiver, PathExprSegment method_path, - std::vector<std::unique_ptr<Expr> > method_params, + std::vector<std::unique_ptr<Expr>> method_params, std::vector<Attribute> outer_attribs, location_t locus) : outer_attrs (std::move (outer_attribs)), receiver (std::move (call_receiver)), @@ -2254,11 +2280,11 @@ public: bool is_marked_for_strip () const override { return receiver == nullptr; } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Expr> > &get_params () const + const std::vector<std::unique_ptr<Expr>> &get_params () const { return params; } - std::vector<std::unique_ptr<Expr> > &get_params () { return params; } + std::vector<std::unique_ptr<Expr>> &get_params () { return params; } // TODO: is this better? Or is a "vis_block" better? Expr &get_receiver_expr () @@ -2504,6 +2530,8 @@ public: bool get_has_move () const { return has_move; } Expr::Kind get_expr_kind () const override { return Expr::Kind::Closure; } + + virtual Expr &get_definition_expr () = 0; }; // Represents a non-type-specified closure expression AST node @@ -2563,7 +2591,7 @@ public: return closure_inner == nullptr; } - Expr &get_definition_expr () + Expr &get_definition_expr () override { rust_assert (closure_inner != nullptr); return *closure_inner; @@ -2583,7 +2611,7 @@ class BlockExpr : public ExprWithBlock { std::vector<Attribute> outer_attrs; std::vector<Attribute> inner_attrs; - std::vector<std::unique_ptr<Stmt> > statements; + std::vector<std::unique_ptr<Stmt>> statements; std::unique_ptr<Expr> expr; tl::optional<LoopLabel> label; location_t start_locus; @@ -2599,7 +2627,7 @@ public: // Returns whether the block contains a final expression. bool has_tail_expr () const { return expr != nullptr; } - BlockExpr (std::vector<std::unique_ptr<Stmt> > block_statements, + BlockExpr (std::vector<std::unique_ptr<Stmt>> block_statements, std::unique_ptr<Expr> block_expr, std::vector<Attribute> inner_attribs, std::vector<Attribute> outer_attribs, @@ -2678,11 +2706,11 @@ public: const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; } std::vector<Attribute> &get_inner_attrs () { return inner_attrs; } - const std::vector<std::unique_ptr<Stmt> > &get_statements () const + const std::vector<std::unique_ptr<Stmt>> &get_statements () const { return statements; } - std::vector<std::unique_ptr<Stmt> > &get_statements () { return statements; } + std::vector<std::unique_ptr<Stmt>> &get_statements () { return statements; } // TODO: is this better? Or is a "vis_block" better? Expr &get_tail_expr () @@ -2744,6 +2772,151 @@ protected: } }; +class AnonConst : public ExprWithBlock +{ +public: + enum class Kind + { + Explicit, + DeferredInference, + }; + + AnonConst (std::unique_ptr<Expr> &&expr, location_t locus = UNKNOWN_LOCATION) + : ExprWithBlock (), locus (locus), kind (Kind::Explicit), + expr (std::move (expr)) + { + rust_assert (this->expr.value ()); + } + + AnonConst (location_t locus = UNKNOWN_LOCATION) + : ExprWithBlock (), locus (locus), kind (Kind::DeferredInference), + expr (tl::nullopt) + {} + + AnonConst (const AnonConst &other) + { + node_id = other.node_id; + locus = other.locus; + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); + } + + AnonConst operator= (const AnonConst &other) + { + node_id = other.node_id; + locus = other.locus; + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); + + return *this; + } + + std::string as_string () const override; + + Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstExpr; } + + location_t get_locus () const override { return locus; } + + Expr &get_inner_expr () + { + rust_assert (expr.has_value ()); + return *expr.value (); + } + + NodeId get_node_id () const override { return node_id; } + + /* FIXME: AnonConst are always "internal" and should not have outer attributes + * - is that true? Or should we instead call + * expr->get_outer_attrs()/expr->set_outer_attrs() */ + + std::vector<Attribute> &get_outer_attrs () override + { + static auto attrs = std::vector<Attribute> (); + return attrs; + } + + void set_outer_attrs (std::vector<Attribute>) override {} + + /* FIXME: Likewise for mark_for_strip() ? */ + void mark_for_strip () override {} + bool is_marked_for_strip () const override { return false; } + + void accept_vis (ASTVisitor &vis) override; + + bool is_deferred () const { return kind == Kind::DeferredInference; } + +private: + location_t locus; + Kind kind; + tl::optional<std::unique_ptr<Expr>> expr; + + AnonConst *clone_expr_with_block_impl () const override + { + return new AnonConst (*this); + } +}; + +class ConstBlock : public ExprWithBlock +{ +public: + ConstBlock (AnonConst &&expr, location_t locus = UNKNOWN_LOCATION, + std::vector<Attribute> &&outer_attrs = {}) + : ExprWithBlock (), expr (std::move (expr)), + outer_attrs (std::move (outer_attrs)), locus (locus) + {} + + ConstBlock (const ConstBlock &other) + : ExprWithBlock (other), expr (other.expr), outer_attrs (other.outer_attrs), + locus (other.locus) + {} + + ConstBlock operator= (const ConstBlock &other) + { + expr = other.expr; + node_id = other.node_id; + outer_attrs = other.outer_attrs; + locus = other.locus; + + return *this; + } + + std::string as_string () const override; + + Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstBlock; } + + AnonConst &get_const_expr () { return expr; } + + void accept_vis (ASTVisitor &vis) override; + + std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } + + void set_outer_attrs (std::vector<Attribute> new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + location_t get_locus () const override { return locus; } + + bool is_marked_for_strip () const override { return marked_for_strip; } + void mark_for_strip () override { marked_for_strip = true; } + +private: + AnonConst expr; + + std::vector<Attribute> outer_attrs; + location_t locus; + bool marked_for_strip = false; + + ConstBlock *clone_expr_with_block_impl () const override + { + return new ConstBlock (*this); + } +}; + // Represents a type-specified closure expression AST node class ClosureExprInnerTyped : public ClosureExpr { @@ -2812,7 +2985,7 @@ public: bool is_marked_for_strip () const override { return expr == nullptr; } // TODO: is this better? Or is a "vis_block" better? - BlockExpr &get_definition_block () + BlockExpr &get_definition_expr () override { rust_assert (expr != nullptr); return *expr; @@ -3572,6 +3745,82 @@ protected: } }; +// Try expression AST node representation +class TryExpr : public ExprWithBlock +{ + std::vector<Attribute> outer_attrs; + std::unique_ptr<BlockExpr> block_expr; + location_t locus; + + // TODO: find another way to store this to save memory? + bool marked_for_strip = false; + +public: + std::string as_string () const override; + + // Constructor for ReturnExpr. + TryExpr (std::unique_ptr<BlockExpr> block_expr, + std::vector<Attribute> outer_attribs, location_t locus) + : outer_attrs (std::move (outer_attribs)), + block_expr (std::move (block_expr)), locus (locus) + { + rust_assert (this->block_expr); + } + + // Copy constructor with clone + TryExpr (TryExpr const &other) + : ExprWithBlock (other), outer_attrs (other.outer_attrs), + block_expr (other.block_expr->clone_block_expr ()), locus (other.locus), + marked_for_strip (other.marked_for_strip) + {} + + // Overloaded assignment operator to clone return_expr pointer + TryExpr &operator= (TryExpr const &other) + { + ExprWithBlock::operator= (other); + locus = other.locus; + marked_for_strip = other.marked_for_strip; + outer_attrs = other.outer_attrs; + + block_expr = other.block_expr->clone_block_expr (); + + return *this; + } + + // move constructors + TryExpr (TryExpr &&other) = default; + TryExpr &operator= (TryExpr &&other) = default; + + location_t get_locus () const override final { return locus; } + + void accept_vis (ASTVisitor &vis) override; + + // Can't think of any invalid invariants, so store boolean. + void mark_for_strip () override { marked_for_strip = true; } + bool is_marked_for_strip () const override { return marked_for_strip; } + + // TODO: is this better? Or is a "vis_block" better? + BlockExpr &get_block_expr () { return *block_expr; } + + const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } + std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } + + void set_outer_attrs (std::vector<Attribute> new_attrs) override + { + outer_attrs = std::move (new_attrs); + } + + Expr::Kind get_expr_kind () const override { return Expr::Kind::Try; } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + TryExpr *clone_expr_with_block_impl () const override + { + return new TryExpr (*this); + } +}; + // Forward decl - defined in rust-macro.h class MacroInvocation; @@ -3847,14 +4096,14 @@ protected: class WhileLetLoopExpr : public BaseLoopExpr { // MatchArmPatterns patterns; - std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined + std::vector<std::unique_ptr<Pattern>> match_arm_patterns; // inlined std::unique_ptr<Expr> scrutinee; public: std::string as_string () const override; // Constructor with a loop label - WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, + WhileLetLoopExpr (std::vector<std::unique_ptr<Pattern>> match_arm_patterns, std::unique_ptr<Expr> scrutinee, std::unique_ptr<BlockExpr> loop_block, location_t locus, tl::optional<LoopLabel> loop_label = tl::nullopt, @@ -3908,11 +4157,11 @@ public: } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const { return match_arm_patterns; } - std::vector<std::unique_ptr<Pattern> > &get_patterns () + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return match_arm_patterns; } @@ -4195,7 +4444,7 @@ protected: class IfLetExpr : public ExprWithBlock { std::vector<Attribute> outer_attrs; - std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined + std::vector<std::unique_ptr<Pattern>> match_arm_patterns; // inlined std::unique_ptr<Expr> value; std::unique_ptr<BlockExpr> if_block; location_t locus; @@ -4203,7 +4452,7 @@ class IfLetExpr : public ExprWithBlock public: std::string as_string () const override; - IfLetExpr (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, + IfLetExpr (std::vector<std::unique_ptr<Pattern>> match_arm_patterns, std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block, std::vector<Attribute> outer_attrs, location_t locus) : outer_attrs (std::move (outer_attrs)), @@ -4297,11 +4546,11 @@ public: } // TODO: this mutable getter seems really dodgy. Think up better way. - const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const { return match_arm_patterns; } - std::vector<std::unique_ptr<Pattern> > &get_patterns () + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return match_arm_patterns; } @@ -4341,11 +4590,11 @@ class IfLetExprConseqElse : public IfLetExpr public: std::string as_string () const override; - IfLetExprConseqElse ( - std::vector<std::unique_ptr<Pattern> > match_arm_patterns, - std::unique_ptr<Expr> value, std::unique_ptr<BlockExpr> if_block, - std::unique_ptr<ExprWithBlock> else_block, - std::vector<Attribute> outer_attrs, location_t locus) + IfLetExprConseqElse (std::vector<std::unique_ptr<Pattern>> match_arm_patterns, + std::unique_ptr<Expr> value, + std::unique_ptr<BlockExpr> if_block, + std::unique_ptr<ExprWithBlock> else_block, + std::vector<Attribute> outer_attrs, location_t locus) : IfLetExpr (std::move (match_arm_patterns), std::move (value), std::move (if_block), std::move (outer_attrs), locus), else_block (std::move (else_block)) @@ -4398,7 +4647,7 @@ struct MatchArm private: std::vector<Attribute> outer_attrs; // MatchArmPatterns patterns; - std::vector<std::unique_ptr<Pattern> > match_arm_patterns; // inlined + std::vector<std::unique_ptr<Pattern>> match_arm_patterns; // inlined // bool has_match_arm_guard; // inlined from MatchArmGuard @@ -4411,7 +4660,7 @@ public: bool has_match_arm_guard () const { return guard_expr != nullptr; } // Constructor for match arm with a guard expression - MatchArm (std::vector<std::unique_ptr<Pattern> > match_arm_patterns, + MatchArm (std::vector<std::unique_ptr<Pattern>> match_arm_patterns, location_t locus, std::unique_ptr<Expr> guard_expr = nullptr, std::vector<Attribute> outer_attrs = std::vector<Attribute> ()) : outer_attrs (std::move (outer_attrs)), @@ -4463,7 +4712,7 @@ public: static MatchArm create_error () { location_t locus = UNDEF_LOCATION; - return MatchArm (std::vector<std::unique_ptr<Pattern> > (), locus); + return MatchArm (std::vector<std::unique_ptr<Pattern>> (), locus); } std::string as_string () const; @@ -4485,11 +4734,11 @@ public: const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } - const std::vector<std::unique_ptr<Pattern> > &get_patterns () const + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const { return match_arm_patterns; } - std::vector<std::unique_ptr<Pattern> > &get_patterns () + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return match_arm_patterns; } @@ -4836,29 +5085,6 @@ enum class InlineAsmOption MAY_UNWIND = 1 << 8, }; -struct AnonConst -{ - NodeId id; - std::unique_ptr<Expr> expr; - AnonConst (NodeId id, std::unique_ptr<Expr> expr) - : id (id), expr (std::move (expr)) - { - rust_assert (this->expr != nullptr); - } - AnonConst (const AnonConst &other) - { - id = other.id; - expr = other.expr->clone_expr (); - } - - AnonConst operator= (const AnonConst &other) - { - id = other.id; - expr = other.expr->clone_expr (); - return *this; - } -}; - struct InlineAsmRegOrRegClass { enum Type @@ -5288,6 +5514,20 @@ struct TupleTemplateStr // Inline Assembly Node class InlineAsm : public ExprWithoutBlock { +public: + enum class Option + { + PURE = 1 << 0, + NOMEM = 1 << 1, + READONLY = 1 << 2, + PRESERVES_FLAGS = 1 << 3, + NORETURN = 1 << 4, + NOSTACK = 1 << 5, + ATT_SYNTAX = 1 << 6, + RAW = 1 << 7, + MAY_UNWIND = 1 << 8, + }; + private: location_t locus; // TODO: Not sure how outer_attrs plays with InlineAsm, I put it here in order @@ -5311,7 +5551,7 @@ public: std::map<std::string, int> named_args; std::set<int> reg_args; std::vector<TupleClobber> clobber_abi; - std::set<InlineAsmOption> options; + std::set<InlineAsm::Option> options; std::vector<location_t> line_spans; @@ -5342,7 +5582,7 @@ public: std::vector<TupleClobber> get_clobber_abi () { return clobber_abi; } - std::set<InlineAsmOption> get_options () { return options; } + std::set<InlineAsm::Option> get_options () { return options; } InlineAsm *clone_expr_without_block_impl () const override { @@ -5350,6 +5590,33 @@ public: } Expr::Kind get_expr_kind () const override { return Expr::Kind::InlineAsm; } + + static std::string option_to_string (Option option) + { + switch (option) + { + case Option::PURE: + return "pure"; + case Option::NOMEM: + return "nomem"; + case Option::READONLY: + return "readonly"; + case Option::PRESERVES_FLAGS: + return "preserves_flags"; + case Option::NORETURN: + return "noreturn"; + case Option::NOSTACK: + return "nostack"; + case Option::ATT_SYNTAX: + return "att_syntax"; + case Option::RAW: + return "raw"; + case Option::MAY_UNWIND: + return "may_unwind"; + default: + rust_unreachable (); + } + } }; class LlvmInlineAsm : public ExprWithoutBlock diff --git a/gcc/rust/ast/rust-expression-yeast.cc b/gcc/rust/ast/rust-expression-yeast.cc new file mode 100644 index 0000000..9f6a62f --- /dev/null +++ b/gcc/rust/ast/rust-expression-yeast.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-expression-yeast.h" +#include "rust-ast-visitor.h" +#include "rust-desugar-question-mark.h" +#include "rust-desugar-try-block.h" +#include "rust-desugar-for-loops.h" +#include "rust-ast-full.h" +#include "rust-desugar-while-let.h" +#include "rust-expr.h" +#include "rust-stmt.h" + +namespace Rust { +namespace AST { + +void +ExpressionYeast::go (AST::Crate &crate) +{ + DefaultASTVisitor::visit (crate); +} + +void +ExpressionYeast::dispatch_loops (std::unique_ptr<Expr> &loop_expr) +{ + auto &loop = static_cast<BaseLoopExpr &> (*loop_expr.get ()); + + switch (loop.get_loop_kind ()) + { + case BaseLoopExpr::Kind::For: + DesugarForLoops::go (loop_expr); + break; + case BaseLoopExpr::Kind::WhileLet: + DesugarWhileLet::go (loop_expr); + break; + default: + break; + } +} + +void +ExpressionYeast::dispatch (std::unique_ptr<Expr> &expr) +{ + switch (expr->get_expr_kind ()) + { + case Expr::Kind::ErrorPropagation: + DesugarQuestionMark::go (expr); + break; + case Expr::Kind::Try: + DesugarTryBlock::go (expr); + break; + case Expr::Kind::Loop: + dispatch_loops (expr); + break; + + default: + break; + } +} + +void +ExpressionYeast::visit (ExprStmt &stmt) +{ + dispatch (stmt.get_expr_ptr ()); + + DefaultASTVisitor::visit (stmt); +} + +void +ExpressionYeast::visit (CallExpr &call) +{ + dispatch (call.get_function_expr_ptr ()); + + for (auto &arg : call.get_params ()) + dispatch (arg); + + DefaultASTVisitor::visit (call); +} + +void +ExpressionYeast::visit (BlockExpr &block) +{ + for (auto &stmt : block.get_statements ()) + if (stmt->get_stmt_kind () == Stmt::Kind::Expr) + dispatch (static_cast<ExprStmt &> (*stmt).get_expr_ptr ()); + + if (block.has_tail_expr ()) + dispatch (block.get_tail_expr_ptr ()); + + DefaultASTVisitor::visit (block); +} + +void +ExpressionYeast::visit (LetStmt &stmt) +{ + if (stmt.has_init_expr ()) + dispatch (stmt.get_init_expr_ptr ()); + + DefaultASTVisitor::visit (stmt); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/ast/rust-expression-yeast.h b/gcc/rust/ast/rust-expression-yeast.h new file mode 100644 index 0000000..855918f --- /dev/null +++ b/gcc/rust/ast/rust-expression-yeast.h @@ -0,0 +1,52 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_EXPRESSION_YEAST +#define RUST_EXPRESSION_YEAST + +#include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-desugar-question-mark.h" + +namespace Rust { +namespace AST { + +// This visitor takes care of all the expression desugars: try-blocks, +// error-propagation, etc. +class ExpressionYeast : public AST::DefaultASTVisitor +{ + using AST::DefaultASTVisitor::visit; + +public: + void go (AST::Crate &); + +private: + // Dispatch to the proper desugar + void dispatch (std::unique_ptr<Expr> &expr); + void dispatch_loops (std::unique_ptr<Expr> &loop_expr); + + void visit (AST::ExprStmt &) override; + void visit (AST::CallExpr &) override; + void visit (AST::LetStmt &) override; + void visit (AST::BlockExpr &) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_EXPRESSION_YEAST diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h index a54faec..3722db2 100644 --- a/gcc/rust/ast/rust-fmt.h +++ b/gcc/rust/ast/rust-fmt.h @@ -266,11 +266,10 @@ enum ParseMode extern "C" { -FormatArgsHandle -collect_pieces (const char *input, bool append_newline, ParseMode parse_mode); +FormatArgsHandle collect_pieces (const char *input, bool append_newline, + ParseMode parse_mode); -FormatArgsHandle -clone_pieces (const FormatArgsHandle &); +FormatArgsHandle clone_pieces (const FormatArgsHandle &); void destroy_pieces (FormatArgsHandle); diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 062f85d..d11eed7 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -51,21 +51,12 @@ class TypePath; // A type generic parameter (as opposed to a lifetime generic parameter) class TypeParam : public GenericParam { - // bool has_outer_attribute; - // std::unique_ptr<Attribute> outer_attr; AST::AttrVec outer_attrs; - Identifier type_representation; - - // bool has_type_param_bounds; - // TypeParamBounds type_param_bounds; - std::vector<std::unique_ptr<TypeParamBound>> - type_param_bounds; // inlined form - - // bool has_type; + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; std::unique_ptr<Type> type; - location_t locus; + bool was_impl_trait; public: Identifier get_type_representation () const { return type_representation; } @@ -85,18 +76,19 @@ public: std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds = std::vector<std::unique_ptr<TypeParamBound>> (), std::unique_ptr<Type> type = nullptr, - AST::AttrVec outer_attrs = {}) + AST::AttrVec outer_attrs = {}, bool was_impl_trait = false) : GenericParam (Analysis::Mappings::get ().get_next_node_id ()), outer_attrs (std::move (outer_attrs)), type_representation (std::move (type_representation)), type_param_bounds (std::move (type_param_bounds)), - type (std::move (type)), locus (locus) + type (std::move (type)), locus (locus), was_impl_trait (was_impl_trait) {} // Copy constructor uses clone TypeParam (TypeParam const &other) : GenericParam (other.node_id), outer_attrs (other.outer_attrs), - type_representation (other.type_representation), locus (other.locus) + type_representation (other.type_representation), locus (other.locus), + was_impl_trait (other.was_impl_trait) { // guard to prevent null pointer dereference if (other.type != nullptr) @@ -114,6 +106,7 @@ public: outer_attrs = other.outer_attrs; locus = other.locus; node_id = other.node_id; + was_impl_trait = other.was_impl_trait; // guard to prevent null pointer dereference if (other.type != nullptr) @@ -153,17 +146,19 @@ public: return type; } - // TODO: mutable getter seems kinda dodgy std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds () { return type_param_bounds; } + const std::vector<std::unique_ptr<TypeParamBound>> & get_type_param_bounds () const { return type_param_bounds; } + bool from_impl_trait () const { return was_impl_trait; } + protected: // Clone function implementation as virtual method TypeParam *clone_generic_param_impl () const override @@ -2455,7 +2450,7 @@ class ConstantItem : public VisItem, public AssociatedItem // either has an identifier or "_" - maybe handle in identifier? // bool identifier_is_underscore; // if no identifier declared, identifier will be "_" - std::string identifier; + Identifier identifier; std::unique_ptr<Type> type; std::unique_ptr<Expr> const_expr; @@ -2465,7 +2460,7 @@ class ConstantItem : public VisItem, public AssociatedItem public: std::string as_string () const override; - ConstantItem (std::string ident, Visibility vis, std::unique_ptr<Type> type, + ConstantItem (Identifier ident, Visibility vis, std::unique_ptr<Type> type, std::unique_ptr<Expr> const_expr, std::vector<Attribute> outer_attrs, location_t locus) : VisItem (std::move (vis), std::move (outer_attrs)), @@ -2473,7 +2468,7 @@ public: const_expr (std::move (const_expr)), locus (locus) {} - ConstantItem (std::string ident, Visibility vis, std::unique_ptr<Type> type, + ConstantItem (Identifier ident, Visibility vis, std::unique_ptr<Type> type, std::vector<Attribute> outer_attrs, location_t locus) : VisItem (std::move (vis), std::move (outer_attrs)), identifier (std::move (ident)), type (std::move (type)), @@ -2516,7 +2511,7 @@ public: /* Returns whether constant item is an "unnamed" (wildcard underscore used * as identifier) constant. */ - bool is_unnamed () const { return identifier == "_"; } + bool is_unnamed () const { return identifier.as_string () == "_"; } location_t get_locus () const override final { return locus; } @@ -2561,7 +2556,7 @@ public: return type; } - std::string get_identifier () const { return identifier; } + const Identifier &get_identifier () const { return identifier; } Item::Kind get_item_kind () const override { diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index fc01e57..4165075 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -27,6 +27,11 @@ #include "rust-macro-builtins.h" namespace Rust { + +// forward declarations for AttributeParser +class MacroInvocLexer; +template <typename ManagedTokenSource> class Parser; + namespace AST { class MacroFragSpec @@ -756,22 +761,16 @@ private: std::vector<std::unique_ptr<MacroInvocation>> pending_eager_invocs; protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_pattern_impl () const final override { return clone_macro_invocation_impl (); } - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_expr_without_block_impl () const final override { return clone_macro_invocation_impl (); } - /* Use covariance to implement clone function as returning this object rather - * than base */ MacroInvocation *clone_type_no_bounds_impl () const final override { return clone_macro_invocation_impl (); @@ -788,6 +787,20 @@ public: return new MacroInvocation (*this); } + std::unique_ptr<MacroInvocation> reconstruct_macro_invocation () const + { + return nullptr; + // return reconstruct (this, + // &MacroInvocation::reconstruct_macro_invocation_impl); + } + + MacroInvocation *reconstruct_impl () const override + { + return new MacroInvocation (kind, builtin_kind, invoc_data, outer_attrs, + locus, is_semi_coloned, + reconstruct_vec (pending_eager_invocs)); + } + void add_semicolon () override { is_semi_coloned = true; } Pattern::Kind get_pattern_kind () override @@ -1108,16 +1121,14 @@ struct AttributeParser { private: // TODO: might as well rewrite to use lexer tokens - std::vector<std::unique_ptr<Token>> token_stream; - int stream_pos; + std::unique_ptr<MacroInvocLexer> lexer; + std::unique_ptr<Parser<MacroInvocLexer>> parser; public: AttributeParser (std::vector<std::unique_ptr<Token>> token_stream, - int stream_start_pos = 0) - : token_stream (std::move (token_stream)), stream_pos (stream_start_pos) - {} + int stream_start_pos = 0); - ~AttributeParser () = default; + ~AttributeParser (); std::vector<std::unique_ptr<MetaItemInner>> parse_meta_item_seq (); @@ -1126,24 +1137,10 @@ private: std::unique_ptr<MetaItemInner> parse_meta_item_inner (); // Returns whether token can end a meta item. bool is_end_meta_item_tok (TokenId id) const; - // Parses a simple path. - SimplePath parse_simple_path (); - // Parses a segment of a simple path (but not scope resolution operator). - SimplePathSegment parse_simple_path_segment (); // Parses a MetaItemLitExpr. std::unique_ptr<MetaItemLitExpr> parse_meta_item_lit (); - // Parses a literal. - Literal parse_literal (); // Parses a meta item that begins with a simple path. std::unique_ptr<MetaItem> parse_path_meta_item (); - - // TODO: should this be const? - std::unique_ptr<Token> &peek_token (int i = 0) - { - return token_stream[stream_pos + i]; - } - - void skip_token (int i = 0) { stream_pos += 1 + i; } }; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc index 8e43ddf..793423a 100644 --- a/gcc/rust/ast/rust-path.cc +++ b/gcc/rust/ast/rust-path.cc @@ -266,6 +266,27 @@ TypePath::as_simple_path () const locus); } +std::string +TypePath::make_debug_string () const +{ + rust_assert (!segments.empty ()); + + std::string output; + + for (const auto &segment : segments) + { + if (segment != nullptr && !segment->is_lang_item () + && !segment->is_error ()) + { + if (!output.empty () || has_opening_scope_resolution_op ()) + output.append ("::"); + output.append (segment->get_ident_segment ().as_string ()); + } + } + + return output; +} + // hopefully definition here will prevent circular dependency issue TraitBound * TypePath::to_trait_bound (bool in_parens) const diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index a4ba93b..a1b19d5 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -391,6 +391,13 @@ public: return default_value.value (); } + tl::optional<GenericArg> &get_default_value () { return default_value; } + + const tl::optional<GenericArg> &get_default_value () const + { + return default_value; + } + std::string as_string () const override; void accept_vis (ASTVisitor &vis) override; @@ -779,6 +786,11 @@ public: { return new TypePathSegment (*this); } + virtual TypePathSegment *reconstruct_impl () const + { + return new TypePathSegment (lang_item, ident_segment, + has_separating_scope_resolution, locus); + } public: virtual ~TypePathSegment () {} @@ -790,6 +802,11 @@ public: { return std::unique_ptr<TypePathSegment> (clone_type_path_segment_impl ()); } + // Unique pointer custom reconstruct function + std::unique_ptr<TypePathSegment> reconstruct () const + { + return reconstruct_base (this); + } TypePathSegment (PathIdentSegment ident_segment, bool has_separating_scope_resolution, location_t locus) @@ -814,6 +831,15 @@ public: node_id (Analysis::Mappings::get ().get_next_node_id ()) {} + // General constructor + TypePathSegment (tl::optional<LangItem::Kind> lang_item, + tl::optional<PathIdentSegment> ident_segment, + bool has_separating_scope_resolution, location_t locus) + : lang_item (lang_item), ident_segment (ident_segment), locus (locus), + has_separating_scope_resolution (has_separating_scope_resolution), + node_id (Analysis::Mappings::get ().get_next_node_id ()) + {} + TypePathSegment (TypePathSegment const &other) : lang_item (other.lang_item), ident_segment (other.ident_segment), locus (other.locus), @@ -968,11 +994,7 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: is this better? Or is a "vis_pattern" better? - GenericArgs &get_generic_args () - { - rust_assert (has_generic_args ()); - return generic_args; - } + GenericArgs &get_generic_args () { return generic_args; } // Use covariance to override base class method TypePathSegmentGeneric *clone_type_path_segment_impl () const override @@ -1149,6 +1171,11 @@ protected: { return new TypePath (*this); } + TypePath *reconstruct_impl () const override + { + return new TypePath (reconstruct_vec (segments), locus, + has_opening_scope_resolution); + } public: /* Returns whether the TypePath has an opening scope resolution operator @@ -1215,6 +1242,8 @@ public: std::string as_string () const override; + std::string make_debug_string () const; + /* Converts TypePath to SimplePath if possible (i.e. no generic or function * arguments). Otherwise returns an empty SimplePath. */ SimplePath as_simple_path () const; @@ -1438,6 +1467,12 @@ protected: { return new QualifiedPathInType (*this); } + QualifiedPathInType *reconstruct_impl () const override + { + return new QualifiedPathInType (path_type, + associated_segment->reconstruct (), + reconstruct_vec (segments), locus); + } public: QualifiedPathInType ( diff --git a/gcc/rust/ast/rust-pattern.cc b/gcc/rust/ast/rust-pattern.cc index fc7b610..15ab0b7 100644 --- a/gcc/rust/ast/rust-pattern.cc +++ b/gcc/rust/ast/rust-pattern.cc @@ -65,8 +65,8 @@ IdentifierPattern::as_string () const str += variable_ident.as_string (); - if (has_pattern_to_bind ()) - str += " @ " + to_bind->as_string (); + if (has_subpattern ()) + str += " @ " + subpattern->as_string (); return str; } @@ -327,17 +327,53 @@ GroupedExpr::as_string () const } std::string -SlicePattern::as_string () const +SlicePatternItemsNoRest::as_string () const { - std::string str ("SlicePattern: "); + std::string str; - for (const auto &pattern : items) + for (const auto &pattern : patterns) str += "\n " + pattern->as_string (); return str; } std::string +SlicePatternItemsHasRest::as_string () const +{ + std::string str; + + str += "\n Lower patterns: "; + if (lower_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &lower : lower_patterns) + str += "\n " + lower->as_string (); + } + + str += "\n Upper patterns: "; + if (upper_patterns.empty ()) + { + str += "none"; + } + else + { + for (const auto &upper : upper_patterns) + str += "\n " + upper->as_string (); + } + + return str; +} + +std::string +SlicePattern::as_string () const +{ + return "SlicePattern: " + items->as_string (); +} + +std::string AltPattern::as_string () const { std::string str ("AltPattern: "); @@ -367,6 +403,18 @@ GroupedExpr::accept_vis (ASTVisitor &vis) } void +SlicePatternItemsNoRest::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void +SlicePatternItemsHasRest::accept_vis (ASTVisitor &vis) +{ + vis.visit (*this); +} + +void SlicePattern::accept_vis (ASTVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h index 69dbd98..4945ec4 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -74,7 +74,7 @@ class IdentifierPattern : public Pattern bool is_mut; // bool has_pattern; - std::unique_ptr<Pattern> to_bind; + std::unique_ptr<Pattern> subpattern; location_t locus; NodeId node_id; @@ -82,22 +82,22 @@ public: std::string as_string () const override; // Returns whether the IdentifierPattern has a pattern to bind. - bool has_pattern_to_bind () const { return to_bind != nullptr; } + bool has_subpattern () const { return subpattern != nullptr; } // Constructor IdentifierPattern (Identifier ident, location_t locus, bool is_ref = false, bool is_mut = false, - std::unique_ptr<Pattern> to_bind = nullptr) + std::unique_ptr<Pattern> subpattern = nullptr) : Pattern (), variable_ident (std::move (ident)), is_ref (is_ref), - is_mut (is_mut), to_bind (std::move (to_bind)), locus (locus), + is_mut (is_mut), subpattern (std::move (subpattern)), locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} IdentifierPattern (NodeId node_id, Identifier ident, location_t locus, bool is_ref = false, bool is_mut = false, - std::unique_ptr<Pattern> to_bind = nullptr) + std::unique_ptr<Pattern> subpattern = nullptr) : Pattern (), variable_ident (std::move (ident)), is_ref (is_ref), - is_mut (is_mut), to_bind (std::move (to_bind)), locus (locus), + is_mut (is_mut), subpattern (std::move (subpattern)), locus (locus), node_id (node_id) {} @@ -107,8 +107,8 @@ public: is_mut (other.is_mut), locus (other.locus), node_id (other.node_id) { // fix to get prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); } // Overload assignment operator to use clone @@ -121,10 +121,10 @@ public: node_id = other.node_id; // fix to prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); else - to_bind = nullptr; + subpattern = nullptr; return *this; } @@ -137,11 +137,10 @@ public: void accept_vis (ASTVisitor &vis) override; - // TODO: is this better? Or is a "vis_pattern" better? - Pattern &get_pattern_to_bind () + Pattern &get_subpattern () { - rust_assert (has_pattern_to_bind ()); - return *to_bind; + rust_assert (has_subpattern ()); + return *subpattern; } Identifier get_ident () const { return variable_ident; } @@ -375,8 +374,7 @@ enum class RangeKind EXCLUDED, }; -RangeKind -tokenid_to_rangekind (TokenId id); +RangeKind tokenid_to_rangekind (TokenId id); // AST node for matching within a certain range (range pattern) class RangePattern : public Pattern { @@ -950,7 +948,7 @@ public: * is empty). */ bool has_struct_pattern_elems () const { return !elems.is_empty (); } - location_t get_locus () const override { return path.get_locus (); } + location_t get_locus () const override { return locus; } void accept_vis (ASTVisitor &vis) override; @@ -1523,41 +1521,217 @@ protected: } }; +// Base abstract class representing patterns in a SlicePattern +class SlicePatternItems +{ +public: + enum SlicePatternItemType + { + NO_REST, + HAS_REST, + }; + + virtual ~SlicePatternItems () {} + + // TODO: should this store location data? + + // Unique pointer custom clone function + std::unique_ptr<SlicePatternItems> clone_slice_pattern_items () const + { + return std::unique_ptr<SlicePatternItems> ( + clone_slice_pattern_items_impl ()); + } + + virtual std::string as_string () const = 0; + + virtual void accept_vis (ASTVisitor &vis) = 0; + + virtual SlicePatternItemType get_pattern_type () const = 0; + +protected: + // pure virtual clone implementation + virtual SlicePatternItems *clone_slice_pattern_items_impl () const = 0; +}; + +// Class representing the patterns in a SlicePattern without `..` +class SlicePatternItemsNoRest : public SlicePatternItems +{ + std::vector<std::unique_ptr<Pattern>> patterns; + +public: + SlicePatternItemsNoRest (std::vector<std::unique_ptr<Pattern>> patterns) + : patterns (std::move (patterns)) + {} + + // Copy constructor with vector clone + SlicePatternItemsNoRest (SlicePatternItemsNoRest const &other) + { + patterns.reserve (other.patterns.size ()); + for (const auto &e : other.patterns) + patterns.push_back (e->clone_pattern ()); + } + + // Overloaded assignment operator to vector clone + SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest const &other) + { + patterns.clear (); + patterns.reserve (other.patterns.size ()); + for (const auto &e : other.patterns) + patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + SlicePatternItemsNoRest (SlicePatternItemsNoRest &&other) = default; + SlicePatternItemsNoRest &operator= (SlicePatternItemsNoRest &&other) + = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern>> &get_patterns () { return patterns; } + const std::vector<std::unique_ptr<Pattern>> &get_patterns () const + { + return patterns; + } + + SlicePatternItemType get_pattern_type () const override + { + return SlicePatternItemType::NO_REST; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + SlicePatternItemsNoRest *clone_slice_pattern_items_impl () const override + { + return new SlicePatternItemsNoRest (*this); + } +}; + +// Class representing the patterns in a SlicePattern that contains a `..` +class SlicePatternItemsHasRest : public SlicePatternItems +{ + std::vector<std::unique_ptr<Pattern>> lower_patterns; + std::vector<std::unique_ptr<Pattern>> upper_patterns; + +public: + SlicePatternItemsHasRest ( + std::vector<std::unique_ptr<Pattern>> lower_patterns, + std::vector<std::unique_ptr<Pattern>> upper_patterns) + : lower_patterns (std::move (lower_patterns)), + upper_patterns (std::move (upper_patterns)) + {} + + // Copy constructor with vector clone + SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other) + { + lower_patterns.reserve (other.lower_patterns.size ()); + for (const auto &e : other.lower_patterns) + lower_patterns.push_back (e->clone_pattern ()); + + upper_patterns.reserve (other.upper_patterns.size ()); + for (const auto &e : other.upper_patterns) + upper_patterns.push_back (e->clone_pattern ()); + } + + // Overloaded assignment operator to clone + SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest const &other) + { + lower_patterns.clear (); + lower_patterns.reserve (other.lower_patterns.size ()); + for (const auto &e : other.lower_patterns) + lower_patterns.push_back (e->clone_pattern ()); + + upper_patterns.clear (); + upper_patterns.reserve (other.upper_patterns.size ()); + for (const auto &e : other.upper_patterns) + upper_patterns.push_back (e->clone_pattern ()); + + return *this; + } + + // move constructors + SlicePatternItemsHasRest (SlicePatternItemsHasRest &&other) = default; + SlicePatternItemsHasRest &operator= (SlicePatternItemsHasRest &&other) + = default; + + std::string as_string () const override; + + void accept_vis (ASTVisitor &vis) override; + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () + { + return lower_patterns; + } + const std::vector<std::unique_ptr<Pattern>> &get_lower_patterns () const + { + return lower_patterns; + } + + // TODO: seems kinda dodgy. Think of better way. + std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () + { + return upper_patterns; + } + const std::vector<std::unique_ptr<Pattern>> &get_upper_patterns () const + { + return upper_patterns; + } + + SlicePatternItemType get_pattern_type () const override + { + return SlicePatternItemType::HAS_REST; + } + +protected: + /* Use covariance to implement clone function as returning this object rather + * than base */ + SlicePatternItemsHasRest *clone_slice_pattern_items_impl () const override + { + return new SlicePatternItemsHasRest (*this); + } +}; + // AST node representing patterns that can match slices and arrays class SlicePattern : public Pattern { - std::vector<std::unique_ptr<Pattern>> items; + std::unique_ptr<SlicePatternItems> items; location_t locus; NodeId node_id; public: std::string as_string () const override; - SlicePattern (std::vector<std::unique_ptr<Pattern>> items, location_t locus) + SlicePattern (std::unique_ptr<SlicePatternItems> items, location_t locus) : items (std::move (items)), locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) {} - // Copy constructor with vector clone + // Copy constructor requires clone SlicePattern (SlicePattern const &other) : locus (other.locus) { + // guard to prevent null dereference + rust_assert (other.items != nullptr); + node_id = other.node_id; - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_pattern ()); + items = other.items->clone_slice_pattern_items (); } - // Overloaded assignment operator to vector clone + // Overloaded assignment operator to clone SlicePattern &operator= (SlicePattern const &other) { locus = other.locus; node_id = other.node_id; - items.clear (); - items.reserve (other.items.size ()); - for (const auto &e : other.items) - items.push_back (e->clone_pattern ()); + // guard to prevent null dereference + rust_assert (other.items != nullptr); + items = other.items->clone_slice_pattern_items (); return *this; } @@ -1570,10 +1744,10 @@ public: void accept_vis (ASTVisitor &vis) override; // TODO: seems kinda dodgy. Think of better way. - std::vector<std::unique_ptr<Pattern>> &get_items () { return items; } - const std::vector<std::unique_ptr<Pattern>> &get_items () const + SlicePatternItems &get_items () { - return items; + rust_assert (items != nullptr); + return *items; } NodeId get_node_id () const override { return node_id; } diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h index 1bb521d..2a3496b 100644 --- a/gcc/rust/ast/rust-type.h +++ b/gcc/rust/ast/rust-type.h @@ -19,7 +19,9 @@ #ifndef RUST_AST_TYPE_H #define RUST_AST_TYPE_H +#include "optional.h" #include "rust-ast.h" +#include "rust-expr.h" #include "rust-path.h" namespace Rust { @@ -73,6 +75,13 @@ public: type_path (std::move (type_path)), locus (locus) {} + TraitBound (TraitBound const &other) + : TypeParamBound (other.get_node_id ()), in_parens (other.in_parens), + opening_question_mark (other.opening_question_mark), + for_lifetimes (other.for_lifetimes), type_path (other.type_path), + locus (other.locus) + {} + std::string as_string () const override; location_t get_locus () const override final { return locus; } @@ -99,6 +108,11 @@ protected: return new TraitBound (node_id, type_path, locus, in_parens, opening_question_mark, for_lifetimes); } + TraitBound *reconstruct_impl () const override + { + return new TraitBound (type_path, locus, in_parens, opening_question_mark, + for_lifetimes); + } }; // definition moved to rust-ast.h @@ -120,6 +134,10 @@ protected: { return new ImplTraitType (*this); } + ImplTraitType *reconstruct_impl () const override + { + return new ImplTraitType (reconstruct_vec (type_param_bounds), locus); + } public: ImplTraitType ( @@ -129,7 +147,8 @@ public: {} // copy constructor with vector clone - ImplTraitType (ImplTraitType const &other) : locus (other.locus) + ImplTraitType (ImplTraitType const &other) + : Type (other.node_id), locus (other.locus) { type_param_bounds.reserve (other.type_param_bounds.size ()); for (const auto &e : other.type_param_bounds) @@ -184,6 +203,11 @@ protected: { return new TraitObjectType (*this); } + TraitObjectType *reconstruct_impl () const override + { + return new TraitObjectType (reconstruct_vec (type_param_bounds), locus, + has_dyn); + } public: TraitObjectType ( @@ -195,7 +219,7 @@ public: // copy constructor with vector clone TraitObjectType (TraitObjectType const &other) - : has_dyn (other.has_dyn), locus (other.locus) + : Type (other.node_id), has_dyn (other.has_dyn), locus (other.locus) { type_param_bounds.reserve (other.type_param_bounds.size ()); for (const auto &e : other.type_param_bounds) @@ -251,6 +275,10 @@ protected: { return new ParenthesisedType (*this); } + ParenthesisedType *reconstruct_impl () const override + { + return new ParenthesisedType (type_in_parens->reconstruct (), locus); + } public: // Constructor uses Type pointer for polymorphism @@ -305,33 +333,35 @@ public: // Impl trait with a single bound? Poor reference material here. class ImplTraitTypeOneBound : public TypeNoBounds { - TraitBound trait_bound; + std::unique_ptr<TypeParamBound> trait_bound; location_t locus; -protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ - ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override - { - return new ImplTraitTypeOneBound (*this); - } - public: - ImplTraitTypeOneBound (TraitBound trait_bound, location_t locus) + ImplTraitTypeOneBound (std::unique_ptr<TypeParamBound> trait_bound, + location_t locus) : trait_bound (std::move (trait_bound)), locus (locus) {} + ImplTraitTypeOneBound (ImplTraitTypeOneBound const &other) + : trait_bound (other.trait_bound->clone_type_param_bound ()), + locus (other.locus) + {} + std::string as_string () const override; location_t get_locus () const override final { return locus; } void accept_vis (ASTVisitor &vis) override; - // TODO: would a "vis_type" be better? - TraitBound &get_trait_bound () + std::unique_ptr<TypeParamBound> &get_trait_bound () { return trait_bound; } + + TypeNoBounds *clone_type_no_bounds_impl () const override { - // TODO: check to ensure invariants are met? - return trait_bound; + return new ImplTraitTypeOneBound (*this); + } + TypeNoBounds *reconstruct_impl () const override + { + return new ImplTraitTypeOneBound (trait_bound->reconstruct (), locus); } }; @@ -350,6 +380,10 @@ protected: { return new TraitObjectTypeOneBound (*this); } + TraitObjectTypeOneBound *reconstruct_impl () const override + { + return new TraitObjectTypeOneBound (trait_bound, locus, has_dyn); + } public: TraitObjectTypeOneBound (TraitBound trait_bound, location_t locus, @@ -443,6 +477,10 @@ protected: { return new TupleType (*this); } + TupleType *reconstruct_impl () const override + { + return new TupleType (reconstruct_vec (elems), locus); + } }; /* A type with no values, representing the result of computations that never @@ -459,6 +497,10 @@ protected: { return new NeverType (*this); } + NeverType *reconstruct_impl () const override + { + return new NeverType (locus); + } public: NeverType (location_t locus) : locus (locus) {} @@ -529,6 +571,9 @@ public: return *type; } + // Getter for direct access to the type unique_ptr + std::unique_ptr<TypeNoBounds> &get_type_ptr () { return type; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -536,6 +581,10 @@ protected: { return new RawPointerType (*this); } + RawPointerType *reconstruct_impl () const override + { + return new RawPointerType (pointer_type, type->reconstruct (), locus); + } }; // A type pointing to memory owned by another value @@ -604,6 +653,9 @@ public: TypeNoBounds &get_base_type () { return *type; } + // Getter for direct access to the type unique_ptr + std::unique_ptr<TypeNoBounds> &get_type_ptr () { return type; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -611,33 +663,42 @@ protected: { return new ReferenceType (*this); } + ReferenceType *reconstruct_impl () const override + { + return new ReferenceType (has_mut, type->reconstruct (), locus, + // TODO: Improve this - it's ugly! + has_lifetime () ? tl::make_optional<Lifetime> ( + lifetime->get_lifetime_type (), + lifetime->get_lifetime_name (), + lifetime->get_locus ()) + : tl::nullopt); + } }; // A fixed-size sequence of elements of a specified type class ArrayType : public TypeNoBounds { std::unique_ptr<Type> elem_type; - std::unique_ptr<Expr> size; + AnonConst size; location_t locus; public: // Constructor requires pointers for polymorphism - ArrayType (std::unique_ptr<Type> type, std::unique_ptr<Expr> array_size, - location_t locus) + ArrayType (std::unique_ptr<Type> type, AnonConst array_size, location_t locus) : elem_type (std::move (type)), size (std::move (array_size)), locus (locus) {} // Copy constructor requires deep copies of both unique pointers ArrayType (ArrayType const &other) - : elem_type (other.elem_type->clone_type ()), - size (other.size->clone_expr ()), locus (other.locus) + : elem_type (other.elem_type->clone_type ()), size (other.size), + locus (other.locus) {} // Overload assignment operator to deep copy pointers ArrayType &operator= (ArrayType const &other) { elem_type = other.elem_type->clone_type (); - size = other.size->clone_expr (); + size = other.size; locus = other.locus; return *this; } @@ -660,12 +721,15 @@ public: } // TODO: would a "vis_expr" be better? - Expr &get_size_expr () + AnonConst &get_size_expr () { - rust_assert (size != nullptr); - return *size; + // rust_assert (size != nullptr); + + return size; } + std::unique_ptr<Type> &get_element_type () { return elem_type; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -673,6 +737,12 @@ protected: { return new ArrayType (*this); } + ArrayType *reconstruct_impl () const override + { + return new ArrayType (elem_type->reconstruct (), + size /* FIXME: This should be `reconstruct_expr()` */, + locus); + } }; /* A dynamically-sized type representing a "view" into a sequence of elements of @@ -719,13 +789,20 @@ public: return *elem_type; } + // Getter for direct access to the elem_type unique_ptr + std::unique_ptr<Type> &get_elem_type_ptr () { return elem_type; } + protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ + /* Use covariance to implement clone function as returning this object + * rather than base */ SliceType *clone_type_no_bounds_impl () const override { return new SliceType (*this); } + SliceType *reconstruct_impl () const override + { + return new SliceType (elem_type->reconstruct (), locus); + } }; /* Type used in generic arguments to explicitly request type inference (wildcard @@ -736,13 +813,21 @@ class InferredType : public TypeNoBounds // e.g. Vec<_> = whatever protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ + /* Use covariance to implement clone function as returning this object + * rather than base */ InferredType *clone_type_no_bounds_impl () const override { + // This goes through the copy constructor return new InferredType (*this); } + InferredType *reconstruct_impl () const override + { + // This goes through the base constructor which calls the base + // TypeNoBounds constructor, which allocates a new NodeId + return new InferredType (locus); + } + public: InferredType (location_t locus) : locus (locus) {} @@ -961,9 +1046,17 @@ public: FunctionQualifiers &get_function_qualifiers () { return function_qualifiers; } + BareFunctionType *reconstruct_impl () const override + { + return new BareFunctionType ( + for_lifetimes, function_qualifiers, params, + /* FIXME: Should params be reconstruct() as well? */ + _is_variadic, variadic_attrs, return_type->reconstruct (), locus); + } + protected: - /* Use covariance to implement clone function as returning this object rather - * than base */ + /* Use covariance to implement clone function as returning this object + * rather than base */ BareFunctionType *clone_type_no_bounds_impl () const override { return new BareFunctionType (*this); @@ -980,13 +1073,13 @@ class MacroInvocation; * function item type? * closure expression types? * primitive types (bool, int, float, char, str (the slice)) - * Although supposedly TypePaths are used to reference these types (including - * primitives) */ + * Although supposedly TypePaths are used to reference these types + * (including primitives) */ /* FIXME: Incomplete spec references: - * anonymous type parameters, aka "impl Trait in argument position" - impl then - * trait bounds abstract return types, aka "impl Trait in return position" - - * impl then trait bounds */ + * anonymous type parameters, aka "impl Trait in argument position" - impl + * then trait bounds abstract return types, aka "impl Trait in return + * position" - impl then trait bounds */ } // namespace AST } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc index 7351cf0..b7143a8 100644 --- a/gcc/rust/backend/rust-compile-asm.cc +++ b/gcc/rust/backend/rust-compile-asm.cc @@ -74,57 +74,94 @@ CompileAsm::asm_construct_string_tree (HIR::InlineAsm &expr) return Backend::string_constant_expression (result); } +tl::optional<std::reference_wrapper<HIR::Expr>> +get_out_expr (HIR::InlineAsmOperand &operand) +{ + switch (operand.get_register_type ()) + { + case HIR::InlineAsmOperand::RegisterType::Out: + return *operand.get_out ().expr; + case HIR::InlineAsmOperand::RegisterType::InOut: + return *operand.get_in_out ().expr; + case HIR::InlineAsmOperand::RegisterType::SplitInOut: + return *operand.get_split_in_out ().out_expr; + case HIR::InlineAsmOperand::RegisterType::Const: + case HIR::InlineAsmOperand::RegisterType::Sym: + case HIR::InlineAsmOperand::RegisterType::Label: + case HIR::InlineAsmOperand::RegisterType::In: + break; + } + return tl::nullopt; +} + tree CompileAsm::asm_construct_outputs (HIR::InlineAsm &expr) { // TODO: Do i need to do this? tree head = NULL_TREE; - for (auto &output : expr.get_operands ()) + for (auto &operand : expr.get_operands ()) { - if (output.get_register_type () - == AST::InlineAsmOperand::RegisterType::Out) - { - auto out = output.get_out (); - - tree out_tree = CompileExpr::Compile (*out.expr, this->ctx); - // expects a tree list - // TODO: This assumes that the output is a register - std::string expr_name = "=r"; - auto name = build_string (expr_name.size () + 1, expr_name.c_str ()); - head - = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name), - out_tree)); - - /*Backend::debug (head);*/ - /*head = chainon (head, out_tree);*/ - } + tl::optional<std::reference_wrapper<HIR::Expr>> out_expr + = get_out_expr (operand); + if (!out_expr.has_value ()) + continue; + + tree out_tree = CompileExpr::Compile (*out_expr, this->ctx); + // expects a tree list + // TODO: This assumes that the output is a register + std::string expr_name = "=r"; + auto name = build_string (expr_name.size () + 1, expr_name.c_str ()); + head = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name), + out_tree)); + + /*Backend::debug (head);*/ + /*head = chainon (head, out_tree);*/ } return head; } +tl::optional<std::reference_wrapper<HIR::Expr>> +get_in_expr (HIR::InlineAsmOperand &operand) +{ + switch (operand.get_register_type ()) + { + case HIR::InlineAsmOperand::RegisterType::In: + return *operand.get_in ().expr; + case HIR::InlineAsmOperand::RegisterType::InOut: + return *operand.get_in_out ().expr; + case HIR::InlineAsmOperand::RegisterType::SplitInOut: + return *operand.get_split_in_out ().in_expr; + case HIR::InlineAsmOperand::RegisterType::Const: + case HIR::InlineAsmOperand::RegisterType::Sym: + case HIR::InlineAsmOperand::RegisterType::Label: + case HIR::InlineAsmOperand::RegisterType::Out: + break; + } + return tl::nullopt; +} + tree CompileAsm::asm_construct_inputs (HIR::InlineAsm &expr) { // TODO: Do i need to do this? tree head = NULL_TREE; - for (auto &input : expr.get_operands ()) + for (auto &operand : expr.get_operands ()) { - if (input.get_register_type () == AST::InlineAsmOperand::RegisterType::In) - { - auto in = input.get_in (); - - tree in_tree = CompileExpr::Compile (*in.expr, this->ctx); - // expects a tree list - // TODO: This assumes that the input is a register - std::string expr_name = "r"; - auto name = build_string (expr_name.size () + 1, expr_name.c_str ()); - head - = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name), - in_tree)); - - /*head = chainon (head, out_tree);*/ - } + tl::optional<std::reference_wrapper<HIR::Expr>> in_expr + = get_in_expr (operand); + if (!in_expr.has_value ()) + continue; + + tree in_tree = CompileExpr::Compile (*in_expr, this->ctx); + // expects a tree list + // TODO: This assumes that the input is a register + std::string expr_name = "r"; + auto name = build_string (expr_name.size () + 1, expr_name.c_str ()); + head = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name), + in_tree)); + + /*head = chainon (head, out_tree);*/ } return head; } diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 12b9561..73c34b2 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -576,6 +576,25 @@ HIRCompileBase::compile_constant_expr ( } tree +HIRCompileBase::query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty, + HIR::Expr &const_value_expr) +{ + HIRCompileBase c (ctx); + + ctx->push_const_context (); + + HirId expr_id = const_value_expr.get_mappings ().get_hirid (); + location_t locus = const_value_expr.get_locus (); + tree capacity_expr = HIRCompileBase::compile_constant_expr ( + ctx, expr_id, expr_ty, expr_ty, Resolver::CanonicalPath::create_empty (), + const_value_expr, locus, locus); + + ctx->pop_const_context (); + + return fold_expr (capacity_expr); +} + +tree HIRCompileBase::indirect_expression (tree expr, location_t locus) { if (expr == error_mark_node) @@ -677,8 +696,12 @@ HIRCompileBase::compile_function ( std::string ir_symbol_name = canonical_path.get () + fntype->subst_as_string (); + rust_debug_loc (locus, "--> Compiling [%s] - %s", ir_symbol_name.c_str (), + fntype->get_name ().c_str ()); + // we don't mangle the main fn since we haven't implemented the main shim - bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item; + bool is_main_fn = fn_name.compare ("main") == 0 && is_root_item + && canonical_path.size () <= 2; if (is_main_fn) { rust_assert (!main_identifier_node); @@ -687,14 +710,9 @@ HIRCompileBase::compile_function ( } std::string asm_name = fn_name; - auto &mappings = Analysis::Mappings::get (); - - if (flag_name_resolution_2_0) - ir_symbol_name = mappings.get_current_crate_name () + "::" + ir_symbol_name; - unsigned int flags = 0; tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, - "" /* asm_name */, flags, locus); + tl::nullopt /* asm_name */, flags, locus); setup_fndecl (fndecl, is_main_fn, fntype->has_substitutions_defined (), visibility, qualifiers, outer_attrs); @@ -812,11 +830,12 @@ HIRCompileBase::compile_constant_item ( // machineary that we already have. This means the best approach is to // make a _fake_ function with a block so it can hold onto temps then // use our constexpr code to fold it completely or error_mark_node - Backend::typed_identifier receiver; + Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION); tree compiled_fn_type = Backend::function_type ( receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, NULL, locus); - tree fndecl = Backend::function (compiled_fn_type, ident, "", 0, locus); + tree fndecl + = Backend::function (compiled_fn_type, ident, tl::nullopt, 0, locus); TREE_READONLY (fndecl) = 1; tree enclosing_scope = NULL_TREE; diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index 6814abc..e9b8596 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -38,6 +38,9 @@ public: const Resolver::CanonicalPath &canonical_path, HIR::Expr &const_value_expr, location_t locus, location_t expr_locus); + static tree query_compile_const_expr (Context *ctx, TyTy::BaseType *expr_ty, + HIR::Expr &const_value_expr); + protected: HIRCompileBase (Context *ctx) : ctx (ctx) {} diff --git a/gcc/rust/backend/rust-compile-block.cc b/gcc/rust/backend/rust-compile-block.cc index f844a27..03c36d2 100644 --- a/gcc/rust/backend/rust-compile-block.cc +++ b/gcc/rust/backend/rust-compile-block.cc @@ -19,6 +19,7 @@ #include "rust-compile-block.h" #include "rust-compile-stmt.h" #include "rust-compile-expr.h" +#include "rust-hir-expr.h" namespace Rust { namespace Compile { diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h index 3f38d08..f84bace 100644 --- a/gcc/rust/backend/rust-compile-block.h +++ b/gcc/rust/backend/rust-compile-block.h @@ -20,6 +20,7 @@ #define RUST_COMPILE_BLOCK #include "rust-compile-base.h" +#include "rust-hir-expr.h" #include "rust-hir-visitor.h" namespace Rust { @@ -83,6 +84,8 @@ public: void visit (HIR::MethodCallExpr &) override {} void visit (HIR::FieldAccessExpr &) override {} void visit (HIR::BlockExpr &) override {} + void visit (HIR::AnonConst &) override {} + void visit (HIR::ConstBlock &) override {} void visit (HIR::ContinueExpr &) override {} void visit (HIR::BreakExpr &) override {} void visit (HIR::RangeFromToExpr &) override {} @@ -101,6 +104,7 @@ public: void visit (HIR::AsyncBlockExpr &) override {} void visit (HIR::InlineAsm &) override {} void visit (HIR::LlvmInlineAsm &) override {} + void visit (HIR::OffsetOf &) override {} private: CompileConditionalBlocks (Context *ctx, Bvariable *result) @@ -138,6 +142,12 @@ public: translated = CompileBlock::compile (expr, ctx, result); } + void visit (HIR::ConstBlock &expr) override + { + rust_unreachable (); + // translated = CompileExpr::compile (expr, ctx, result); + } + // Empty visit for unused Expression HIR nodes. void visit (HIR::PathInExpression &) override {} void visit (HIR::QualifiedPathInExpression &) override {} @@ -184,6 +194,8 @@ public: void visit (HIR::AsyncBlockExpr &) override {} void visit (HIR::InlineAsm &) override {} void visit (HIR::LlvmInlineAsm &) override {} + void visit (HIR::OffsetOf &) override {} + void visit (HIR::AnonConst &) override {} private: CompileExprWithBlock (Context *ctx, Bvariable *result) diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index 86f0894..349d492 100644 --- a/gcc/rust/backend/rust-compile-context.cc +++ b/gcc/rust/backend/rust-compile-context.cc @@ -22,9 +22,18 @@ namespace Rust { namespace Compile { +Context * +Context::get () +{ + static Context *instance; + if (instance == nullptr) + instance = new Context (); + + return instance; +} + Context::Context () - : resolver (Resolver::Resolver::get ()), - tyctx (Resolver::TypeCheckContext::get ()), + : tyctx (Resolver::TypeCheckContext::get ()), mappings (Analysis::Mappings::get ()), mangler (Mangler ()) { setup_builtins (); @@ -70,7 +79,8 @@ Context::type_hasher (tree type) hstate.add_object (TYPE_HASH (TYPE_OFFSET_BASETYPE (type))); break; - case ARRAY_TYPE: { + case ARRAY_TYPE: + { if (TYPE_DOMAIN (type)) hstate.add_object (TYPE_HASH (TYPE_DOMAIN (type))); if (!AGGREGATE_TYPE_P (TREE_TYPE (type))) @@ -81,7 +91,8 @@ Context::type_hasher (tree type) } break; - case INTEGER_TYPE: { + case INTEGER_TYPE: + { tree t = TYPE_MAX_VALUE (type); if (!t) t = TYPE_MIN_VALUE (type); @@ -91,7 +102,8 @@ Context::type_hasher (tree type) } case REAL_TYPE: - case FIXED_POINT_TYPE: { + case FIXED_POINT_TYPE: + { unsigned prec = TYPE_PRECISION (type); hstate.add_object (prec); break; @@ -103,7 +115,8 @@ Context::type_hasher (tree type) case RECORD_TYPE: case UNION_TYPE: - case QUAL_UNION_TYPE: { + case QUAL_UNION_TYPE: + { for (tree t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t)) { hashval_t name_hash = IDENTIFIER_HASH_VALUE (DECL_NAME (t)); @@ -118,7 +131,8 @@ Context::type_hasher (tree type) break; case REFERENCE_TYPE: - case POINTER_TYPE: { + case POINTER_TYPE: + { hashval_t type_hash = type_hasher (TREE_TYPE (type)); hstate.add_object (type_hash); } diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h index ce81a1d..d4a642b 100644 --- a/gcc/rust/backend/rust-compile-context.h +++ b/gcc/rust/backend/rust-compile-context.h @@ -49,7 +49,7 @@ struct CustomDeriveInfo class Context { public: - Context (); + static Context *get (); void setup_builtins (); @@ -90,7 +90,6 @@ public: return type; } - Resolver::Resolver *get_resolver () { return resolver; } Resolver::TypeCheckContext *get_tyctx () { return tyctx; } Analysis::Mappings &get_mappings () { return mappings; } @@ -391,7 +390,8 @@ public: } private: - Resolver::Resolver *resolver; + Context (); + Resolver::TypeCheckContext *tyctx; Analysis::Mappings &mappings; Mangler mangler; diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index dd3420f..6433923 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -17,6 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-compile-expr.h" +#include "rust-backend.h" +#include "rust-compile-type.h" #include "rust-compile-struct-field-expr.h" #include "rust-compile-pattern.h" #include "rust-compile-resolve-path.h" @@ -30,8 +32,11 @@ #include "realmpfr.h" #include "convert.h" #include "print-tree.h" +#include "rust-hir-expr.h" #include "rust-system.h" +#include "rust-tree.h" #include "rust-tyty.h" +#include "tree-core.h" namespace Rust { namespace Compile { @@ -375,6 +380,31 @@ CompileExpr::visit (HIR::LlvmInlineAsm &expr) } void +CompileExpr::visit (HIR::OffsetOf &expr) +{ + TyTy::BaseType *type = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + expr.get_type ().get_mappings ().get_hirid (), &type)) + { + translated = error_mark_node; + return; + } + + auto compiled_ty = TyTyResolveCompile::compile (ctx, type); + + rust_assert (TREE_CODE (compiled_ty) == RECORD_TYPE); + + // Create an identifier node for the field + auto field_id = Backend::get_identifier_node (expr.get_field ().as_string ()); + + // And now look it up and get its value for `byte_position` + auto field = Backend::lookup_field (compiled_ty, field_id); + auto field_value = TREE_VALUE (field); + + translated = byte_position (field_value); +} + +void CompileExpr::visit (HIR::IfExprConseqElse &expr) { TyTy::BaseType *if_type = nullptr; @@ -441,6 +471,18 @@ CompileExpr::visit (HIR::BlockExpr &expr) } void +CompileExpr::visit (HIR::AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +CompileExpr::visit (HIR::ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + +void CompileExpr::visit (HIR::UnsafeBlockExpr &expr) { expr.get_block_expr ().accept_vis (*this); @@ -471,6 +513,8 @@ CompileExpr::visit (HIR::StructExprStructFields &struct_expr) rust_error_at (struct_expr.get_locus (), "unknown type"); return; } + if (!tyty->is<TyTy::ADTType> ()) + return; // it must be an ADT rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT); @@ -669,6 +713,15 @@ void CompileExpr::visit (HIR::LoopExpr &expr) { TyTy::BaseType *block_tyty = nullptr; + fncontext fnctx = ctx->peek_fn (); + if (ctx->const_context_p () && !DECL_DECLARED_CONSTEXPR_P (fnctx.fndecl)) + { + rich_location r (line_table, expr.get_locus ()); + rust_error_at (r, ErrorCode::E0658, + "%<loop%> is not allowed in const context"); + return; + } + if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (), &block_tyty)) { @@ -676,7 +729,6 @@ CompileExpr::visit (HIR::LoopExpr &expr) return; } - fncontext fnctx = ctx->peek_fn (); tree enclosing_scope = ctx->peek_enclosing_scope (); tree block_type = TyTyResolveCompile::compile (ctx, block_tyty); @@ -701,7 +753,8 @@ CompileExpr::visit (HIR::LoopExpr &expr) loop_label.get_lifetime ().get_mappings ().get_hirid (), label); } - tree loop_begin_label = Backend::label (fnctx.fndecl, "", expr.get_locus ()); + tree loop_begin_label + = Backend::label (fnctx.fndecl, tl::nullopt, expr.get_locus ()); tree loop_begin_label_decl = Backend::label_definition_statement (loop_begin_label); ctx->add_statement (loop_begin_label_decl); @@ -743,7 +796,8 @@ CompileExpr::visit (HIR::WhileLoopExpr &expr) start_location, end_location); ctx->push_block (loop_block); - tree loop_begin_label = Backend::label (fnctx.fndecl, "", expr.get_locus ()); + tree loop_begin_label + = Backend::label (fnctx.fndecl, tl::nullopt, expr.get_locus ()); tree loop_begin_label_decl = Backend::label_definition_statement (loop_begin_label); ctx->add_statement (loop_begin_label_decl); @@ -787,25 +841,16 @@ CompileExpr::visit (HIR::BreakExpr &expr) if (expr.has_label ()) { - NodeId resolved_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (auto id - = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) - resolved_node_id = *id; - } - else + NodeId resolved_node_id; + if (auto id + = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) { - NodeId tmp = UNKNOWN_NODEID; - if (ctx->get_resolver ()->lookup_resolved_label ( - expr.get_label ().get_mappings ().get_nodeid (), &tmp)) - resolved_node_id = tmp; + resolved_node_id = *id; } - - if (resolved_node_id == UNKNOWN_NODEID) + else { rust_error_at ( expr.get_label ().get_locus (), @@ -849,26 +894,16 @@ CompileExpr::visit (HIR::ContinueExpr &expr) tree label = ctx->peek_loop_begin_label (); if (expr.has_label ()) { - NodeId resolved_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (auto id - = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) - resolved_node_id = *id; - } - else + NodeId resolved_node_id; + if (auto id + = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ())) { - NodeId tmp = UNKNOWN_NODEID; - - if (ctx->get_resolver ()->lookup_resolved_label ( - expr.get_label ().get_mappings ().get_nodeid (), &tmp)) - resolved_node_id = tmp; + resolved_node_id = *id; } - - if (resolved_node_id == UNKNOWN_NODEID) + else { rust_error_at ( expr.get_label ().get_locus (), @@ -1130,9 +1165,8 @@ CompileExpr::visit (HIR::MatchExpr &expr) // setup the end label so the cases can exit properly tree fndecl = fnctx.fndecl; location_t end_label_locus = expr.get_locus (); // FIXME - tree end_label - = Backend::label (fndecl, "" /* empty creates an artificial label */, - end_label_locus); + // tl::nullopt creates an artificial label + tree end_label = Backend::label (fndecl, tl::nullopt, end_label_locus); tree end_label_decl_statement = Backend::label_definition_statement (end_label); @@ -1325,6 +1359,28 @@ CompileExpr::visit (HIR::CallExpr &expr) }; auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx); + if (ctx->const_context_p ()) + { + if (!FUNCTION_POINTER_TYPE_P (TREE_TYPE (fn_address))) + { + rust_error_at (expr.get_locus (), + "calls in constants are limited to constant " + "functions, tuple structs and tuple variants"); + return; + } + + if (TREE_CODE (fn_address) == ADDR_EXPR) + { + tree fndecl = TREE_OPERAND (fn_address, 0); + if (!DECL_DECLARED_CONSTEXPR_P (fndecl)) + { + rust_error_at (expr.get_locus (), + "calls in constants are limited to constant " + "functions, tuple structs and tuple variants"); + return; + } + } + } // is this a closure call? bool possible_trait_call @@ -1883,7 +1939,8 @@ CompileExpr::visit (HIR::ArrayExpr &expr) HIR::ArrayElems &elements = expr.get_internal_elements (); switch (elements.get_array_expr_type ()) { - case HIR::ArrayElems::ArrayExprType::VALUES: { + case HIR::ArrayElems::ArrayExprType::VALUES: + { HIR::ArrayElemsValues &elems = static_cast<HIR::ArrayElemsValues &> (elements); translated @@ -2032,7 +2089,8 @@ HIRCompileBase::resolve_adjustements ( return error_mark_node; case Resolver::Adjustment::AdjustmentType::IMM_REF: - case Resolver::Adjustment::AdjustmentType::MUT_REF: { + case Resolver::Adjustment::AdjustmentType::MUT_REF: + { if (!RS_DST_FLAG (TREE_TYPE (e))) { e = address_expression (e, locus); @@ -2474,23 +2532,12 @@ CompileExpr::generate_closure_function (HIR::ClosureExpr &expr, if (is_block_expr) { auto body_mappings = function_body.get_mappings (); - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); + auto candidate = nr_ctx.values.to_rib (body_mappings.get_nodeid ()); - rust_assert (candidate.has_value ()); - } - else - { - Resolver::Rib *rib = nullptr; - bool ok - = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), - &rib); - rust_assert (ok); - } + rust_assert (candidate.has_value ()); } tree enclosing_scope = NULL_TREE; diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 65ed4b3..b8b4e8d 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -48,6 +48,8 @@ public: void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::BlockExpr &expr) override; + void visit (HIR::AnonConst &expr) override; + void visit (HIR::ConstBlock &expr) override; void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::StructExprStruct &struct_expr) override; void visit (HIR::StructExprStructFields &struct_expr) override; @@ -70,6 +72,7 @@ public: void visit (HIR::ClosureExpr &expr) override; void visit (HIR::InlineAsm &expr) override; void visit (HIR::LlvmInlineAsm &expr) override; + void visit (HIR::OffsetOf &expr) override; // TODO void visit (HIR::ErrorPropagationExpr &) override {} diff --git a/gcc/rust/backend/rust-compile-implitem.cc b/gcc/rust/backend/rust-compile-implitem.cc index 1230c85..63df2f5 100644 --- a/gcc/rust/backend/rust-compile-implitem.cc +++ b/gcc/rust/backend/rust-compile-implitem.cc @@ -27,22 +27,11 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant) rust_assert (concrete != nullptr); TyTy::BaseType *resolved_type = concrete; - tl::optional<Resolver::CanonicalPath> canonical_path; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path = nr_ctx.values.to_canonical_path ( - constant.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = ctx->get_mappings ().lookup_canonical_path ( - constant.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path); + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (constant.get_mappings ().get_nodeid ()); HIR::Expr &const_value_expr = constant.get_expr (); TyTy::BaseType *expr_type = nullptr; @@ -52,7 +41,7 @@ CompileTraitItem::visit (HIR::TraitItemConst &constant) tree const_expr = compile_constant_item (constant.get_mappings ().get_hirid (), expr_type, - resolved_type, *canonical_path, const_value_expr, + resolved_type, canonical_path, const_value_expr, constant.get_locus (), const_value_expr.get_locus ()); ctx->push_const (const_expr); @@ -96,22 +85,11 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func) fntype->override_context (); } - tl::optional<Resolver::CanonicalPath> canonical_path; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (func.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = ctx->get_mappings ().lookup_canonical_path ( - func.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path); + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (func.get_mappings ().get_nodeid ()); // FIXME: How do we get the proper visibility here? auto vis = HIR::Visibility (HIR::Visibility::VisType::PUBLIC); @@ -121,7 +99,7 @@ CompileTraitItem::visit (HIR::TraitItemFunc &func) function.get_self (), function.get_function_params (), function.get_qualifiers (), vis, func.get_outer_attrs (), func.get_locus (), - &func.get_block_expr (), *canonical_path, fntype); + &func.get_block_expr (), canonical_path, fntype); reference = address_expression (fndecl, ref_locus); } diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 4888e23..450a869 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -32,8 +32,7 @@ // declaration taken from "stringpool.h" // the get_identifier macro causes compilation issues -extern tree -get_identifier (const char *); +extern tree get_identifier (const char *); namespace Rust { namespace Compile { @@ -70,28 +69,19 @@ check_for_basic_integer_type (const std::string &intrinsic_str, return is_basic_integer; } -static tree -offset_handler (Context *ctx, TyTy::FnType *fntype); -static tree -sizeof_handler (Context *ctx, TyTy::FnType *fntype); -static tree -transmute_handler (Context *ctx, TyTy::FnType *fntype); -static tree -rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); -static tree -wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); -static tree -op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); -static tree -uninit_handler (Context *ctx, TyTy::FnType *fntype); -static tree -move_val_init_handler (Context *ctx, TyTy::FnType *fntype); -static tree -assume_handler (Context *ctx, TyTy::FnType *fntype); -static tree -discriminant_value_handler (Context *ctx, TyTy::FnType *fntype); -static tree -variant_count_handler (Context *ctx, TyTy::FnType *fntype); +static tree offset_handler (Context *ctx, TyTy::FnType *fntype); +static tree sizeof_handler (Context *ctx, TyTy::FnType *fntype); +static tree transmute_handler (Context *ctx, TyTy::FnType *fntype); +static tree rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); +static tree wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, + tree_code op); +static tree op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, + tree_code op); +static tree uninit_handler (Context *ctx, TyTy::FnType *fntype); +static tree move_val_init_handler (Context *ctx, TyTy::FnType *fntype); +static tree assume_handler (Context *ctx, TyTy::FnType *fntype); +static tree discriminant_value_handler (Context *ctx, TyTy::FnType *fntype); +static tree variant_count_handler (Context *ctx, TyTy::FnType *fntype); enum class Prefetch { @@ -99,8 +89,8 @@ enum class Prefetch Write }; -static tree -prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, Prefetch kind); +static tree prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, + Prefetch kind); static inline tree rotate_left_handler (Context *ctx, TyTy::FnType *fntype) @@ -140,10 +130,10 @@ prefetch_write_data (Context *ctx, TyTy::FnType *fntype) return prefetch_data_handler (ctx, fntype, Prefetch::Write); } -static tree -atomic_store_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering); -static tree -atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering); +static tree atomic_store_handler_inner (Context *ctx, TyTy::FnType *fntype, + int ordering); +static tree atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, + int ordering); static inline std::function<tree (Context *, TyTy::FnType *)> atomic_store_handler (int ordering) @@ -161,8 +151,8 @@ atomic_load_handler (int ordering) }; } -static inline tree -unchecked_op_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); +static inline tree unchecked_op_inner (Context *ctx, TyTy::FnType *fntype, + tree_code op); const static std::function<tree (Context *, TyTy::FnType *)> unchecked_op_handler (tree_code op) @@ -172,8 +162,8 @@ unchecked_op_handler (tree_code op) }; } -static inline tree -copy_handler_inner (Context *ctx, TyTy::FnType *fntype, bool overlaps); +static inline tree copy_handler_inner (Context *ctx, TyTy::FnType *fntype, + bool overlaps); const static std::function<tree (Context *, TyTy::FnType *)> copy_handler (bool overlaps) @@ -183,8 +173,8 @@ copy_handler (bool overlaps) }; } -static inline tree -expect_handler_inner (Context *ctx, TyTy::FnType *fntype, bool likely); +static inline tree expect_handler_inner (Context *ctx, TyTy::FnType *fntype, + bool likely); const static std::function<tree (Context *, TyTy::FnType *)> expect_handler (bool likely) @@ -194,8 +184,8 @@ expect_handler (bool likely) }; } -static tree -try_handler_inner (Context *ctx, TyTy::FnType *fntype, bool is_new_api); +static tree try_handler_inner (Context *ctx, TyTy::FnType *fntype, + bool is_new_api); const static std::function<tree (Context *, TyTy::FnType *)> try_handler (bool is_new_api) @@ -447,8 +437,8 @@ sizeof_handler (Context *ctx, TyTy::FnType *fntype) // get the template parameter type tree fn size_of<T>(); rust_assert (fntype->get_num_substitutions () == 1); auto ¶m_mapping = fntype->get_substs ().at (0); - const TyTy::ParamType *param_tyty = param_mapping.get_param_ty (); - TyTy::BaseType *resolved_tyty = param_tyty->resolve (); + const auto param_tyty = param_mapping.get_param_ty (); + auto resolved_tyty = param_tyty->resolve (); tree template_parameter_type = TyTyResolveCompile::compile (ctx, resolved_tyty); @@ -653,8 +643,8 @@ op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op) rust_assert (fntype->get_num_substitutions () == 1); auto ¶m_mapping = fntype->get_substs ().at (0); - const TyTy::ParamType *param_tyty = param_mapping.get_param_ty (); - TyTy::BaseType *resolved_tyty = param_tyty->resolve (); + const auto param_tyty = param_mapping.get_param_ty (); + auto resolved_tyty = param_tyty->resolve (); tree template_parameter_type = TyTyResolveCompile::compile (ctx, resolved_tyty); @@ -1089,8 +1079,8 @@ uninit_handler (Context *ctx, TyTy::FnType *fntype) // get the template parameter type tree fn uninit<T>(); rust_assert (fntype->get_num_substitutions () == 1); auto ¶m_mapping = fntype->get_substs ().at (0); - const TyTy::ParamType *param_tyty = param_mapping.get_param_ty (); - TyTy::BaseType *resolved_tyty = param_tyty->resolve (); + const auto param_tyty = param_mapping.get_param_ty (); + auto resolved_tyty = param_tyty->resolve (); tree template_parameter_type = TyTyResolveCompile::compile (ctx, resolved_tyty); @@ -1154,8 +1144,8 @@ move_val_init_handler (Context *ctx, TyTy::FnType *fntype) // get the template parameter type tree fn size_of<T>(); rust_assert (fntype->get_num_substitutions () == 1); auto ¶m_mapping = fntype->get_substs ().at (0); - const TyTy::ParamType *param_tyty = param_mapping.get_param_ty (); - TyTy::BaseType *resolved_tyty = param_tyty->resolve (); + auto param_tyty = param_mapping.get_param_ty (); + auto resolved_tyty = param_tyty->resolve (); tree template_parameter_type = TyTyResolveCompile::compile (ctx, resolved_tyty); diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc index 9666990..b72e70d 100644 --- a/gcc/rust/backend/rust-compile-item.cc +++ b/gcc/rust/backend/rust-compile-item.cc @@ -50,33 +50,21 @@ CompileItem::visit (HIR::StaticItem &var) tree type = TyTyResolveCompile::compile (ctx, resolved_type); - tl::optional<Resolver::CanonicalPath> canonical_path; + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (var.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = ctx->get_mappings ().lookup_canonical_path ( - var.get_mappings ().get_nodeid ()); - } - - rust_assert (canonical_path.has_value ()); + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (var.get_mappings ().get_nodeid ()); ctx->push_const_context (); tree value = compile_constant_item (var.get_mappings ().get_hirid (), expr_type, - resolved_type, *canonical_path, const_value_expr, + resolved_type, canonical_path, const_value_expr, var.get_locus (), const_value_expr.get_locus ()); ctx->pop_const_context (); - std::string name = canonical_path->get (); - std::string asm_name = ctx->mangle_item (resolved_type, *canonical_path); + std::string name = canonical_path.get (); + std::string asm_name = ctx->mangle_item (resolved_type, canonical_path); bool is_external = false; bool is_hidden = false; @@ -115,24 +103,12 @@ CompileItem::visit (HIR::ConstantItem &constant) const_value_expr.get_mappings ().get_hirid (), &expr_type); rust_assert (ok); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + // canonical path Resolver::CanonicalPath canonical_path - = Resolver::CanonicalPath::create_empty (); - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (mappings.get_nodeid ()).value (); - } - else - { - canonical_path = ctx->get_mappings () - .lookup_canonical_path (mappings.get_nodeid ()) - .value (); - } + = nr_ctx.to_canonical_path (mappings.get_nodeid ()); ctx->push_const_context (); tree const_expr @@ -210,26 +186,11 @@ CompileItem::visit (HIR::Function &function) } } - Resolver::CanonicalPath canonical_path - = Resolver::CanonicalPath::create_empty (); - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - auto path = nr_ctx.values.to_canonical_path ( - function.get_mappings ().get_nodeid ()); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - canonical_path = path.value (); - } - else - { - auto path = ctx->get_mappings ().lookup_canonical_path ( - function.get_mappings ().get_nodeid ()); - - canonical_path = *path; - } + Resolver::CanonicalPath canonical_path + = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); const std::string asm_name = ctx->mangle_item (fntype, canonical_path); @@ -300,5 +261,65 @@ CompileItem::visit (HIR::Module &module) CompileItem::compile (item.get (), ctx); } +void +CompileItem::visit (HIR::TupleStruct &tuple_struct_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type ( + tuple_struct_decl.get_mappings ().get_hirid (), &lookup)) + { + rust_error_at (tuple_struct_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::Enum &enum_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (enum_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (enum_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::Union &union_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (union_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (union_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + +void +CompileItem::visit (HIR::StructStruct &struct_decl) +{ + TyTy::BaseType *lookup = nullptr; + if (!ctx->get_tyctx ()->lookup_type (struct_decl.get_mappings ().get_hirid (), + &lookup)) + { + rust_error_at (struct_decl.get_locus (), "failed to resolve type"); + return; + } + + if (lookup->is_concrete ()) + TyTyResolveCompile::compile (ctx, lookup); +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index d9d946d..56baaab 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -44,9 +44,12 @@ public: void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; void visit (HIR::Module &module) override; + void visit (HIR::TupleStruct &tuple_struct) override; + void visit (HIR::Enum &enum_decl) override; + void visit (HIR::Union &union_decl) override; + void visit (HIR::StructStruct &struct_decl) override; // Empty visit for unused Stmt HIR nodes. - void visit (HIR::TupleStruct &) override {} void visit (HIR::EnumItem &) override {} void visit (HIR::EnumItemTuple &) override {} void visit (HIR::EnumItemStruct &) override {} @@ -57,9 +60,6 @@ public: void visit (HIR::ExternCrate &) override {} void visit (HIR::UseDeclaration &) override {} void visit (HIR::TypeAlias &) override {} - void visit (HIR::StructStruct &) override {} - void visit (HIR::Enum &) override {} - void visit (HIR::Union &) override {} void visit (HIR::Trait &) override {} void visit (HIR::EmptyStmt &) override {} void visit (HIR::LetStmt &) override {} diff --git a/gcc/rust/backend/rust-compile-pattern.cc b/gcc/rust/backend/rust-compile-pattern.cc index e83717b..fe65921 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -22,6 +22,11 @@ #include "rust-constexpr.h" #include "rust-compile-type.h" #include "print-tree.h" +#include "rust-diagnostics.h" +#include "rust-hir-pattern-abstract.h" +#include "rust-hir-pattern.h" +#include "rust-system.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -107,7 +112,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, tree result = NULL_TREE; switch (bound.get_bound_type ()) { - case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: + { auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound); HIR::LiteralExpr litexpr (mappings, ref.get_literal (), locus, @@ -117,7 +123,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, } break; - case HIR::RangePatternBound::RangePatternBoundType::PATH: { + case HIR::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound); result = ResolvePathRef::Compile (ref.get_path (), ctx); @@ -127,7 +134,8 @@ compile_range_pattern_bound (HIR::RangePatternBound &bound, } break; - case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound); result = ResolvePathRef::Compile (ref.get_qualified_path (), ctx); @@ -204,6 +212,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) rust_assert (adt->number_of_variants () > 0); TyTy::VariantDef *variant = nullptr; + tree variant_accesser_expr = nullptr; if (adt->is_enum ()) { // lookup the variant @@ -218,9 +227,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) // find expected discriminant // // need to access qualifier the field, if we use QUAL_UNION_TYPE this - // // would be DECL_QUALIFIER i think. For now this will just access the - // // first record field and its respective qualifier because it will - // // always be set because this is all a big special union + // // would be DECL_QUALIFIER i think. HIR::Expr &discrim_expr = variant->get_discriminant (); tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx); @@ -229,6 +236,14 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) = Backend::struct_field_expression (match_scrutinee_expr, 0, pattern.get_path ().get_locus ()); + // access variant data + tree scrutinee_union_expr + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern.get_path ().get_locus ()); + variant_accesser_expr + = Backend::struct_field_expression (scrutinee_union_expr, variant_index, + pattern.get_path ().get_locus ()); + check_expr = Backend::comparison_expression (ComparisonOperator::EQUAL, scrutinee_expr_qualifier_expr, @@ -240,6 +255,7 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) else { variant = adt->get_variants ().at (0); + variant_accesser_expr = match_scrutinee_expr; check_expr = boolean_true_node; } @@ -248,13 +264,15 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { + case HIR::StructPatternField::ItemType::TUPLE_PAT: + { // TODO rust_unreachable (); } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { + case HIR::StructPatternField::ItemType::IDENT_PAT: + { HIR::StructPatternFieldIdentPat &ident = static_cast<HIR::StructPatternFieldIdentPat &> (*field.get ()); @@ -263,11 +281,8 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) nullptr, &offs); rust_assert (ok); - // we may be offsetting by + 1 here since the first field in the - // record is always the discriminator - offs += adt->is_enum (); tree field_expr - = Backend::struct_field_expression (match_scrutinee_expr, offs, + = Backend::struct_field_expression (variant_accesser_expr, offs, ident.get_locus ()); tree check_expr_sub @@ -279,7 +294,8 @@ CompilePatternCheckExpr::visit (HIR::StructPattern &pattern) } break; - case HIR::StructPatternField::ItemType::IDENT: { + case HIR::StructPatternField::ItemType::IDENT: + { // ident pattern always matches - do nothing } break; @@ -338,44 +354,70 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) HIR::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { // TODO rust_unreachable (); } break; - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { HIR::TupleStructItemsNoRange &items_no_range = static_cast<HIR::TupleStructItemsNoRange &> (items); rust_assert (items_no_range.get_patterns ().size () == variant->num_fields ()); - size_t tuple_field_index = 0; - for (auto &pattern : items_no_range.get_patterns ()) + if (adt->is_enum ()) { - // find payload union field of scrutinee - tree payload_ref - = Backend::struct_field_expression (match_scrutinee_expr, 1, - pattern->get_locus ()); + size_t tuple_field_index = 0; + for (auto &pattern : items_no_range.get_patterns ()) + { + // find payload union field of scrutinee + tree payload_ref + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern->get_locus ()); - tree variant_ref - = Backend::struct_field_expression (payload_ref, variant_index, - pattern->get_locus ()); + tree variant_ref + = Backend::struct_field_expression (payload_ref, + variant_index, + pattern->get_locus ()); - tree field_expr - = Backend::struct_field_expression (variant_ref, - tuple_field_index++, - pattern->get_locus ()); + tree field_expr + = Backend::struct_field_expression (variant_ref, + tuple_field_index++, + pattern->get_locus ()); - tree check_expr_sub - = CompilePatternCheckExpr::Compile (*pattern, field_expr, ctx); - check_expr = Backend::arithmetic_or_logical_expression ( - ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, - check_expr_sub, pattern->get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern, field_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern->get_locus ()); + } } + else + { + // For non-enum TupleStructPatterns + size_t tuple_field_index = 0; + for (auto &pattern : items_no_range.get_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pattern->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern, field_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern->get_locus ()); + } + } + break; } - break; } } @@ -386,13 +428,57 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::RANGED: { - // TODO - gcc_unreachable (); + case HIR::TuplePatternItems::RANGED: + { + auto &items + = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); + size_t tuple_field_index = 0; + + // lookup the type to find out number of fields + TyTy::BaseType *ty = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + pattern.get_mappings ().get_hirid (), &ty); + rust_assert (ok); + rust_assert (ty->get_kind () == TyTy::TypeKind::TUPLE); + + // compile check expr for lower patterns + for (auto &pat : items.get_lower_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pat->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pat->get_locus ()); + } + + // skip the fields that are not checked + tuple_field_index = static_cast<TyTy::TupleType &> (*ty).num_fields () + - items.get_upper_patterns ().size (); + + // compile check expr for upper patterns + for (auto &pat : items.get_upper_patterns ()) + { + tree field_expr + = Backend::struct_field_expression (match_scrutinee_expr, + tuple_field_index++, + pat->get_locus ()); + + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pat, field_expr, ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pat->get_locus ()); + } } break; - case HIR::TuplePatternItems::MULTIPLE: { + case HIR::TuplePatternItems::MULTIPLE: + { auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( pattern.get_items ()); size_t tuple_field_index = 0; @@ -414,6 +500,99 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) } } +void +CompilePatternCheckExpr::visit (HIR::IdentifierPattern &pattern) +{ + if (pattern.has_subpattern ()) + { + check_expr = CompilePatternCheckExpr::Compile (pattern.get_subpattern (), + match_scrutinee_expr, ctx); + } + else + { + check_expr = boolean_true_node; + } +} + +void +CompilePatternCheckExpr::visit (HIR::SlicePattern &pattern) +{ + check_expr = boolean_true_node; + + // lookup the type + TyTy::BaseType *lookup = nullptr; + bool ok + = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (), + &lookup); + rust_assert (ok); + + // pattern must either be ArrayType or SliceType, should be already confirmed + // by type checking + rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY + || lookup->get_kind () == TyTy::TypeKind::SLICE + || lookup->get_kind () == TyTy::REF); + + size_t array_element_index = 0; + switch (lookup->get_kind ()) + { + case TyTy::TypeKind::ARRAY: + for (auto &pattern_member : pattern.get_items ()) + { + tree array_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::array_index_expression (match_scrutinee_expr, + array_index_tree, + pattern.get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern_member, element_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern.get_locus ()); + } + break; + case TyTy::TypeKind::SLICE: + rust_sorry_at ( + pattern.get_locus (), + "SlicePattern matching against non-ref slices are not yet supported"); + break; + case TyTy::TypeKind::REF: + { + rust_assert (RS_DST_FLAG_P (TREE_TYPE (match_scrutinee_expr))); + tree size_field + = Backend::struct_field_expression (match_scrutinee_expr, 1, + pattern.get_locus ()); + + // First compare the size + check_expr = Backend::comparison_expression ( + ComparisonOperator::EQUAL, size_field, + build_int_cst (size_type_node, pattern.get_items ().size ()), + pattern.get_locus ()); + + // Then compare each element in the slice pattern + for (auto &pattern_member : pattern.get_items ()) + { + tree slice_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::slice_index_expression (match_scrutinee_expr, + slice_index_tree, + pattern.get_locus ()); + tree check_expr_sub + = CompilePatternCheckExpr::Compile (*pattern_member, element_expr, + ctx); + check_expr = Backend::arithmetic_or_logical_expression ( + ArithmeticOrLogicalOperator::BITWISE_AND, check_expr, + check_expr_sub, pattern.get_locus ()); + } + } + break; + default: + rust_unreachable (); + } +} + // setup the bindings void @@ -449,13 +628,15 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) HIR::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { // TODO rust_unreachable (); } break; - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { HIR::TupleStructItemsNoRange &items_no_range = static_cast<HIR::TupleStructItemsNoRange &> (items); @@ -504,6 +685,71 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern) } } +tree +CompilePatternBindings::make_struct_access (TyTy::ADTType *adt, + TyTy::VariantDef *variant, + const Identifier &ident, + int variant_index) +{ + size_t offs = 0; + auto ok = variant->lookup_field (ident.as_string (), nullptr, &offs); + rust_assert (ok); + + if (adt->is_enum ()) + { + tree payload_accessor_union + = Backend::struct_field_expression (match_scrutinee_expr, 1, + ident.get_locus ()); + + tree variant_accessor + = Backend::struct_field_expression (payload_accessor_union, + variant_index, ident.get_locus ()); + + return Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); + } + else + { + tree variant_accessor = match_scrutinee_expr; + + return Backend::struct_field_expression (variant_accessor, offs, + ident.get_locus ()); + } +} + +void +CompilePatternBindings::handle_struct_pattern_ident ( + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) +{ + HIR::StructPatternFieldIdent &ident + = static_cast<HIR::StructPatternFieldIdent &> (pat); + + auto identifier = ident.get_identifier (); + tree binding = make_struct_access (adt, variant, identifier, variant_index); + + ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), binding); +} + +void +CompilePatternBindings::handle_struct_pattern_ident_pat ( + HIR::StructPatternField &pat, TyTy::ADTType *adt, TyTy::VariantDef *variant, + int variant_index) +{ + auto &pattern = static_cast<HIR::StructPatternFieldIdentPat &> (pat); + + tree binding = make_struct_access (adt, variant, pattern.get_identifier (), + variant_index); + CompilePatternBindings::Compile (pattern.get_pattern (), binding, ctx); +} + +void +CompilePatternBindings::handle_struct_pattern_tuple_pat ( + HIR::StructPatternField &pat) +{ + rust_unreachable (); +} + void CompilePatternBindings::visit (HIR::StructPattern &pattern) { @@ -539,54 +785,14 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { - // TODO - rust_unreachable (); - } + case HIR::StructPatternField::ItemType::TUPLE_PAT: + handle_struct_pattern_tuple_pat (*field); break; - - case HIR::StructPatternField::ItemType::IDENT_PAT: { - // TODO - rust_unreachable (); - } + case HIR::StructPatternField::ItemType::IDENT_PAT: + handle_struct_pattern_ident_pat (*field, adt, variant, variant_index); break; - - case HIR::StructPatternField::ItemType::IDENT: { - HIR::StructPatternFieldIdent &ident - = static_cast<HIR::StructPatternFieldIdent &> (*field.get ()); - - size_t offs = 0; - ok = variant->lookup_field (ident.get_identifier ().as_string (), - nullptr, &offs); - rust_assert (ok); - - tree binding = error_mark_node; - if (adt->is_enum ()) - { - tree payload_accessor_union - = Backend::struct_field_expression (match_scrutinee_expr, 1, - ident.get_locus ()); - - tree variant_accessor - = Backend::struct_field_expression (payload_accessor_union, - variant_index, - ident.get_locus ()); - - binding - = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); - } - else - { - tree variant_accessor = match_scrutinee_expr; - binding - = Backend::struct_field_expression (variant_accessor, offs, - ident.get_locus ()); - } - - ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (), - binding); - } + case HIR::StructPatternField::ItemType::IDENT: + handle_struct_pattern_ident (*field, adt, variant, variant_index); break; } } @@ -605,6 +811,12 @@ CompilePatternBindings::visit (HIR::ReferencePattern &pattern) void CompilePatternBindings::visit (HIR::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + CompilePatternBindings::Compile (pattern.get_subpattern (), + match_scrutinee_expr, ctx); + } + if (!pattern.get_is_ref ()) { ctx->insert_pattern_binding (pattern.get_mappings ().get_hirid (), @@ -631,7 +843,8 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::RANGED: { + case HIR::TuplePatternItems::ItemType::RANGED: + { size_t tuple_idx = 0; auto &items = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); @@ -674,7 +887,8 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) return; } - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { size_t tuple_idx = 0; auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( pattern.get_items ()); @@ -695,12 +909,67 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) return; } - default: { + default: + { rust_unreachable (); } } } +void +CompilePatternBindings::visit (HIR::SlicePattern &pattern) +{ + // lookup the type + TyTy::BaseType *lookup = nullptr; + bool ok + = ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (), + &lookup); + rust_assert (ok); + + rust_assert (lookup->get_kind () == TyTy::TypeKind::ARRAY + || lookup->get_kind () == TyTy::TypeKind::SLICE + || lookup->get_kind () == TyTy::REF); + + size_t array_element_index = 0; + switch (lookup->get_kind ()) + { + case TyTy::TypeKind::ARRAY: + for (auto &pattern_member : pattern.get_items ()) + { + tree array_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::array_index_expression (match_scrutinee_expr, + array_index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, element_expr, ctx); + } + break; + case TyTy::TypeKind::SLICE: + rust_sorry_at ( + pattern.get_locus (), + "SlicePattern matching against non-ref slices are not yet supported"); + break; + case TyTy::TypeKind::REF: + { + for (auto &pattern_member : pattern.get_items ()) + { + tree slice_index_tree + = Backend::size_constant_expression (array_element_index++); + tree element_expr + = Backend::slice_index_expression (match_scrutinee_expr, + slice_index_tree, + pattern.get_locus ()); + CompilePatternBindings::Compile (*pattern_member, element_expr, + ctx); + } + break; + } + default: + rust_unreachable (); + } +} + // void @@ -755,7 +1024,8 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::RANGED: { + case HIR::TuplePatternItems::ItemType::RANGED: + { size_t tuple_idx = 0; auto &items = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); @@ -799,7 +1069,8 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) return; } - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { size_t tuple_idx = 0; auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( pattern.get_items ()); @@ -821,7 +1092,8 @@ CompilePatternLet::visit (HIR::TuplePattern &pattern) return; } - default: { + default: + { rust_unreachable (); } } diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index c7a62fc..233799e 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -17,7 +17,9 @@ // <http://www.gnu.org/licenses/>. #include "rust-compile-base.h" +#include "rust-hir-pattern.h" #include "rust-hir-visitor.h" +#include "rust-tyty.h" namespace Rust { namespace Compile { @@ -43,12 +45,10 @@ public: void visit (HIR::StructPattern &) override; void visit (HIR::TupleStructPattern &) override; void visit (HIR::TuplePattern &) override; + void visit (HIR::IdentifierPattern &) override; + void visit (HIR::SlicePattern &) override; // Always succeeds - void visit (HIR::IdentifierPattern &) override - { - check_expr = boolean_true_node; - } void visit (HIR::WildcardPattern &) override { check_expr = boolean_true_node; @@ -56,7 +56,6 @@ public: // Empty visit for unused Pattern HIR nodes. void visit (HIR::QualifiedPathInExpression &) override {} - void visit (HIR::SlicePattern &) override {} CompilePatternCheckExpr (Context *ctx, tree match_scrutinee_expr) : HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr), @@ -78,11 +77,25 @@ public: pattern.accept_vis (compiler); } + tree make_struct_access (TyTy::ADTType *adt, TyTy::VariantDef *variant, + const Identifier &ident, int variant_index); + + void handle_struct_pattern_ident (HIR::StructPatternField &pat, + TyTy::ADTType *adt, + TyTy::VariantDef *variant, + int variant_index); + void handle_struct_pattern_ident_pat (HIR::StructPatternField &pat, + TyTy::ADTType *adt, + TyTy::VariantDef *variant, + int variant_index); + void handle_struct_pattern_tuple_pat (HIR::StructPatternField &pat); + void visit (HIR::StructPattern &pattern) override; void visit (HIR::TupleStructPattern &pattern) override; void visit (HIR::ReferencePattern &pattern) override; void visit (HIR::IdentifierPattern &) override; void visit (HIR::TuplePattern &pattern) override; + void visit (HIR::SlicePattern &) override; // Empty visit for unused Pattern HIR nodes. void visit (HIR::AltPattern &) override {} @@ -90,7 +103,6 @@ public: void visit (HIR::PathInExpression &) override {} void visit (HIR::QualifiedPathInExpression &) override {} void visit (HIR::RangePattern &) override {} - void visit (HIR::SlicePattern &) override {} void visit (HIR::WildcardPattern &) override {} protected: diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 81d2dbb..f3b9dc2 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -187,13 +187,18 @@ ResolvePathRef::resolve_with_node_id ( } // Handle unit struct + tree resolved_item = error_mark_node; if (lookup->get_kind () == TyTy::TypeKind::ADT) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); + resolved_item + = attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); + + if (!error_operand_p (resolved_item)) + return resolved_item; // let the query system figure it out - tree resolved_item = query_compile (ref, lookup, final_segment, mappings, - expr_locus, is_qualified_path); + resolved_item = query_compile (ref, lookup, final_segment, mappings, + expr_locus, is_qualified_path); if (resolved_item != error_mark_node) { TREE_USED (resolved_item) = 1; @@ -209,36 +214,24 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, { TyTy::BaseType *lookup = nullptr; bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup); - rust_assert (ok); + if (!ok) + return error_mark_node; // need to look up the reference for this identifier // this can fail because it might be a Constructor for something // in that case the caller should attempt ResolvePathType::Compile - NodeId ref_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - auto resolved = nr_ctx.lookup (mappings.get_nodeid ()); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (!resolved) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); + auto resolved = nr_ctx.lookup (mappings.get_nodeid ()); - ref_node_id = *resolved; - } - else - { - if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (), - &ref_node_id)) - return attempt_constructor_expression_lookup (lookup, ctx, mappings, - expr_locus); - } + if (!resolved) + return attempt_constructor_expression_lookup (lookup, ctx, mappings, + expr_locus); return resolve_with_node_id (final_segment, mappings, expr_locus, - is_qualified_path, ref_node_id); + is_qualified_path, *resolved); } tree @@ -336,11 +329,18 @@ HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup, rust_assert (lookup->is<TyTy::FnType> ()); auto fn = lookup->as<TyTy::FnType> (); rust_assert (fn->get_num_type_params () > 0); - auto &self = fn->get_substs ().at (0); - auto receiver = self.get_param_ty (); + TyTy::SubstitutionParamMapping &self = fn->get_substs ().at (0); + TyTy::BaseGeneric *receiver = self.get_param_ty (); + TyTy::BaseType *r = receiver; + if (!receiver->can_resolve ()) + { + bool ok + = ctx->get_tyctx ()->lookup_type (receiver->get_ref (), &r); + rust_assert (ok); + } + auto candidates - = Resolver::PathProbeImplTrait::Probe (receiver, final_segment, - trait_ref); + = Resolver::PathProbeImplTrait::Probe (r, final_segment, trait_ref); if (candidates.size () == 0) { // this means we are defaulting back to the trait_item if diff --git a/gcc/rust/backend/rust-compile-stmt.cc b/gcc/rust/backend/rust-compile-stmt.cc index a4b5a98..b520baf 100644 --- a/gcc/rust/backend/rust-compile-stmt.cc +++ b/gcc/rust/backend/rust-compile-stmt.cc @@ -58,6 +58,9 @@ CompileStmt::visit (HIR::LetStmt &stmt) return; } + rust_debug_loc (stmt.get_locus (), " -> LetStmt %s", + ty->as_string ().c_str ()); + // setup var decl nodes fncontext fnctx = ctx->peek_fn (); tree fndecl = fnctx.fndecl; diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 83e5756..0622954 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -17,11 +17,11 @@ // <http://www.gnu.org/licenses/>. #include "rust-compile-type.h" -#include "rust-compile-expr.h" #include "rust-constexpr.h" -#include "rust-gcc.h" +#include "rust-compile-base.h" #include "tree.h" +#include "fold-const.h" #include "stor-layout.h" namespace Rust { @@ -121,6 +121,13 @@ TyTyResolveCompile::visit (const TyTy::InferType &type) if (orig == lookup) { + TyTy::BaseType *def = nullptr; + if (type.default_type (&def)) + { + translated = TyTyResolveCompile::compile (ctx, def); + return; + } + translated = error_mark_node; return; } @@ -135,6 +142,12 @@ TyTyResolveCompile::visit (const TyTy::ParamType &) } void +TyTyResolveCompile::visit (const TyTy::ConstType &) +{ + translated = error_mark_node; +} + +void TyTyResolveCompile::visit (const TyTy::ProjectionType &type) { translated = error_mark_node; @@ -189,7 +202,7 @@ TyTyResolveCompile::visit (const TyTy::ClosureType &type) void TyTyResolveCompile::visit (const TyTy::FnType &type) { - Backend::typed_identifier receiver; + Backend::typed_identifier receiver ("", NULL_TREE, UNKNOWN_LOCATION); std::vector<Backend::typed_identifier> parameters; std::vector<Backend::typed_identifier> results; @@ -454,7 +467,7 @@ TyTyResolveCompile::visit (const TyTy::TupleType &type) } tree struct_type_record = Backend::struct_type (fields); - translated = Backend::named_type (type.as_string (), struct_type_record, + translated = Backend::named_type (type.get_name (), struct_type_record, type.get_ident ().locus); } @@ -463,26 +476,15 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) { tree element_type = TyTyResolveCompile::compile (ctx, type.get_element_type ()); + TyTy::ConstType *const_capacity = type.get_capacity (); + tree folded_capacity_expr = const_capacity->get_value (); - ctx->push_const_context (); - - HIR::Expr &hir_capacity_expr = type.get_capacity_expr (); - TyTy::BaseType *capacity_expr_ty = nullptr; - bool ok = ctx->get_tyctx ()->lookup_type ( - hir_capacity_expr.get_mappings ().get_hirid (), &capacity_expr_ty); - rust_assert (ok); - tree capacity_expr = HIRCompileBase::compile_constant_expr ( - ctx, hir_capacity_expr.get_mappings ().get_hirid (), capacity_expr_ty, - capacity_expr_ty, Resolver::CanonicalPath::create_empty (), - hir_capacity_expr, type.get_locus (), hir_capacity_expr.get_locus ()); - - ctx->pop_const_context (); - - tree folded_capacity_expr = fold_expr (capacity_expr); + // build_index_type takes the maximum index, which is one less than + // the length. + tree index_type_tree = build_index_type ( + fold_build2 (MINUS_EXPR, sizetype, folded_capacity_expr, size_one_node)); - translated = Backend::array_type (element_type, folded_capacity_expr); - if (translated != error_mark_node) - translated = ctx->insert_compiled_type (translated); + translated = build_array_type (element_type, index_type_tree, false); } void @@ -755,7 +757,9 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type) void TyTyResolveCompile::visit (const TyTy::OpaqueType &type) { - translated = error_mark_node; + rust_assert (type.can_resolve ()); + auto underlying = type.resolve (); + translated = TyTyResolveCompile::compile (ctx, underlying, trait_object_mode); } tree diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h index 7ebc4a6..0675343 100644 --- a/gcc/rust/backend/rust-compile-type.h +++ b/gcc/rust/backend/rust-compile-type.h @@ -50,6 +50,7 @@ public: void visit (const TyTy::ReferenceType &) override; void visit (const TyTy::PointerType &) override; void visit (const TyTy::ParamType &) override; + void visit (const TyTy::ConstType &) override; void visit (const TyTy::StrType &) override; void visit (const TyTy::NeverType &) override; void visit (const TyTy::PlaceholderType &) override; diff --git a/gcc/rust/backend/rust-compile-var-decl.h b/gcc/rust/backend/rust-compile-var-decl.h index 4c46a7b..5c6d145 100644 --- a/gcc/rust/backend/rust-compile-var-decl.h +++ b/gcc/rust/backend/rust-compile-var-decl.h @@ -70,7 +70,8 @@ public: { switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { rust_assert (TREE_CODE (translated_type) == RECORD_TYPE); auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( pattern.get_items ()); diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc index dc2d6b1..d524d09 100644 --- a/gcc/rust/backend/rust-constexpr.cc +++ b/gcc/rust/backend/rust-constexpr.cc @@ -68,32 +68,24 @@ literal_type_p (tree t) return false; } -static bool -verify_constant (tree, bool, bool *, bool *); - -static HOST_WIDE_INT -find_array_ctor_elt (tree ary, tree dindex, bool insert = false); -static int -array_index_cmp (tree key, tree index); -static bool -potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, - tsubst_flags_t flags, tree *jump_target); -bool -potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, - tsubst_flags_t flags); -tree -unshare_constructor (tree t MEM_STAT_DECL); -void -maybe_save_constexpr_fundef (tree fun); - -static bool -returns (tree *jump_target); -static bool -breaks (tree *jump_target); -static bool -continues (tree *jump_target); -static bool -switches (tree *jump_target); +static bool verify_constant (tree, bool, bool *, bool *); + +static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex, + bool insert = false); +static int array_index_cmp (tree key, tree index); +static bool potential_constant_expression_1 (tree t, bool want_rval, + bool strict, bool now, + tsubst_flags_t flags, + tree *jump_target); +bool potential_constant_expression_1 (tree t, bool want_rval, bool strict, + bool now, tsubst_flags_t flags); +tree unshare_constructor (tree t MEM_STAT_DECL); +void maybe_save_constexpr_fundef (tree fun); + +static bool returns (tree *jump_target); +static bool breaks (tree *jump_target); +static bool continues (tree *jump_target); +static bool switches (tree *jump_target); struct constexpr_global_ctx { @@ -463,60 +455,52 @@ save_fundef_copy (tree fun, tree copy) *slot = copy; } -static tree -constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p, - bool unshare_p); -tree -decl_constant_value (tree decl, bool unshare_p); +static tree constant_value_1 (tree decl, bool strict_p, + bool return_aggregate_cst_ok_p, bool unshare_p); +tree decl_constant_value (tree decl, bool unshare_p); -static void -non_const_var_error (location_t loc, tree r); +static void non_const_var_error (location_t loc, tree r); -static tree -eval_constant_expression (const constexpr_ctx *ctx, tree, bool, bool *, bool *, - tree * = NULL); +static tree eval_constant_expression (const constexpr_ctx *ctx, tree, bool, + bool *, bool *, tree * = NULL); -static tree -constexpr_fn_retval (const constexpr_ctx *ctx, tree r); +static tree constexpr_fn_retval (const constexpr_ctx *ctx, tree r); -static tree -eval_store_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *); +static tree eval_store_expression (const constexpr_ctx *ctx, tree r, bool, + bool *, bool *); -static tree -eval_call_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *); +static tree eval_call_expression (const constexpr_ctx *ctx, tree r, bool, + bool *, bool *); -static tree -eval_binary_expression (const constexpr_ctx *ctx, tree r, bool, bool *, bool *); +static tree eval_binary_expression (const constexpr_ctx *ctx, tree r, bool, + bool *, bool *); -static tree -get_function_named_in_call (tree t); +static tree get_function_named_in_call (tree t); -static tree -eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p, tree *jump_target); -static tree -extract_string_elt (tree string, unsigned chars_per_elt, unsigned index); +static tree eval_statement_list (const constexpr_ctx *ctx, tree t, + bool *non_constant_p, bool *overflow_p, + tree *jump_target); +static tree extract_string_elt (tree string, unsigned chars_per_elt, + unsigned index); -static tree -eval_conditional_expression (const constexpr_ctx *ctx, tree t, bool lval, - bool *non_constant_p, bool *overflow_p, - tree *jump_target); +static tree eval_conditional_expression (const constexpr_ctx *ctx, tree t, + bool lval, bool *non_constant_p, + bool *overflow_p, tree *jump_target); -static tree -eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval, - bool *non_constant_p, bool *overflow_p); +static tree eval_bit_field_ref (const constexpr_ctx *ctx, tree t, bool lval, + bool *non_constant_p, bool *overflow_p); -static tree -eval_loop_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p, tree *jump_target); +static tree eval_loop_expr (const constexpr_ctx *ctx, tree t, + bool *non_constant_p, bool *overflow_p, + tree *jump_target); -static tree -eval_switch_expr (const constexpr_ctx *ctx, tree t, bool *non_constant_p, - bool *overflow_p, tree *jump_target); +static tree eval_switch_expr (const constexpr_ctx *ctx, tree t, + bool *non_constant_p, bool *overflow_p, + tree *jump_target); -static tree -eval_unary_expression (const constexpr_ctx *ctx, tree t, bool /*lval*/, - bool *non_constant_p, bool *overflow_p); +static tree eval_unary_expression (const constexpr_ctx *ctx, tree t, + bool /*lval*/, bool *non_constant_p, + bool *overflow_p); /* Variables and functions to manage constexpr call expansion context. These do not need to be marked for PCH or GC. */ @@ -1235,7 +1219,8 @@ get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1) /* We fell off the end of the CONSTRUCTOR, so insert a new entry at the end. */ - insert : { + insert: + { constructor_elt ce = {index, NULL_TREE}; vec_safe_insert (CONSTRUCTOR_ELTS (ctor), idx, ce); @@ -1568,10 +1553,9 @@ free_constructor (tree t) } } -static tree -eval_and_check_array_index (const constexpr_ctx *ctx, tree t, - bool allow_one_past, bool *non_constant_p, - bool *overflow_p); +static tree eval_and_check_array_index (const constexpr_ctx *ctx, tree t, + bool allow_one_past, + bool *non_constant_p, bool *overflow_p); // forked from gcc/cp/constexpr.cc cxx_eval_array_reference @@ -1901,6 +1885,9 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, location_t loc = EXPR_LOCATION (t); + if (t == NULL_TREE) + return NULL_TREE; + if (CONSTANT_CLASS_P (t)) { if (TREE_OVERFLOW (t)) @@ -1936,8 +1923,9 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, return eval_constant_expression (ctx, r, lval, non_constant_p, overflow_p); } - /* fall through */ - case CONST_DECL: { + /* fall through */ + case CONST_DECL: + { /* We used to not check lval for CONST_DECL, but darwin.cc uses CONST_DECL for aggregate constants. */ if (lval) @@ -2045,7 +2033,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, overflow_p); break; - case TARGET_EXPR: { + case TARGET_EXPR: + { tree type = TREE_TYPE (t); if (!literal_type_p (type)) @@ -2129,7 +2118,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, } break; - case DECL_EXPR: { + case DECL_EXPR: + { r = DECL_EXPR_DECL (t); if (AGGREGATE_TYPE_P (TREE_TYPE (r)) || VECTOR_TYPE_P (TREE_TYPE (r))) @@ -2201,7 +2191,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, return eval_constant_expression (ctx, OBJ_TYPE_REF_EXPR (t), lval, non_constant_p, overflow_p); - case EXIT_EXPR: { + case EXIT_EXPR: + { tree cond = TREE_OPERAND (t, 0); cond = eval_constant_expression (ctx, cond, /*lval*/ false, non_constant_p, overflow_p); @@ -2243,7 +2234,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, } break; - case ADDR_EXPR: { + case ADDR_EXPR: + { tree oldop = TREE_OPERAND (t, 0); tree op = eval_constant_expression (ctx, oldop, /*lval*/ true, non_constant_p, @@ -2261,7 +2253,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, break; } - case COMPOUND_EXPR: { + case COMPOUND_EXPR: + { /* check_return_expr sometimes wraps a TARGET_EXPR in a COMPOUND_EXPR; don't get confused. Also handle EMPTY_CLASS_EXPR introduced by build_call_a. */ @@ -2401,7 +2394,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, non_constant_p, overflow_p, jump_target); break; - case CLEANUP_POINT_EXPR: { + case CLEANUP_POINT_EXPR: + { auto_vec<tree, 2> cleanups; vec<tree> *prev_cleanups = ctx->global->cleanups; ctx->global->cleanups = &cleanups; @@ -2441,7 +2435,8 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, /* FALLTHROUGH. */ case NOP_EXPR: case CONVERT_EXPR: - case VIEW_CONVERT_EXPR: { + case VIEW_CONVERT_EXPR: + { tree oldop = TREE_OPERAND (t, 0); tree op = eval_constant_expression (ctx, oldop, lval, non_constant_p, @@ -2688,7 +2683,8 @@ eval_store_expression (const constexpr_ctx *ctx, tree t, bool lval, { case BIT_FIELD_REF: case COMPONENT_REF: - case ARRAY_REF: { + case ARRAY_REF: + { tree ob = TREE_OPERAND (probe, 0); tree elt = TREE_OPERAND (probe, 1); if (TREE_CODE (elt) == FIELD_DECL /*&& DECL_MUTABLE_P (elt)*/) @@ -3940,7 +3936,8 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body) { switch (TREE_CODE (body)) { - case STATEMENT_LIST: { + case STATEMENT_LIST: + { tree expr = NULL_TREE; for (tree stmt : tsi_range (body)) { @@ -3958,13 +3955,15 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body) return expr; } - case RETURN_EXPR: { + case RETURN_EXPR: + { bool non_constant_p = false; bool overflow_p = false; return eval_constant_expression (ctx, body, false, &non_constant_p, &overflow_p); } - case DECL_EXPR: { + case DECL_EXPR: + { tree decl = DECL_EXPR_DECL (body); if (TREE_CODE (decl) == USING_DECL /* Accept __func__, __FUNCTION__, and __PRETTY_FUNCTION__. */ @@ -3976,7 +3975,8 @@ constexpr_fn_retval (const constexpr_ctx *ctx, tree body) case CLEANUP_POINT_EXPR: return constexpr_fn_retval (ctx, TREE_OPERAND (body, 0)); - case BIND_EXPR: { + case BIND_EXPR: + { tree b = BIND_EXPR_BODY (body); return constexpr_fn_retval (ctx, b); } @@ -4136,7 +4136,8 @@ array_index_cmp (tree key, tree index) { case INTEGER_CST: return tree_int_cst_compare (key, index); - case RANGE_EXPR: { + case RANGE_EXPR: + { tree lo = TREE_OPERAND (index, 0); tree hi = TREE_OPERAND (index, 1); if (tree_int_cst_lt (key, lo)) @@ -5943,7 +5944,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case BIT_FIELD_REF: return RECUR (TREE_OPERAND (t, 0), want_rval); - case INDIRECT_REF: { + case INDIRECT_REF: + { tree x = TREE_OPERAND (t, 0); STRIP_NOPS (x); return RECUR (x, rval); @@ -6214,7 +6216,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case INIT_EXPR: return RECUR (TREE_OPERAND (t, 1), rval); - case CONSTRUCTOR: { + case CONSTRUCTOR: + { vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); constructor_elt *ce; for (i = 0; vec_safe_iterate (v, i, &ce); ++i) @@ -6223,7 +6226,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return true; } - case TREE_LIST: { + case TREE_LIST: + { gcc_assert (TREE_PURPOSE (t) == NULL_TREE || DECL_P (TREE_PURPOSE (t))); if (!RECUR (TREE_VALUE (t), want_rval)) return false; @@ -6238,7 +6242,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case ROUND_DIV_EXPR: case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: - case ROUND_MOD_EXPR: { + case ROUND_MOD_EXPR: + { tree denom = TREE_OPERAND (t, 1); if (!RECUR (denom, rval)) return false; @@ -6258,7 +6263,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } } - case COMPOUND_EXPR: { + case COMPOUND_EXPR: + { /* check_return_expr sometimes wraps a TARGET_EXPR in a COMPOUND_EXPR; don't get confused. */ tree op0 = TREE_OPERAND (t, 0); @@ -6280,7 +6286,8 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR: tmp = boolean_false_node; - truth : { + truth: + { tree op0 = TREE_OPERAND (t, 0); tree op1 = TREE_OPERAND (t, 1); if (!RECUR (op0, rval)) diff --git a/gcc/rust/backend/rust-constexpr.h b/gcc/rust/backend/rust-constexpr.h index 77a0797..27f0a2e 100644 --- a/gcc/rust/backend/rust-constexpr.h +++ b/gcc/rust/backend/rust-constexpr.h @@ -24,8 +24,7 @@ namespace Rust { namespace Compile { extern tree fold_expr (tree); -extern void -maybe_save_constexpr_fundef (tree fun); +extern void maybe_save_constexpr_fundef (tree fun); } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-mangle-v0.cc b/gcc/rust/backend/rust-mangle-v0.cc index d0df4ab..f6b1a4c 100644 --- a/gcc/rust/backend/rust-mangle-v0.cc +++ b/gcc/rust/backend/rust-mangle-v0.cc @@ -62,9 +62,9 @@ struct V0Path } }; -static std::string -v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, - const Resolver::CanonicalPath &path); +static std::string v0_path (Rust::Compile::Context *ctx, + const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path); static std::string v0_tuple_prefix (const TyTy::BaseType *ty) @@ -148,7 +148,8 @@ v0_complex_type_prefix (Context *ctx, const TyTy::BaseType *ty) // TODO: generics switch (ty->get_kind ()) { - case TyTy::TypeKind::ADT: { + case TyTy::TypeKind::ADT: + { const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (ty); return v0_path (ctx, ty, adt->get_ident ().path); } @@ -387,7 +388,8 @@ v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, { switch (impl_item->first->get_impl_item_type ()) { - case HIR::ImplItem::FUNCTION: { + case HIR::ImplItem::FUNCTION: + { HIR::Function *fn = static_cast<HIR::Function *> (impl_item->first); v0path @@ -408,7 +410,8 @@ v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, { switch (trait_item.value ()->get_item_kind ()) { - case HIR::TraitItem::FUNC: { + case HIR::TraitItem::FUNC: + { auto fn = static_cast<HIR::TraitItemFunc *> (*trait_item); rust_unreachable (); v0path = v0_function_path (v0path, ctx, ty, @@ -428,7 +431,8 @@ v0_path (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, else if (auto item = mappings.lookup_hir_item (hir_id)) switch (item.value ()->get_item_kind ()) { - case HIR::Item::ItemKind::Function: { + case HIR::Item::ItemKind::Function: + { HIR::Function *fn = static_cast<HIR::Function *> (*item); v0path = v0_function_path (v0path, ctx, ty, fn->get_generic_params (), diff --git a/gcc/rust/backend/rust-mangle.h b/gcc/rust/backend/rust-mangle.h index 2a84b6b..418f2bd 100644 --- a/gcc/rust/backend/rust-mangle.h +++ b/gcc/rust/backend/rust-mangle.h @@ -49,13 +49,12 @@ private: static enum MangleVersion version; }; -std::string -legacy_mangle_item (const TyTy::BaseType *ty, - const Resolver::CanonicalPath &path); +std::string legacy_mangle_item (const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path); -std::string -v0_mangle_item (Rust::Compile::Context *ctx, const TyTy::BaseType *ty, - const Resolver::CanonicalPath &path); +std::string v0_mangle_item (Rust::Compile::Context *ctx, + const TyTy::BaseType *ty, + const Resolver::CanonicalPath &path); } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc index 2302ffb..b86c3c8 100644 --- a/gcc/rust/backend/rust-tree.cc +++ b/gcc/rust/backend/rust-tree.cc @@ -268,7 +268,8 @@ convert_to_void (tree expr, impl_conv_void implicit) return expr; switch (TREE_CODE (expr)) { - case COND_EXPR: { + case COND_EXPR: + { /* The two parts of a cond expr might be separate lvalues. */ tree op1 = TREE_OPERAND (expr, 1); tree op2 = TREE_OPERAND (expr, 2); @@ -294,7 +295,8 @@ convert_to_void (tree expr, impl_conv_void implicit) break; } - case COMPOUND_EXPR: { + case COMPOUND_EXPR: + { /* The second part of a compound expr contains the value. */ tree op1 = TREE_OPERAND (expr, 1); tree new_op1; @@ -323,7 +325,8 @@ convert_to_void (tree expr, impl_conv_void implicit) maybe_warn_nodiscard (expr, implicit); break; - case INDIRECT_REF: { + case INDIRECT_REF: + { tree type = TREE_TYPE (expr); int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0))); int is_volatile = TYPE_VOLATILE (type); @@ -518,7 +521,8 @@ convert_to_void (tree expr, impl_conv_void implicit) break; } - case VAR_DECL: { + case VAR_DECL: + { /* External variables might be incomplete. */ tree type = TREE_TYPE (expr); int is_complete = COMPLETE_TYPE_P (type); @@ -1485,7 +1489,8 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void *data) parameter pack. ??? Should some of these be in cp_walk_subtrees? */ switch (TREE_CODE (t)) { - case DECL_EXPR: { + case DECL_EXPR: + { tree decl = DECL_EXPR_DECL (t); if (is_typedef_decl (decl)) /* Since we stop at typedefs above, we need to look through them at @@ -1506,7 +1511,8 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; return NULL_TREE; - case DECLTYPE_TYPE: { + case DECLTYPE_TYPE: + { /* When traversing a DECLTYPE_TYPE_EXPR, we need to set type_pack_expansion_p to false so that any placeholders within the expression don't get marked as parameter packs. */ @@ -1970,7 +1976,8 @@ rs_tree_equal (tree t1, tree t2) case SAVE_EXPR: return rs_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); - case CALL_EXPR: { + case CALL_EXPR: + { if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2)) return false; @@ -1996,7 +2003,8 @@ rs_tree_equal (tree t1, tree t2) return true; } - case TARGET_EXPR: { + case TARGET_EXPR: + { tree o1 = TREE_OPERAND (t1, 0); tree o2 = TREE_OPERAND (t2, 0); @@ -2067,7 +2075,8 @@ rs_tree_equal (tree t1, tree t2) case tcc_expression: case tcc_vl_exp: case tcc_reference: - case tcc_statement: { + case tcc_statement: + { int n = rs_tree_operand_length (t1); if (TREE_CODE_CLASS (code1) == tcc_vl_exp && n != TREE_OPERAND_LENGTH (t2)) @@ -2095,7 +2104,11 @@ rs_tree_equal (tree t1, tree t2) /* TRUE iff TYPE is publicly & uniquely derived from PARENT. */ -bool publicly_uniquely_derived_p (tree, tree) { return false; } +bool +publicly_uniquely_derived_p (tree, tree) +{ + return false; +} // forked from gcc/cp/typeck.cc comp_except_types @@ -3375,7 +3388,11 @@ release_tree_vector (vec<tree, va_gc> *vec) /* As above, but also check value-dependence of the expression as a whole. */ -bool instantiation_dependent_expression_p (tree) { return false; } +bool +instantiation_dependent_expression_p (tree) +{ + return false; +} // forked from gcc/cp/cvt.cc cp_get_callee @@ -3425,7 +3442,11 @@ scalarish_type_p (const_tree t) constructors are deleted. This function implements the ABI notion of non-trivial copy, which has diverged from the one in the standard. */ -bool type_has_nontrivial_copy_init (const_tree) { return false; } +bool +type_has_nontrivial_copy_init (const_tree) +{ + return false; +} // forked from gcc/cp/tree.cc build_local_temp @@ -3448,7 +3469,11 @@ build_local_temp (tree type) /* Returns true iff DECL is a capture proxy for a normal capture (i.e. without explicit initializer). */ -bool is_normal_capture_proxy (tree) { return false; } +bool +is_normal_capture_proxy (tree) +{ + return false; +} // forked from gcc/cp/c-common.cc reject_gcc_builtin @@ -3522,7 +3547,8 @@ is_bitfield_expr_with_lowered_type (const_tree exp) case BIT_NOT_EXPR: return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0)); - case COMPONENT_REF: { + case COMPONENT_REF: + { tree field; field = TREE_OPERAND (exp, 1); @@ -3909,7 +3935,8 @@ retry: break; case OFFSET_TYPE: - bad_member : { + bad_member: + { tree member = TREE_OPERAND (value, 1); if (is_overloaded_fn (member)) member = get_first_fn (member); @@ -3994,13 +4021,21 @@ decl_constant_var_p (tree decl) /* Returns true iff DECL is a variable or function declared with an auto type that has not yet been deduced to a real type. */ -bool undeduced_auto_decl (tree) { return false; } +bool +undeduced_auto_decl (tree) +{ + return false; +} // forked from gcc/cp/decl.cc require_deduced_type /* Complain if DECL has an undeduced return type. */ -bool require_deduced_type (tree, tsubst_flags_t) { return true; } +bool +require_deduced_type (tree, tsubst_flags_t) +{ + return true; +} /* Return the location of a tree passed to %+ formats. */ @@ -4290,10 +4325,9 @@ struct GTY ((for_user)) source_location_table_entry } // namespace Rust -extern void -gt_pch_nx (Rust::source_location_table_entry &); -extern void -gt_pch_nx (Rust::source_location_table_entry *, gt_pointer_operator, void *); +extern void gt_pch_nx (Rust::source_location_table_entry &); +extern void gt_pch_nx (Rust::source_location_table_entry *, gt_pointer_operator, + void *); namespace Rust { @@ -4421,7 +4455,8 @@ lvalue_kind (const_tree ref) case VIEW_CONVERT_EXPR: return lvalue_kind (TREE_OPERAND (ref, 0)); - case ARRAY_REF: { + case ARRAY_REF: + { tree op1 = TREE_OPERAND (ref, 0); if (TREE_CODE (TREE_TYPE (op1)) == ARRAY_TYPE) { @@ -4518,7 +4553,8 @@ lvalue_kind (const_tree ref) op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1)); break; - case COND_EXPR: { + case COND_EXPR: + { tree op1 = TREE_OPERAND (ref, 1); if (!op1) op1 = TREE_OPERAND (ref, 0); diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h index 3630b0e..9e859d4 100644 --- a/gcc/rust/backend/rust-tree.h +++ b/gcc/rust/backend/rust-tree.h @@ -1543,7 +1543,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; #if defined ENABLE_TREE_CHECKING #define LANG_DECL_MIN_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (!LANG_DECL_HAS_MIN (NODE)) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1554,7 +1554,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; template, not just on a FUNCTION_DECL. So when looking for things in lang_decl_fn, look down through a TEMPLATE_DECL into its result. */ #define LANG_DECL_FN_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (!DECL_DECLARES_FUNCTION_P (NODE) || lt->u.base.selector != lds_fn) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1562,7 +1562,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; }) #define LANG_DECL_NS_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (TREE_CODE (NODE) != NAMESPACE_DECL || lt->u.base.selector != lds_ns) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1570,7 +1570,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; }) #define LANG_DECL_PARM_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (TREE_CODE (NODE) != PARM_DECL || lt->u.base.selector != lds_parm) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -1578,7 +1578,7 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; }) #define LANG_DECL_DECOMP_CHECK(NODE) \ - __extension__({ \ + __extension__ ({ \ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \ if (!VAR_P (NODE) || lt->u.base.selector != lds_decomp) \ lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \ @@ -2060,8 +2060,8 @@ struct GTY (()) rust_cxx_saved_binding // forked from gcc/cp/name-lookup.h resort_type_member_vec /* needed for GTY annotation */ -extern void -resort_type_member_vec (void *, void *, gt_pointer_operator, void *); +extern void resort_type_member_vec (void *, void *, gt_pointer_operator, + void *); // forked from gcc/cp/cp-tree.h saved_scope @@ -2895,8 +2895,7 @@ enum compare_bounds_t bounds_first }; -extern tree -convert_to_void (tree expr, impl_conv_void implicit); +extern tree convert_to_void (tree expr, impl_conv_void implicit); // The lvalue-to-rvalue conversion (7.1) is applied if and only if the // expression is a glvalue of volatile-qualified type and it is one of the @@ -2911,63 +2910,52 @@ convert_to_void (tree expr, impl_conv_void implicit); // operands are one of these expressions, or // * comma expression (8.19) where the right operand is one of these // expressions. -extern tree -mark_discarded_use (tree expr); +extern tree mark_discarded_use (tree expr); // Mark EXP as read, not just set, for set but not used -Wunused warning // purposes. -extern void -mark_exp_read (tree exp); +extern void mark_exp_read (tree exp); // We've seen an actual use of EXPR. Possibly replace an outer variable // reference inside with its constant value or a lambda capture. -extern tree -mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc, - bool reject_builtin); +extern tree mark_use (tree expr, bool rvalue_p, bool read_p, location_t loc, + bool reject_builtin); // Called whenever the expression EXPR is used in an rvalue context. // When REJECT_BUILTIN is true the expression is checked to make sure // it doesn't make it possible to obtain the address of a GCC built-in // function with no library fallback (or any of its bits, such as in // a conversion to bool). -extern tree -mark_rvalue_use (tree, location_t = UNKNOWN_LOCATION, - bool reject_builtin = true); +extern tree mark_rvalue_use (tree, location_t = UNKNOWN_LOCATION, + bool reject_builtin = true); // Called whenever an expression is used in an lvalue context. -extern tree -mark_lvalue_use (tree expr); +extern tree mark_lvalue_use (tree expr); // As above, but don't consider this use a read. -extern tree -mark_lvalue_use_nonread (tree expr); +extern tree mark_lvalue_use_nonread (tree expr); // We are using a reference VAL for its value. Bash that reference all the way // down to its lowest form. -extern tree -convert_from_reference (tree val); +extern tree convert_from_reference (tree val); // Subroutine of convert_to_void. Warn if we're discarding something with // attribute [[nodiscard]]. -extern void -maybe_warn_nodiscard (tree expr, impl_conv_void implicit); +extern void maybe_warn_nodiscard (tree expr, impl_conv_void implicit); -extern location_t -expr_loc_or_loc (const_tree t, location_t or_loc); +extern location_t expr_loc_or_loc (const_tree t, location_t or_loc); -extern location_t -expr_loc_or_input_loc (const_tree t); +extern location_t expr_loc_or_input_loc (const_tree t); // FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL // if we can. -extern tree -get_fndecl_from_callee (tree fn); +extern tree get_fndecl_from_callee (tree fn); // FIXME some helpers from HIRCompileBase could probably be moved here over time // Return an expression for the address of BASE[INDEX], used in offset intrinsic -extern tree -pointer_offset_expression (tree base_tree, tree index_tree, location_t locus); +extern tree pointer_offset_expression (tree base_tree, tree index_tree, + location_t locus); /* A tree node, together with a location, so that we can track locations (and ranges) during parsing. @@ -2978,11 +2966,9 @@ pointer_offset_expression (tree base_tree, tree index_tree, location_t locus); extern location_t rs_expr_location (const_tree); -extern int -is_empty_class (tree type); +extern int is_empty_class (tree type); -extern bool -is_really_empty_class (tree, bool); +extern bool is_really_empty_class (tree, bool); extern bool builtin_valid_in_constant_expr_p (const_tree); @@ -2990,15 +2976,13 @@ extern bool maybe_constexpr_fn (tree); extern bool var_in_maybe_constexpr_fn (tree); -extern int -rs_type_quals (const_tree type); +extern int rs_type_quals (const_tree type); inline bool type_unknown_p (const_tree); extern bool decl_maybe_constant_var_p (tree); -extern void -init_modules (); +extern void init_modules (); extern bool var_in_constexpr_fn (tree); @@ -3006,11 +2990,9 @@ inline tree ovl_first (tree) ATTRIBUTE_PURE; inline bool type_unknown_p (const_tree); -extern tree -lookup_add (tree fns, tree lookup); +extern tree lookup_add (tree fns, tree lookup); -extern tree -ovl_make (tree fn, tree next = NULL_TREE); +extern tree ovl_make (tree fn, tree next = NULL_TREE); extern int is_overloaded_fn (tree) ATTRIBUTE_PURE; @@ -3024,19 +3006,15 @@ extern tree make_conv_op_name (tree); extern int type_memfn_quals (const_tree); -struct c_fileinfo * -get_fileinfo (const char *); +struct c_fileinfo *get_fileinfo (const char *); -extern tree -cxx_make_type (enum tree_code CXX_MEM_STAT_INFO); +extern tree cxx_make_type (enum tree_code CXX_MEM_STAT_INFO); -extern tree -build_cplus_array_type (tree, tree, int is_dep = -1); +extern tree build_cplus_array_type (tree, tree, int is_dep = -1); extern bool is_byte_access_type (tree); -extern bool -comptypes (tree, tree, int); +extern bool comptypes (tree, tree, int); extern tree canonical_eh_spec (tree); @@ -3046,8 +3024,7 @@ extern bool rs_tree_equal (tree, tree); extern bool compparms (const_tree, const_tree); -extern tree -rs_build_qualified_type_real (tree, int, tsubst_flags_t); +extern tree rs_build_qualified_type_real (tree, int, tsubst_flags_t); #define rs_build_qualified_type(TYPE, QUALS) \ rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) extern bool cv_qualified_p (const_tree); @@ -3056,21 +3033,18 @@ extern bool similar_type_p (tree, tree); extern bool rs_tree_equal (tree, tree); -extern bool -vector_targets_convertible_p (const_tree t1, const_tree t2); +extern bool vector_targets_convertible_p (const_tree t1, const_tree t2); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); extern bool comp_ptr_ttypes_const (tree, tree, compare_bounds_t); -extern tree -get_class_binding_direct (tree, tree, bool want_type = false); +extern tree get_class_binding_direct (tree, tree, bool want_type = false); extern tree skip_artificial_parms_for (const_tree, tree); -extern void -lang_check_failed (const char *, int, - const char *) ATTRIBUTE_NORETURN ATTRIBUTE_COLD; +extern void lang_check_failed (const char *, int, + const char *) ATTRIBUTE_NORETURN ATTRIBUTE_COLD; extern tree default_init_uninitialized_part (tree); @@ -3088,8 +3062,7 @@ extern tree in_class_defaulted_default_constructor (tree); extern bool is_instantiation_of_constexpr (tree); -extern bool -check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); +extern bool check_for_uninitialized_const_var (tree, bool, tsubst_flags_t); extern bool reduced_constant_expression_p (tree); @@ -3108,19 +3081,17 @@ extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree convert_bitfield_to_declared_type (tree); -extern tree -cp_fold_maybe_rvalue (tree, bool); +extern tree cp_fold_maybe_rvalue (tree, bool); extern tree maybe_undo_parenthesized_ref (tree); -extern tree -fold_offsetof (tree, tree = size_type_node, tree_code ctx = ERROR_MARK); +extern tree fold_offsetof (tree, tree = size_type_node, + tree_code ctx = ERROR_MARK); extern tree cp_truthvalue_conversion (tree, tsubst_flags_t); -extern tree -fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, - bool = false, tree = NULL_TREE); +extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, + bool = false, tree = NULL_TREE); extern int char_type_p (tree); @@ -3163,13 +3134,11 @@ extern tree build_new_constexpr_heap_type (tree, tree, tree); extern bool is_empty_field (tree); -extern bool -in_immediate_context (); +extern bool in_immediate_context (); extern tree cp_get_callee_fndecl_nofold (tree); -extern bool -cxx_mark_addressable (tree, bool = false); +extern bool cxx_mark_addressable (tree, bool = false); extern tree fold_builtin_source_location (location_t); @@ -3183,25 +3152,22 @@ extern bool glvalue_p (const_tree); extern cp_lvalue_kind lvalue_kind (const_tree); -extern tree -decl_constant_value (tree, bool); +extern tree decl_constant_value (tree, bool); extern tree lookup_enumerator (tree, tree); -extern int -is_class_type (tree, int); +extern int is_class_type (tree, int); extern tree braced_lists_to_strings (tree, tree); -extern tree -fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); +extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, + int, tree *); extern bool layout_compatible_type_p (tree, tree); extern tree finish_underlying_type (tree); -extern tree -c_common_type_for_mode (machine_mode, int); +extern tree c_common_type_for_mode (machine_mode, int); extern bool std_layout_type_p (const_tree); @@ -3213,25 +3179,21 @@ extern void note_failed_type_completion_for_satisfaction (tree); extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t); -extern bool -next_common_initial_seqence (tree &, tree &); +extern bool next_common_initial_seqence (tree &, tree &); extern bool null_member_pointer_value_p (tree); -extern tree -fold_builtin_is_corresponding_member (location_t, int, tree *); +extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern tree cp_fold_rvalue (tree); -extern tree -maybe_constant_value (tree, tree = NULL_TREE, bool = false); +extern tree maybe_constant_value (tree, tree = NULL_TREE, bool = false); extern tree lvalue_type (tree); extern void lvalue_error (location_t, enum lvalue_use); -extern tree -cp_fold_maybe_rvalue (tree, bool); +extern tree cp_fold_maybe_rvalue (tree, bool); extern tree get_first_fn (tree) ATTRIBUTE_PURE; @@ -3253,13 +3215,12 @@ enum ce_exact }; -extern tree -rs_build_qualified_type_real (tree, int, tsubst_flags_t); +extern tree rs_build_qualified_type_real (tree, int, tsubst_flags_t); #define rs_build_qualified_type(TYPE, QUALS) \ rs_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) -extern tree -rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, hash_set<tree> *); +extern tree rs_walk_subtrees (tree *, int *, walk_tree_fn, void *, + hash_set<tree> *); #define rs_walk_tree(tp, func, data, pset) \ walk_tree_1 (tp, func, data, pset, rs_walk_subtrees) #define rs_walk_tree_without_duplicates(tp, func, data) \ @@ -3351,11 +3312,9 @@ gnu_vector_type_p (const_tree type) return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type); } -extern vec<tree, va_gc> * -make_tree_vector (void); +extern vec<tree, va_gc> *make_tree_vector (void); -extern void -release_tree_vector (vec<tree, va_gc> *); +extern void release_tree_vector (vec<tree, va_gc> *); /* Simplified unique_ptr clone to release a tree vec on exit. */ @@ -3373,7 +3332,7 @@ public: releasing_vec &operator= (const releasing_vec &); vec_t &operator* () const { return *v; } - vec_t *operator-> () const { return v; } + vec_t *operator->() const { return v; } vec_t *get () const { return v; } operator vec_t * () const { return v; } vec_t **operator& () { return &v; } @@ -3442,8 +3401,7 @@ cxx_incomplete_type_error (const_tree value, const_tree type) cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error); } -extern location_t -location_of (tree t); +extern location_t location_of (tree t); /* Helpers for IMPLICIT_RVALUE_P to look through automatic dereference. */ @@ -3465,23 +3423,18 @@ set_implicit_rvalue_p (tree ot) } namespace Compile { -extern tree -maybe_constant_init (tree, tree = NULL_TREE, bool = false); +extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false); -extern void -explain_invalid_constexpr_fn (tree fun); +extern void explain_invalid_constexpr_fn (tree fun); extern bool potential_constant_expression (tree); -extern bool -literal_type_p (tree t); +extern bool literal_type_p (tree t); -extern bool -maybe_constexpr_fn (tree t); +extern bool maybe_constexpr_fn (tree t); -extern tree -fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error, - bool = false, tree = NULL_TREE); +extern tree fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error, + bool = false, tree = NULL_TREE); } // namespace Compile } // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h index 0ce2142..0434bcf 100644 --- a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h +++ b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h @@ -239,31 +239,25 @@ struct Facts * * Output is not yet implemented and is only dumped to stdout. */ -extern "C" FFI::Output -polonius_run (FFI::FactsView input, bool dump_enabled); +extern "C" FFI::Output polonius_run (FFI::FactsView input, bool dump_enabled); // Helper functions for FFIVector to be used on Rust side extern "C" { -FFI::FFIVector<size_t> * -FFIVector__new (); +FFI::FFIVector<size_t> *FFIVector__new (); -FFI::FFIVectorPair * -FFIVector__new_vec_pair (); +FFI::FFIVectorPair *FFIVector__new_vec_pair (); -FFI::FFIVectorTriple * -FFIVector__new_vec_triple (); +FFI::FFIVectorTriple *FFIVector__new_vec_triple (); -void -FFIVector__push (FFI::FFIVector<size_t> *vector, size_t element); +void FFIVector__push (FFI::FFIVector<size_t> *vector, size_t element); void FFIVector__push_vec_pair (FFI::FFIVectorPair *vector, FFI::Pair<size_t, FFI::FFIVector<size_t> *> element); -void -FFIVector__push_vec_triple (FFI::FFIVectorTriple *vector, - FFI::Triple<size_t, size_t, size_t> element); +void FFIVector__push_vec_triple (FFI::FFIVectorTriple *vector, + FFI::Triple<size_t, size_t, size_t> element); } } // namespace Polonius diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc index 6b8b2e9..5b22c1a 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc @@ -240,7 +240,8 @@ ExprStmtBuilder::visit (HIR::ArrayExpr &expr) auto &elems = expr.get_internal_elements (); switch (elems.get_array_expr_type ()) { - case HIR::ArrayElems::VALUES: { + case HIR::ArrayElems::VALUES: + { auto &elem_vals = (static_cast<HIR::ArrayElemsValues &> (elems)); auto init_values = visit_list (elem_vals.get_values ()); // collect locations @@ -254,7 +255,8 @@ ExprStmtBuilder::visit (HIR::ArrayExpr &expr) lookup_type (expr), expr.get_locus ()); break; } - case HIR::ArrayElems::COPIED: { + case HIR::ArrayElems::COPIED: + { auto &elem_copied = (static_cast<HIR::ArrayElemsCopied &> (elems)); auto init = visit_expr (elem_copied.get_elem_to_copy ()); return_expr (new InitializerExpr ({init}), lookup_type (expr), @@ -329,6 +331,10 @@ ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr) {} void +ExprStmtBuilder::visit (HIR::OffsetOf &expr) +{} + +void ExprStmtBuilder::visit (HIR::MethodCallExpr &expr) {} @@ -415,6 +421,18 @@ ExprStmtBuilder::visit (HIR::BlockExpr &block) } void +ExprStmtBuilder::visit (HIR::AnonConst &block) +{ + rust_unreachable (); +} + +void +ExprStmtBuilder::visit (HIR::ConstBlock &block) +{ + rust_unreachable (); +} + +void ExprStmtBuilder::visit (HIR::ContinueExpr &cont) { LoopAndLabelCtx info = cont.has_label () ? get_label_ctx (cont.get_label ()) diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h index 5cab3c4..ba5db8b 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h @@ -19,6 +19,7 @@ #ifndef RUST_BIR_BUILDER_EXPR_H #define RUST_BIR_BUILDER_EXPR_H +#include "rust-hir-expr.h" #include "rust-hir-visitor.h" #include "rust-bir-builder-internal.h" @@ -84,6 +85,8 @@ protected: // Expr void visit (HIR::MethodCallExpr &expr) override; void visit (HIR::FieldAccessExpr &expr) override; void visit (HIR::BlockExpr &block) override; + void visit (HIR::AnonConst &block) override; + void visit (HIR::ConstBlock &block) override; void visit (HIR::ContinueExpr &cont) override; void visit (HIR::BreakExpr &brk) override; void visit (HIR::RangeFromToExpr &range) override; @@ -101,6 +104,7 @@ protected: // Expr void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::InlineAsm &expr) override; void visit (HIR::LlvmInlineAsm &expr) override; + void visit (HIR::OffsetOf &expr) override; void visit (HIR::MatchExpr &expr) override; void visit (HIR::AwaitExpr &expr) override; diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h index 4df0e14..e2cc2dd 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h @@ -27,6 +27,8 @@ #include "rust-name-resolver.h" #include "rust-bir.h" #include "rust-bir-free-region.h" +#include "rust-immutable-name-resolution-context.h" +#include "options.h" namespace Rust { @@ -402,19 +404,40 @@ protected: // HIR resolution helpers template <typename T> NodeId resolve_label (T &expr) { NodeId resolved_label; - bool ok - = ctx.resolver.lookup_resolved_label (expr.get_mappings ().get_nodeid (), - &resolved_label); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto res = nr_ctx.lookup (expr.get_mappings ().get_nodeid ()); + rust_assert (res.has_value ()); + resolved_label = res.value (); + } + else + { + bool ok = ctx.resolver.lookup_resolved_label ( + expr.get_mappings ().get_nodeid (), &resolved_label); + rust_assert (ok); + } return resolved_label; } template <typename T> PlaceId resolve_variable (T &variable) { NodeId variable_id; - bool ok = ctx.resolver.lookup_resolved_name ( - variable.get_mappings ().get_nodeid (), &variable_id); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto res = nr_ctx.lookup (variable.get_mappings ().get_nodeid ()); + rust_assert (res.has_value ()); + variable_id = res.value (); + } + else + { + bool ok = ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id); + rust_assert (ok); + } return ctx.place_db.lookup_variable (variable_id); } @@ -425,9 +448,20 @@ protected: // HIR resolution helpers // Unlike variables, // functions do not have to be declared in PlaceDB before use. NodeId variable_id; - bool ok = ctx.resolver.lookup_resolved_name ( - variable.get_mappings ().get_nodeid (), &variable_id); - rust_assert (ok); + if (flag_name_resolution_2_0) + { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto res = nr_ctx.lookup (variable.get_mappings ().get_nodeid ()); + rust_assert (res.has_value ()); + variable_id = res.value (); + } + else + { + bool ok = ctx.resolver.lookup_resolved_name ( + variable.get_mappings ().get_nodeid (), &variable_id); + rust_assert (ok); + } if (ty->is<TyTy::FnType> ()) return ctx.place_db.get_constant (ty); else diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index b7a1555..9108009 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -169,6 +169,14 @@ public: { return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); } + void visit (HIR::AnonConst &expr) override + { + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); + } + void visit (HIR::ConstBlock &expr) override + { + return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); + } void visit (HIR::UnsafeBlockExpr &expr) override { return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ()); @@ -208,6 +216,7 @@ public: void visit (HIR::InlineAsm &expr) override {} void visit (HIR::LlvmInlineAsm &expr) override {} + void visit (HIR::OffsetOf &expr) override {} protected: // Illegal at this position. void visit (HIR::StructExprFieldIdentifier &field) override diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc index ee37bb0..2d655f9 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc @@ -101,7 +101,8 @@ PatternBindingBuilder::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::TUPLE_PAT: { + case HIR::StructPatternField::TUPLE_PAT: + { auto tuple = static_cast<HIR::StructPatternFieldTuplePat *> (field.get ()); @@ -123,7 +124,8 @@ PatternBindingBuilder::visit (HIR::StructPattern &pattern) tuple->get_tuple_pattern ().accept_vis (*this); break; } - case HIR::StructPatternField::IDENT_PAT: { + case HIR::StructPatternField::IDENT_PAT: + { auto ident_field = static_cast<HIR::StructPatternFieldIdentPat *> (field.get ()); TyTy::StructFieldType *field_ty = nullptr; @@ -139,7 +141,8 @@ PatternBindingBuilder::visit (HIR::StructPattern &pattern) ident_field->get_pattern ().accept_vis (*this); break; } - case HIR::StructPatternField::IDENT: { + case HIR::StructPatternField::IDENT: + { auto ident_field = static_cast<HIR::StructPatternFieldIdent *> (field.get ()); TyTy::StructFieldType *field_ty = nullptr; @@ -199,13 +202,15 @@ PatternBindingBuilder::visit (HIR::TuplePattern &pattern) size_t index = 0; switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::MULTIPLE: { + case HIR::TuplePatternItems::MULTIPLE: + { auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( pattern.get_items ()); visit_tuple_fields (items.get_patterns (), saved, index); break; } - case HIR::TuplePatternItems::RANGED: { + case HIR::TuplePatternItems::RANGED: + { auto &items = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); @@ -244,7 +249,8 @@ PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern) size_t index = 0; switch (pattern.get_items ().get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { auto &items = static_cast<HIR::TupleStructItemsRange &> (pattern.get_items ()); @@ -261,7 +267,8 @@ PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern) visit_tuple_fields (items.get_upper_patterns (), saved, index); break; } - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { auto &items = static_cast<HIR::TupleStructItemsNoRange &> (pattern.get_items ()); visit_tuple_fields (items.get_patterns (), saved, index); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 84311cc..d87ff8c 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h @@ -21,6 +21,7 @@ #include "rust-bir-builder-internal.h" #include "rust-bir-builder-expr-stmt.h" +#include "rust-hir-expr.h" namespace Rust { namespace BIR { @@ -133,6 +134,8 @@ protected: void visit (HIR::MethodCallExpr &expr) override { rust_unreachable (); } void visit (HIR::FieldAccessExpr &expr) override { rust_unreachable (); } void visit (HIR::BlockExpr &expr) override { rust_unreachable (); } + void visit (HIR::AnonConst &expr) override { rust_unreachable (); } + void visit (HIR::ConstBlock &expr) override { rust_unreachable (); } void visit (HIR::ClosureExpr &expr) override { rust_unreachable (); } void visit (HIR::ContinueExpr &expr) override { rust_unreachable (); } void visit (HIR::BreakExpr &expr) override { rust_unreachable (); } @@ -154,6 +157,7 @@ protected: void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); } void visit (HIR::InlineAsm &expr) override { rust_unreachable (); } void visit (HIR::LlvmInlineAsm &expr) override { rust_unreachable (); } + void visit (HIR::OffsetOf &expr) override { rust_unreachable (); } void visit (HIR::TypeParam ¶m) override { rust_unreachable (); } void visit (HIR::ConstGenericParam ¶m) override { rust_unreachable (); } void visit (HIR::LifetimeWhereClauseItem &item) override diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc index 3864b81..9a7bb20 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc +++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc @@ -182,7 +182,8 @@ Dump::visit (const Statement &stmt) statement_place = stmt.get_place (); switch (stmt.get_kind ()) { - case Statement::Kind::ASSIGNMENT: { + case Statement::Kind::ASSIGNMENT: + { visit_place (stmt.get_place ()); stream << " = "; stmt.get_expr ().accept_vis (*this); diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h index 32a4cd7..4462d77 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h @@ -232,42 +232,50 @@ protected: // Main collection entry points (for different categories). { switch (stmt.get_kind ()) { - case Statement::Kind::ASSIGNMENT: { + case Statement::Kind::ASSIGNMENT: + { // TODO: for unwind, must had hadning for non-panic-only assignements issue_write_deep (stmt.get_place ()); visit_assignment_expr (stmt.get_place (), stmt.get_expr ()); break; } - case Statement::Kind::SWITCH: { + case Statement::Kind::SWITCH: + { issue_read_move (stmt.get_place ()); issue_jumps (); } break; - case Statement::Kind::GOTO: { + case Statement::Kind::GOTO: + { issue_jumps (); } break; - case Statement::Kind::RETURN: { + case Statement::Kind::RETURN: + { issue_place_access (RETURN_VALUE_PLACE); issue_locals_dealloc (); break; } - case Statement::Kind::STORAGE_DEAD: { + case Statement::Kind::STORAGE_DEAD: + { facts.path_moved_at_base.emplace_back (stmt.get_place ().value, get_current_point_mid ()); facts.var_defined_at.emplace_back (stmt.get_place ().value, get_current_point_mid ()); break; } - case Statement::Kind::STORAGE_LIVE: { + case Statement::Kind::STORAGE_LIVE: + { issue_write_deep (stmt.get_place (), true); break; } - case Statement::Kind::USER_TYPE_ASCRIPTION: { + case Statement::Kind::USER_TYPE_ASCRIPTION: + { issue_user_type_constraints (stmt.get_place (), stmt.get_type ()); break; } - case Statement::Kind::FAKE_READ: { + case Statement::Kind::FAKE_READ: + { issue_place_access (stmt.get_place ()); break; } @@ -791,7 +799,8 @@ protected: // Subset helpers. type->as<const TyTy::SliceType> ()->get_element_type (), region_start, regions); case TyTy::FNDEF: - case TyTy::TUPLE: { + case TyTy::TUPLE: + { for (auto &field : type->as<const TyTy::TupleType> ()->get_fields ()) sanitize_constraints (field.get_tyty (), region_start, regions); } @@ -815,6 +824,7 @@ protected: // Subset helpers. case TyTy::PLACEHOLDER: case TyTy::INFER: case TyTy::PARAM: + case TyTy::CONST: case TyTy::OPAQUE: rust_unreachable (); } @@ -874,7 +884,7 @@ protected: // Subset helpers. return region_end; } -}; // namespace BIR +}; } // namespace BIR } // namespace Rust diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h index dd9e672..2e9103f 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h @@ -53,7 +53,7 @@ using Variance = TyTy::VarianceAnalysis::Variance; /** A unique identifier for a loan in the BIR. */ struct LoanId { - uint32_t value; + size_t value; // some overloads for comparision bool operator== (const LoanId &rhs) const { return value == rhs.value; } bool operator!= (const LoanId &rhs) const { return !(operator== (rhs)); } @@ -217,7 +217,7 @@ public: const T &operator[] (I pid) const { return internal_vector[pid.value]; } void push_back (T &¶m) { internal_vector.push_back (std::move (param)); } - template <typename... Args> void emplace_back (Args &&... args) + template <typename... Args> void emplace_back (Args &&...args) { internal_vector.emplace_back (std::forward<Args> (args)...); } @@ -471,14 +471,16 @@ private: case TyTy::FNDEF: case TyTy::NEVER: return true; - case TyTy::TUPLE: { + case TyTy::TUPLE: + { auto &fields = ty->as<TyTy::TupleType> ()->get_fields (); return std::all_of (fields.begin (), fields.end (), [] (const TyTy::TyVar &field) { return is_type_copy (field.get_tyty ()); }); } - case TyTy::ARRAY: { + case TyTy::ARRAY: + { return is_type_copy (ty->as<TyTy::ArrayType> ()->get_element_type ()); } case TyTy::INFER: @@ -491,6 +493,7 @@ private: case TyTy::PROJECTION: // TODO: DUNNO case TyTy::CLOSURE: // TODO: DUNNO case TyTy::DYNAMIC: // TODO: dunno + case TyTy::CONST: case TyTy::OPAQUE: return false; } diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h b/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h index 5dac89e..d405569 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-visitor.h @@ -51,7 +51,7 @@ template <typename BASE, typename T> class VisitableImpl : public BASE { public: template <typename... Args> - explicit VisitableImpl (Args &&... args) : BASE (std::forward<Args> (args)...) + explicit VisitableImpl (Args &&...args) : BASE (std::forward<Args> (args)...) {} void accept_vis (Visitor &visitor) override diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index 7cf0952..86f96c1 100644 --- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h @@ -19,6 +19,7 @@ #ifndef RUST_HIR_FUNCTION_COLLECTOR_H #define RUST_HIR_FUNCTION_COLLECTOR_H +#include "rust-hir-expr.h" #include "rust-hir-item.h" #include "rust-hir-visitor.h" #include "rust-hir.h" @@ -104,6 +105,8 @@ public: void visit (HIR::MethodCallExpr &expr) override {} void visit (HIR::FieldAccessExpr &expr) override {} void visit (HIR::BlockExpr &expr) override {} + void visit (HIR::AnonConst &expr) override {} + void visit (HIR::ConstBlock &expr) override {} void visit (HIR::ContinueExpr &expr) override {} void visit (HIR::BreakExpr &expr) override {} void visit (HIR::RangeFromToExpr &expr) override {} @@ -124,6 +127,7 @@ public: void visit (HIR::AsyncBlockExpr &expr) override {} void visit (HIR::InlineAsm &expr) override {} void visit (HIR::LlvmInlineAsm &expr) override {} + void visit (HIR::OffsetOf &expr) override {} void visit (HIR::TypeParam ¶m) override {} void visit (HIR::ConstGenericParam ¶m) override {} void visit (HIR::LifetimeWhereClauseItem &item) override {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-check.cc b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc index 3d25459..5291276 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-check.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc @@ -25,8 +25,7 @@ #include "rust-pub-restricted-visitor.h" #include "rust-privacy-reporter.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Privacy { diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h index a506613f..9699ac4 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h @@ -71,8 +71,7 @@ private: #if CHECKING_P namespace selftest { -void -rust_privacy_ctx_test (void); +void rust_privacy_ctx_test (void); } #endif // !CHECKING_P diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index 2a10053..4af9639 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -157,7 +157,8 @@ PrivacyReporter::check_for_privacy_violation (const NodeId &use_id, { case ModuleVisibility::Public: break; - case ModuleVisibility::Restricted: { + case ModuleVisibility::Restricted: + { // If we are in the crate, everything is restricted correctly, but we // can't get a module for it if (!current_module.has_value ()) @@ -215,12 +216,14 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, case TyTy::USIZE: case TyTy::ISIZE: case TyTy::ADT: - case TyTy::STR: { + case TyTy::STR: + { auto ref_id = ty->get_ref (); if (auto lookup_id = mappings.lookup_hir_to_node (ref_id)) return check_for_privacy_violation (*lookup_id, locus); - rust_unreachable (); } + break; + case TyTy::REF: return recursive_check ( static_cast<const TyTy::ReferenceType *> (ty)->get_base ()); @@ -243,7 +246,8 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, static_cast<const TyTy::TupleType *> (ty)->get_fields ()) recursive_check (param.get_tyty ()); return; - case TyTy::PLACEHOLDER: { + case TyTy::PLACEHOLDER: + { const auto p = static_cast<const TyTy::PlaceholderType *> (ty); if (!p->can_resolve ()) return; @@ -273,6 +277,8 @@ PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, return; case TyTy::OPAQUE: return; + case TyTy::CONST: + return; case TyTy::ERROR: return; } @@ -310,6 +316,12 @@ PrivacyReporter::visit (HIR::LlvmInlineAsm &) {} void +PrivacyReporter::visit (HIR::OffsetOf &expr) +{ + // TODO: Do we have to do anything? +} + +void PrivacyReporter::visit (HIR::TypePath &path) { check_for_privacy_violation (path.get_mappings ().get_nodeid (), @@ -413,7 +425,8 @@ PrivacyReporter::visit (HIR::ArrayExpr &expr) HIR::ArrayElems &elements = expr.get_internal_elements (); switch (elements.get_array_expr_type ()) { - case HIR::ArrayElems::ArrayExprType::VALUES: { + case HIR::ArrayElems::ArrayExprType::VALUES: + { auto &elems = static_cast<HIR::ArrayElemsValues &> (elements); for (auto &value : elems.get_values ()) value->accept_vis (*this); @@ -518,6 +531,18 @@ PrivacyReporter::visit (HIR::BlockExpr &expr) } void +PrivacyReporter::visit (HIR::AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + +void PrivacyReporter::visit (HIR::ContinueExpr &) {} diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index 7df2cf4..72716a6 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -19,6 +19,7 @@ #ifndef RUST_PRIVACY_REPORTER_H #define RUST_PRIVACY_REPORTER_H +#include "rust-hir-expr.h" #include "rust-hir-map.h" #include "rust-hir-visitor.h" #include "rust-mapping-common.h" @@ -106,6 +107,8 @@ types virtual void visit (HIR::MethodCallExpr &expr); virtual void visit (HIR::FieldAccessExpr &expr); virtual void visit (HIR::BlockExpr &expr); + virtual void visit (HIR::AnonConst &expr); + virtual void visit (HIR::ConstBlock &expr); virtual void visit (HIR::ContinueExpr &expr); virtual void visit (HIR::BreakExpr &expr); virtual void visit (HIR::RangeFromToExpr &expr); @@ -126,6 +129,7 @@ types virtual void visit (HIR::AsyncBlockExpr &expr); virtual void visit (HIR::InlineAsm &expr); virtual void visit (HIR::LlvmInlineAsm &expr); + virtual void visit (HIR::OffsetOf &expr); virtual void visit (HIR::EnumItemTuple &); virtual void visit (HIR::EnumItemStruct &); diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.cc b/gcc/rust/checks/errors/privacy/rust-reachability.cc index 1e57674..223c77b 100644 --- a/gcc/rust/checks/errors/privacy/rust-reachability.cc +++ b/gcc/rust/checks/errors/privacy/rust-reachability.cc @@ -158,7 +158,8 @@ ReachabilityVisitor::visit (HIR::Enum &enum_item) switch (variant->get_enum_item_kind ()) { - case HIR::EnumItem::Tuple: { + case HIR::EnumItem::Tuple: + { // Should we update the fields only if they are public? Similarly to // what we do in the ReachabilityVisitor for HIR::TupleStruct? auto tuple_variant @@ -167,7 +168,8 @@ ReachabilityVisitor::visit (HIR::Enum &enum_item) ctx.update_reachability (field.get_mappings (), variant_reach); break; } - case HIR::EnumItem::Struct: { + case HIR::EnumItem::Struct: + { // Should we update the fields only if they are public? Similarly to // what we do in the ReachabilityVisitor for HIR::StructStruct? auto struct_variant diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc index f0da745..c59763d 100644 --- a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc +++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc @@ -127,7 +127,8 @@ VisibilityResolver::resolve_visibility (const HIR::Visibility &visibility, case HIR::Visibility::PUBLIC: to_resolve = ModuleVisibility::create_public (); return true; - case HIR::Visibility::RESTRICTED: { + case HIR::Visibility::RESTRICTED: + { // FIXME: We also need to handle 2015 vs 2018 edition conflicts auto id = UNKNOWN_DEFID; auto result = resolve_module_path (visibility.get_path (), id); diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 3716ea5..c40f9db 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -417,6 +417,26 @@ ConstChecker::visit (BlockExpr &expr) } void +ConstChecker::visit (AnonConst &expr) +{ + const_context.enter (expr.get_mappings ().get_hirid ()); + + expr.get_inner_expr ().accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (ConstBlock &expr) +{ + const_context.enter (expr.get_mappings ().get_hirid ()); + + expr.get_const_expr ().accept_vis (*this); + + const_context.exit (); +} + +void ConstChecker::visit (ContinueExpr &) {} @@ -541,6 +561,10 @@ ConstChecker::visit (LlvmInlineAsm &) {} void +ConstChecker::visit (OffsetOf &) +{} + +void ConstChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h index b954330..eb63095 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -113,6 +113,8 @@ private: virtual void visit (FieldAccessExpr &expr) override; virtual void visit (ClosureExpr &expr) override; virtual void visit (BlockExpr &expr) override; + virtual void visit (AnonConst &expr) override; + virtual void visit (ConstBlock &expr) override; virtual void visit (ContinueExpr &expr) override; virtual void visit (BreakExpr &expr) override; virtual void visit (RangeFromToExpr &expr) override; @@ -133,6 +135,7 @@ private: virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; virtual void visit (LlvmInlineAsm &expr) override; + virtual void visit (OffsetOf &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; diff --git a/gcc/rust/checks/errors/rust-feature.cc b/gcc/rust/checks/errors/rust-feature.cc index 441a1b2..071d3f8 100644 --- a/gcc/rust/checks/errors/rust-feature.cc +++ b/gcc/rust/checks/errors/rust-feature.cc @@ -84,7 +84,7 @@ const std::map<std::string, Feature::Name> Feature::name_hash_map = { {"exclusive_range_pattern", Feature::Name::EXCLUSIVE_RANGE_PATTERN}, {"prelude_import", Feature::Name::PRELUDE_IMPORT}, {"min_specialization", Feature::Name::MIN_SPECIALIZATION}, -}; // namespace Rust +}; tl::optional<Feature::Name> Feature::as_name (const std::string &name) diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc index 648bc07..2566971 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -295,6 +295,18 @@ PatternChecker::visit (BlockExpr &expr) } void +PatternChecker::visit (AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +PatternChecker::visit (ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + +void PatternChecker::visit (ContinueExpr &) {} @@ -427,6 +439,10 @@ PatternChecker::visit (LlvmInlineAsm &expr) {} void +PatternChecker::visit (OffsetOf &expr) +{} + +void PatternChecker::visit (TypeParam &) {} @@ -728,23 +744,27 @@ Constructor::is_covered_by (const Constructor &o) const switch (kind) { - case ConstructorKind::VARIANT: { + case ConstructorKind::VARIANT: + { rust_assert (kind == ConstructorKind::VARIANT); return variant_idx == o.variant_idx; } break; - case ConstructorKind::INT_RANGE: { + case ConstructorKind::INT_RANGE: + { rust_assert (kind == ConstructorKind::INT_RANGE); return int_range.lo >= o.int_range.lo && int_range.hi <= o.int_range.hi; } break; - case ConstructorKind::WILDCARD: { + case ConstructorKind::WILDCARD: + { // TODO: wildcard is covered by a variant of enum with a single // variant return false; } break; - case ConstructorKind::STRUCT: { + case ConstructorKind::STRUCT: + { // Struct pattern is always covered by a other struct constructor. return true; } @@ -900,19 +920,22 @@ PlaceInfo::specialize (const Constructor &c) const switch (c.get_kind ()) { case Constructor::ConstructorKind::WILDCARD: - case Constructor::ConstructorKind::INT_RANGE: { + case Constructor::ConstructorKind::INT_RANGE: + { return {}; } break; case Constructor::ConstructorKind::STRUCT: - case Constructor::ConstructorKind::VARIANT: { + case Constructor::ConstructorKind::VARIANT: + { rust_assert (ty->get_kind () == TyTy::TypeKind::ADT); TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); switch (adt->get_adt_kind ()) { case TyTy::ADTType::ADTKind::ENUM: case TyTy::ADTType::ADTKind::STRUCT_STRUCT: - case TyTy::ADTType::ADTKind::TUPLE_STRUCT: { + case TyTy::ADTType::ADTKind::TUPLE_STRUCT: + { TyTy::VariantDef *variant = adt->get_variants ().at (c.get_variant_index ()); if (variant->get_variant_type () @@ -926,14 +949,16 @@ PlaceInfo::specialize (const Constructor &c) const return new_place_infos; } break; - case TyTy::ADTType::ADTKind::UNION: { + case TyTy::ADTType::ADTKind::UNION: + { // TODO: support unions rust_unreachable (); } } } break; - default: { + default: + { rust_unreachable (); } break; @@ -991,7 +1016,8 @@ WitnessPat::to_string () const { switch (ctor.get_kind ()) { - case Constructor::ConstructorKind::STRUCT: { + case Constructor::ConstructorKind::STRUCT: + { TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); TyTy::VariantDef *variant = adt->get_variants ().at (ctor.get_variant_index ()); @@ -1016,7 +1042,8 @@ WitnessPat::to_string () const return buf; } break; - case Constructor::ConstructorKind::VARIANT: { + case Constructor::ConstructorKind::VARIANT: + { std::string buf; TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); buf += adt->get_identifier (); @@ -1026,11 +1053,13 @@ WitnessPat::to_string () const switch (variant->get_variant_type ()) { - case TyTy::VariantDef::VariantType::NUM: { + case TyTy::VariantDef::VariantType::NUM: + { return buf; } break; - case TyTy::VariantDef::VariantType::TUPLE: { + case TyTy::VariantDef::VariantType::TUPLE: + { buf += "("; for (size_t i = 0; i < fields.size (); i++) { @@ -1042,7 +1071,8 @@ WitnessPat::to_string () const return buf; } break; - case TyTy::VariantDef::VariantType::STRUCT: { + case TyTy::VariantDef::VariantType::STRUCT: + { buf += " {"; if (!fields.empty ()) buf += " "; @@ -1061,7 +1091,8 @@ WitnessPat::to_string () const buf += "}"; } break; - default: { + default: + { rust_unreachable (); } break; @@ -1069,21 +1100,25 @@ WitnessPat::to_string () const return buf; } break; - case Constructor::ConstructorKind::INT_RANGE: { + case Constructor::ConstructorKind::INT_RANGE: + { // TODO: implement rust_unreachable (); } break; - case Constructor::ConstructorKind::WILDCARD: { + case Constructor::ConstructorKind::WILDCARD: + { return "_"; } break; - case Constructor::ConstructorKind::REFERENCE: { + case Constructor::ConstructorKind::REFERENCE: + { // TODO: implement rust_unreachable (); } break; - default: { + default: + { rust_unreachable (); } break; @@ -1100,12 +1135,14 @@ WitnessMatrix::apply_constructor (const Constructor &ctor, // TODO: only support struct and variant ctor for now. switch (ctor.get_kind ()) { - case Constructor::ConstructorKind::WILDCARD: { + case Constructor::ConstructorKind::WILDCARD: + { arity = 0; } break; case Constructor::ConstructorKind::STRUCT: - case Constructor::ConstructorKind::VARIANT: { + case Constructor::ConstructorKind::VARIANT: + { if (ty->get_kind () == TyTy::TypeKind::ADT) { TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty); @@ -1118,7 +1155,8 @@ WitnessMatrix::apply_constructor (const Constructor &ctor, } } break; - default: { + default: + { rust_unreachable (); } } @@ -1160,9 +1198,9 @@ WitnessMatrix::extend (const WitnessMatrix &other) } // forward declarations -static DeconstructedPat -lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, - TyTy::BaseType *scrutinee_ty); +static DeconstructedPat lower_pattern (Resolver::TypeCheckContext *ctx, + HIR::Pattern &pattern, + TyTy::BaseType *scrutinee_ty); static DeconstructedPat lower_tuple_pattern (Resolver::TypeCheckContext *ctx, @@ -1175,7 +1213,8 @@ lower_tuple_pattern (Resolver::TypeCheckContext *ctx, std::vector<DeconstructedPat> fields; switch (elems.get_item_type ()) { - case HIR::TupleStructItems::ItemType::MULTIPLE: { + case HIR::TupleStructItems::ItemType::MULTIPLE: + { HIR::TupleStructItemsNoRange &multiple = static_cast<HIR::TupleStructItemsNoRange &> (elems); @@ -1191,12 +1230,14 @@ lower_tuple_pattern (Resolver::TypeCheckContext *ctx, return DeconstructedPat (ctor, arity, fields, pattern.get_locus ()); } break; - case HIR::TupleStructItems::ItemType::RANGED: { + case HIR::TupleStructItems::ItemType::RANGED: + { // TODO: ranged tuple struct items rust_unreachable (); } break; - default: { + default: + { rust_unreachable (); } } @@ -1227,7 +1268,8 @@ lower_struct_pattern (Resolver::TypeCheckContext *ctx, { switch (elem->get_item_type ()) { - case HIR::StructPatternField::ItemType::IDENT: { + case HIR::StructPatternField::ItemType::IDENT: + { HIR::StructPatternFieldIdent *ident = static_cast<HIR::StructPatternFieldIdent *> (elem.get ()); int field_idx @@ -1236,7 +1278,8 @@ lower_struct_pattern (Resolver::TypeCheckContext *ctx, = DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { + case HIR::StructPatternField::ItemType::IDENT_PAT: + { HIR::StructPatternFieldIdentPat *ident_pat = static_cast<HIR::StructPatternFieldIdentPat *> (elem.get ()); int field_idx @@ -1246,12 +1289,14 @@ lower_struct_pattern (Resolver::TypeCheckContext *ctx, variant->get_fields ().at (field_idx)->get_field_type ()); } break; - case HIR::StructPatternField::ItemType::TUPLE_PAT: { + case HIR::StructPatternField::ItemType::TUPLE_PAT: + { // TODO: tuple: pat rust_unreachable (); } break; - default: { + default: + { rust_unreachable (); } } @@ -1268,11 +1313,13 @@ lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, switch (pat_type) { case HIR::Pattern::PatternType::WILDCARD: - case HIR::Pattern::PatternType::IDENTIFIER: { + case HIR::Pattern::PatternType::IDENTIFIER: + { return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::PATH: { + case HIR::Pattern::PatternType::PATH: + { // TODO: support constants, associated constants, enum variants and // structs // https://doc.rust-lang.org/reference/patterns.html#path-patterns @@ -1280,13 +1327,15 @@ lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::REFERENCE: { + case HIR::Pattern::PatternType::REFERENCE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; case HIR::Pattern::PatternType::STRUCT: - case HIR::Pattern::PatternType::TUPLE_STRUCT: { + case HIR::Pattern::PatternType::TUPLE_STRUCT: + { HirId path_id = UNKNOWN_HIRID; if (pat_type == HIR::Pattern::PatternType::STRUCT) { @@ -1343,37 +1392,44 @@ lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern &pattern, } } break; - case HIR::Pattern::PatternType::TUPLE: { + case HIR::Pattern::PatternType::TUPLE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::SLICE: { + case HIR::Pattern::PatternType::SLICE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::ALT: { + case HIR::Pattern::PatternType::ALT: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::LITERAL: { + case HIR::Pattern::PatternType::LITERAL: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::RANGE: { + case HIR::Pattern::PatternType::RANGE: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - case HIR::Pattern::PatternType::GROUPED: { + case HIR::Pattern::PatternType::GROUPED: + { // TODO: unimplemented. Treat this pattern as wildcard for now. return DeconstructedPat::make_wildcard (pattern.get_locus ()); } break; - default: { + default: + { rust_unreachable (); } } diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 6d60ced..dd44abc 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -33,9 +33,9 @@ namespace Analysis { using namespace HIR; -void -check_match_usefulness (Resolver::TypeCheckContext *ctx, - TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr); +void check_match_usefulness (Resolver::TypeCheckContext *ctx, + TyTy::BaseType *scrutinee_ty, + HIR::MatchExpr &expr); class PatternChecker : public HIR::HIRFullVisitor { @@ -86,6 +86,8 @@ private: virtual void visit (MethodCallExpr &expr) override; virtual void visit (FieldAccessExpr &expr) override; virtual void visit (BlockExpr &expr) override; + virtual void visit (AnonConst &expr) override; + virtual void visit (ConstBlock &expr) override; virtual void visit (ClosureExpr &expr) override; virtual void visit (ContinueExpr &expr) override; virtual void visit (BreakExpr &expr) override; @@ -107,6 +109,7 @@ private: virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; virtual void visit (LlvmInlineAsm &expr) override; + virtual void visit (OffsetOf &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; virtual void visit (LifetimeWhereClauseItem &item) override; diff --git a/gcc/rust/checks/errors/rust-readonly-check2.cc b/gcc/rust/checks/errors/rust-readonly-check2.cc new file mode 100644 index 0000000..2fa92ae --- /dev/null +++ b/gcc/rust/checks/errors/rust-readonly-check2.cc @@ -0,0 +1,253 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-readonly-check2.h" +#include "rust-hir-expr.h" +#include "rust-hir-node.h" +#include "rust-hir-path.h" +#include "rust-hir-map.h" +#include "rust-hir-pattern.h" +#include "rust-mapping-common.h" +#include "rust-system.h" +#include "rust-immutable-name-resolution-context.h" +#include "rust-tyty.h" + +namespace Rust { +namespace HIR { + +static std::set<HirId> already_assigned_variables = {}; + +ReadonlyChecker::ReadonlyChecker () + : resolver (*Resolver::Resolver::get ()), + mappings (Analysis::Mappings::get ()), + context (*Resolver::TypeCheckContext::get ()) +{} + +void +ReadonlyChecker::go (Crate &crate) +{ + for (auto &item : crate.get_items ()) + item->accept_vis (*this); +} + +void +ReadonlyChecker::visit (AssignmentExpr &expr) +{ + Expr &lhs = expr.get_lhs (); + mutable_context.enter (expr.get_mappings ().get_hirid ()); + lhs.accept_vis (*this); + mutable_context.exit (); +} + +void +ReadonlyChecker::visit (PathInExpression &expr) +{ + if (!mutable_context.is_in_context ()) + return; + + NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + NodeId def_id; + + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + if (auto id = nr_ctx.lookup (ast_node_id)) + def_id = *id; + else + return; + + auto hir_id = mappings.lookup_node_to_hir (def_id); + if (!hir_id) + return; + + // Check if the local variable is mutable. + auto maybe_pattern = mappings.lookup_hir_pattern (*hir_id); + if (maybe_pattern + && maybe_pattern.value ()->get_pattern_type () + == HIR::Pattern::PatternType::IDENTIFIER) + check_variable (static_cast<IdentifierPattern *> (maybe_pattern.value ()), + expr.get_locus ()); + + // Check if the static item is mutable. + auto maybe_item = mappings.lookup_hir_item (*hir_id); + if (maybe_item + && maybe_item.value ()->get_item_kind () == HIR::Item::ItemKind::Static) + { + auto static_item = static_cast<HIR::StaticItem *> (*maybe_item); + if (!static_item->is_mut ()) + rust_error_at (expr.get_locus (), + "assignment of read-only location '%s'", + static_item->get_identifier ().as_string ().c_str ()); + } + + // Check if the constant item is mutable. + if (maybe_item + && maybe_item.value ()->get_item_kind () == HIR::Item::ItemKind::Constant) + { + auto const_item = static_cast<HIR::ConstantItem *> (*maybe_item); + rust_error_at (expr.get_locus (), "assignment of read-only location '%s'", + const_item->get_identifier ().as_string ().c_str ()); + } +} + +void +ReadonlyChecker::check_variable (IdentifierPattern *pattern, + location_t assigned_loc) +{ + if (!mutable_context.is_in_context ()) + return; + if (pattern->is_mut ()) + return; + + auto hir_id = pattern->get_mappings ().get_hirid (); + if (already_assigned_variables.count (hir_id) > 0) + rust_error_at (assigned_loc, "assignment of read-only variable '%s'", + pattern->as_string ().c_str ()); + already_assigned_variables.insert (hir_id); +} + +void +ReadonlyChecker::collect_assignment_identifier (IdentifierPattern &pattern, + bool has_init_expr) +{ + if (has_init_expr) + { + HirId pattern_id = pattern.get_mappings ().get_hirid (); + already_assigned_variables.insert (pattern_id); + } +} + +void +ReadonlyChecker::collect_assignment_tuple (TuplePattern &tuple_pattern, + bool has_init_expr) +{ + switch (tuple_pattern.get_items ().get_item_type ()) + { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { + auto &items = static_cast<HIR::TuplePatternItemsMultiple &> ( + tuple_pattern.get_items ()); + for (auto &sub : items.get_patterns ()) + { + collect_assignment (*sub, has_init_expr); + } + } + break; + default: + break; + } +} + +void +ReadonlyChecker::collect_assignment (Pattern &pattern, bool has_init_expr) +{ + switch (pattern.get_pattern_type ()) + { + case HIR::Pattern::PatternType::IDENTIFIER: + { + collect_assignment_identifier (static_cast<IdentifierPattern &> ( + pattern), + has_init_expr); + } + break; + case HIR::Pattern::PatternType::TUPLE: + { + auto &tuple_pattern = static_cast<HIR::TuplePattern &> (pattern); + collect_assignment_tuple (tuple_pattern, has_init_expr); + } + break; + default: + break; + } +} + +void +ReadonlyChecker::visit (LetStmt &stmt) +{ + HIR::Pattern &pattern = stmt.get_pattern (); + collect_assignment (pattern, stmt.has_init_expr ()); +} + +void +ReadonlyChecker::visit (FieldAccessExpr &expr) +{ + if (mutable_context.is_in_context ()) + { + expr.get_receiver_expr ().accept_vis (*this); + } +} + +void +ReadonlyChecker::visit (TupleIndexExpr &expr) +{ + if (mutable_context.is_in_context ()) + { + expr.get_tuple_expr ().accept_vis (*this); + } +} + +void +ReadonlyChecker::visit (ArrayIndexExpr &expr) +{ + if (mutable_context.is_in_context ()) + { + expr.get_array_expr ().accept_vis (*this); + } +} + +void +ReadonlyChecker::visit (TupleExpr &expr) +{ + if (mutable_context.is_in_context ()) + { + // TODO: Add check for tuple expression + } +} + +void +ReadonlyChecker::visit (LiteralExpr &expr) +{ + if (mutable_context.is_in_context ()) + { + rust_error_at (expr.get_locus (), "assignment of read-only location"); + } +} + +void +ReadonlyChecker::visit (DereferenceExpr &expr) +{ + if (!mutable_context.is_in_context ()) + return; + TyTy::BaseType *to_deref_type; + auto to_deref = expr.get_expr ().get_mappings ().get_hirid (); + if (!context.lookup_type (to_deref, &to_deref_type)) + return; + if (to_deref_type->get_kind () == TyTy::TypeKind::REF) + { + auto ref_type = static_cast<TyTy::ReferenceType *> (to_deref_type); + if (!ref_type->is_mutable ()) + rust_error_at (expr.get_locus (), "assignment of read-only location"); + } + if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER) + { + auto ptr_type = static_cast<TyTy::PointerType *> (to_deref_type); + if (!ptr_type->is_mutable ()) + rust_error_at (expr.get_locus (), "assignment of read-only location"); + } +} +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/checks/errors/rust-readonly-check2.h b/gcc/rust/checks/errors/rust-readonly-check2.h new file mode 100644 index 0000000..06af9db --- /dev/null +++ b/gcc/rust/checks/errors/rust-readonly-check2.h @@ -0,0 +1,67 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-hir-visitor.h" +#include "rust-name-resolver.h" +#include "rust-stacked-contexts.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace HIR { +class ReadonlyChecker : public DefaultHIRVisitor +{ +public: + ReadonlyChecker (); + + void go (HIR::Crate &crate); + +private: + enum class lvalue_use + { + assign, + increment, + decrement, + }; + + Resolver::Resolver &resolver; + Analysis::Mappings &mappings; + Resolver::TypeCheckContext &context; + StackedContexts<HirId> mutable_context; + + using DefaultHIRVisitor::visit; + + virtual void visit (AssignmentExpr &expr) override; + virtual void visit (PathInExpression &expr) override; + virtual void visit (FieldAccessExpr &expr) override; + virtual void visit (ArrayIndexExpr &expr) override; + virtual void visit (TupleExpr &expr) override; + virtual void visit (TupleIndexExpr &expr) override; + virtual void visit (LetStmt &stmt) override; + virtual void visit (LiteralExpr &expr) override; + virtual void visit (DereferenceExpr &expr) override; + + void collect_assignment (Pattern &pattern, bool has_init_expr); + void collect_assignment_identifier (IdentifierPattern &pattern, + bool has_init_expr); + void collect_assignment_tuple (TuplePattern &pattern, bool has_init_expr); + + void check_variable (IdentifierPattern *pattern, location_t assigned_loc); +}; + +} // namespace HIR +} // namespace Rust
\ No newline at end of file diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc index 46eef11..405c59b 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -540,6 +540,18 @@ UnsafeChecker::visit (BlockExpr &expr) } void +UnsafeChecker::visit (AnonConst &expr) +{ + expr.get_inner_expr ().accept_vis (*this); +} + +void +UnsafeChecker::visit (ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + +void UnsafeChecker::visit (ContinueExpr &) {} @@ -682,6 +694,12 @@ UnsafeChecker::visit (LlvmInlineAsm &expr) } void +UnsafeChecker::visit (OffsetOf &expr) +{ + // nothing to do, offset_of!() is safe +} + +void UnsafeChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h index 9a8fb7c..dc3b482 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -95,6 +95,8 @@ private: virtual void visit (FieldAccessExpr &expr) override; virtual void visit (ClosureExpr &expr) override; virtual void visit (BlockExpr &expr) override; + virtual void visit (AnonConst &expr) override; + virtual void visit (ConstBlock &expr) override; virtual void visit (ContinueExpr &expr) override; virtual void visit (BreakExpr &expr) override; virtual void visit (RangeFromToExpr &expr) override; @@ -115,6 +117,7 @@ private: virtual void visit (AsyncBlockExpr &expr) override; virtual void visit (InlineAsm &expr) override; virtual void visit (LlvmInlineAsm &expr) override; + virtual void visit (OffsetOf &expr) override; virtual void visit (TypeParam ¶m) override; virtual void visit (ConstGenericParam ¶m) override; virtual void visit (LifetimeWhereClauseItem &item) override; diff --git a/gcc/rust/checks/lints/rust-lint-unused-var.cc b/gcc/rust/checks/lints/rust-lint-unused-var.cc index 896eeb0..08596f1 100644 --- a/gcc/rust/checks/lints/rust-lint-unused-var.cc +++ b/gcc/rust/checks/lints/rust-lint-unused-var.cc @@ -31,6 +31,7 @@ check_decl (tree *t) tree var_name = DECL_NAME (*t); const char *var_name_ptr = IDENTIFIER_POINTER (var_name); bool starts_with_under_score = strncmp (var_name_ptr, "_", 1) == 0; + bool is_self = strcmp (var_name_ptr, "self") == 0; bool is_constant = TREE_CODE (*t) == CONST_DECL; // if (!is_constant) @@ -43,7 +44,8 @@ check_decl (tree *t) // starts_with_under_score ? "true" : "false", var_name_ptr); // } - if (!TREE_USED (*t) && !DECL_ARTIFICIAL (*t) && !starts_with_under_score) + if (!TREE_USED (*t) && !DECL_ARTIFICIAL (*t) && !starts_with_under_score + && !is_self) { warning_at (DECL_SOURCE_LOCATION (*t), is_constant ? OPT_Wunused_const_variable_ diff --git a/gcc/rust/expand/rust-cfg-strip.cc b/gcc/rust/expand/rust-cfg-strip.cc index a8c3ca5..58d8071 100644 --- a/gcc/rust/expand/rust-cfg-strip.cc +++ b/gcc/rust/expand/rust-cfg-strip.cc @@ -289,7 +289,8 @@ CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args) { switch (arg.get_kind ()) { - case AST::GenericArg::Kind::Type: { + case AST::GenericArg::Kind::Type: + { auto &type = arg.get_type (); type.accept_vis (*this); @@ -298,7 +299,8 @@ CfgStrip::maybe_strip_generic_args (AST::GenericArgs &args) "cannot strip type in this position"); break; } - case AST::GenericArg::Kind::Const: { + case AST::GenericArg::Kind::Const: + { auto &expr = arg.get_expression (); expr.accept_vis (*this); @@ -1190,7 +1192,7 @@ CfgStrip::visit (AST::ClosureExprInnerTyped &expr) rust_error_at (type.get_locus (), "cannot strip type in this position"); // can't strip expression itself, but can strip sub-expressions - auto &definition_block = expr.get_definition_block (); + auto &definition_block = expr.get_definition_expr (); definition_block.accept_vis (*this); if (definition_block.is_marked_for_strip ()) rust_error_at (definition_block.get_locus (), @@ -1763,16 +1765,17 @@ CfgStrip::visit (AST::Module &module) return; } - // A loaded module might have inner attributes - if (module.get_kind () == AST::Module::ModuleKind::LOADED) + if (module.get_kind () == AST::Module::UNLOADED) { - // strip test based on inner attrs - expand_cfg_attrs (module.get_inner_attrs ()); - if (fails_cfg_with_expand (module.get_inner_attrs ())) - { - module.mark_for_strip (); - return; - } + module.load_items (); + } + + // strip test based on inner attrs + expand_cfg_attrs (module.get_inner_attrs ()); + if (fails_cfg_with_expand (module.get_inner_attrs ())) + { + module.mark_for_strip (); + return; } // strip items if required @@ -2260,12 +2263,12 @@ void CfgStrip::visit (AST::IdentifierPattern &pattern) { // can only strip sub-patterns of the inner pattern to bind - if (!pattern.has_pattern_to_bind ()) + if (!pattern.has_subpattern ()) return; AST::DefaultASTVisitor::visit (pattern); - auto &sub_pattern = pattern.get_pattern_to_bind (); + auto &sub_pattern = pattern.get_subpattern (); if (sub_pattern.is_marked_for_strip ()) rust_error_at (sub_pattern.get_locus (), "cannot strip pattern in this position"); @@ -2475,20 +2478,44 @@ CfgStrip::visit (AST::GroupedPattern &pattern) } void -CfgStrip::visit (AST::SlicePattern &pattern) +CfgStrip::visit (AST::SlicePatternItemsNoRest &items) { - AST::DefaultASTVisitor::visit (pattern); + AST::DefaultASTVisitor::visit (items); // can't strip individual patterns, only sub-patterns - for (auto &item : pattern.get_items ()) + for (auto &pattern : items.get_patterns ()) { - if (item->is_marked_for_strip ()) - rust_error_at (item->get_locus (), + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), "cannot strip pattern in this position"); - // TODO: quit stripping now? or keep going? } } void +CfgStrip::visit (AST::SlicePatternItemsHasRest &items) +{ + AST::DefaultASTVisitor::visit (items); + // can't strip individual patterns, only sub-patterns + for (auto &pattern : items.get_lower_patterns ()) + { + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + for (auto &pattern : items.get_upper_patterns ()) + { + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } +} + +void +CfgStrip::visit (AST::SlicePattern &pattern) +{ + AST::DefaultASTVisitor::visit (pattern); +} + +void CfgStrip::visit (AST::AltPattern &pattern) { AST::DefaultASTVisitor::visit (pattern); diff --git a/gcc/rust/expand/rust-cfg-strip.h b/gcc/rust/expand/rust-cfg-strip.h index 4900ae8..767cf28 100644 --- a/gcc/rust/expand/rust-cfg-strip.h +++ b/gcc/rust/expand/rust-cfg-strip.h @@ -172,6 +172,8 @@ public: void visit (AST::TuplePatternItemsMultiple &tuple_items) override; void visit (AST::TuplePatternItemsRanged &tuple_items) override; void visit (AST::GroupedPattern &pattern) override; + void visit (AST::SlicePatternItemsNoRest &items) override; + void visit (AST::SlicePatternItemsHasRest &items) override; void visit (AST::SlicePattern &pattern) override; void visit (AST::AltPattern &pattern) override; diff --git a/gcc/rust/expand/rust-derive-clone.h b/gcc/rust/expand/rust-derive-clone.h index 61224ba..a3320c7 100644 --- a/gcc/rust/expand/rust-derive-clone.h +++ b/gcc/rust/expand/rust-derive-clone.h @@ -29,7 +29,7 @@ class DeriveClone : DeriveVisitor public: DeriveClone (location_t loc); - std::unique_ptr<AST::Item> go (Item &item); + std::unique_ptr<Item> go (Item &item); private: std::unique_ptr<Item> expanded; @@ -80,10 +80,10 @@ private: MatchCase clone_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-cmp-common.cc b/gcc/rust/expand/rust-derive-cmp-common.cc new file mode 100644 index 0000000..22ca16f --- /dev/null +++ b/gcc/rust/expand/rust-derive-cmp-common.cc @@ -0,0 +1,191 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-derive-cmp-common.h" +#include "rust-ast-builder.h" +#include "rust-item.h" + +namespace Rust { +namespace AST { + +SelfOther +SelfOther::index (Builder builder, int idx) +{ + return SelfOther{ + builder.tuple_idx ("self", idx), + builder.tuple_idx ("other", idx), + }; +} + +std::vector<SelfOther> +SelfOther::indexes (Builder builder, const std::vector<TupleField> &fields) +{ + std::vector<SelfOther> vec; + + for (size_t i = 0; i < fields.size (); i++) + vec.emplace_back (SelfOther::index (builder, i)); + + return vec; +} + +SelfOther +SelfOther::field (Builder builder, const std::string &field_name) +{ + return SelfOther{ + builder.field_access (builder.identifier ("self"), field_name), + builder.field_access (builder.identifier ("other"), field_name), + }; +} + +std::vector<SelfOther> +SelfOther::fields (Builder builder, const std::vector<StructField> &fields) +{ + std::vector<SelfOther> vec; + + for (const auto &field : fields) + vec.emplace_back ( + SelfOther::field (builder, field.get_field_name ().as_string ())); + + return vec; +} + +MatchCase +EnumMatchBuilder::tuple (EnumItem &variant_raw) +{ + auto &variant = static_cast<EnumItemTuple &> (variant_raw); + + auto self_patterns = std::vector<std::unique_ptr<Pattern>> (); + auto other_patterns = std::vector<std::unique_ptr<Pattern>> (); + + auto self_other_exprs = std::vector<SelfOther> (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + // The patterns we're creating for each field are `self_<i>` and + // `other_<i>` where `i` is the index of the field. It doesn't actually + // matter what we use, as long as it's ordered, unique, and that we can + // reuse it in the match case's return expression to check that they are + // equal. + + auto self_pattern_str = "__self_" + std::to_string (i); + auto other_pattern_str = "__other_" + std::to_string (i); + + self_patterns.emplace_back ( + builder.identifier_pattern (self_pattern_str)); + other_patterns.emplace_back ( + builder.identifier_pattern (other_pattern_str)); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + // TODO: Replace with `reconstruct()` instead of building these twice + auto self_variant_path = builder.variant_path (enum_path, variant_path); + auto other_variant_path = builder.variant_path (enum_path, variant_path); + + auto self_pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (self_patterns))); + auto other_pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (other_patterns))); + + auto self_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern ( + self_variant_path, std::move (self_pattern_items))), + false, false, builder.loc)); + auto other_pattern = std::unique_ptr<Pattern> (new ReferencePattern ( + std::unique_ptr<Pattern> (new TupleStructPattern ( + other_variant_path, std::move (other_pattern_items))), + false, false, builder.loc)); + + auto tuple_items = std::make_unique<TuplePatternItemsMultiple> ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern + = std::make_unique<TuplePattern> (std::move (tuple_items), builder.loc); + + auto expr = fn (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +MatchCase +EnumMatchBuilder::strukt (EnumItem &variant_raw) +{ + auto &variant = static_cast<EnumItemStruct &> (variant_raw); + + auto self_fields = std::vector<std::unique_ptr<StructPatternField>> (); + auto other_fields = std::vector<std::unique_ptr<StructPatternField>> (); + + auto self_other_exprs = std::vector<SelfOther> (); + + for (auto &field : variant.get_struct_fields ()) + { + // The patterns we're creating for each field are `self_<field>` and + // `other_<field>` where `field` is the name of the field. It doesn't + // actually matter what we use, as long as it's ordered, unique, and that + // we can reuse it in the match case's return expression to check that + // they are equal. + + auto field_name = field.get_field_name ().as_string (); + + auto self_pattern_str = "__self_" + field_name; + auto other_pattern_str = "__other_" + field_name; + + self_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (self_pattern_str))); + other_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (other_pattern_str))); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + // TODO: Replace with `reconstruct()` instead of building these twice + auto self_variant_path = builder.variant_path (enum_path, variant_path); + auto other_variant_path = builder.variant_path (enum_path, variant_path); + + auto self_elts = StructPatternElements (std::move (self_fields)); + auto other_elts = StructPatternElements (std::move (other_fields)); + + auto self_pattern = std::unique_ptr<Pattern> (new ReferencePattern ( + std::unique_ptr<Pattern> (new StructPattern (self_variant_path, builder.loc, + std::move (self_elts))), + false, false, builder.loc)); + auto other_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> ( + new StructPattern (other_variant_path, builder.loc, + std::move (other_elts))), + false, false, builder.loc)); + + auto tuple_items = std::make_unique<TuplePatternItemsMultiple> ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern + = std::make_unique<TuplePattern> (std::move (tuple_items), builder.loc); + + auto expr = fn (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-cmp-common.h b/gcc/rust/expand/rust-derive-cmp-common.h new file mode 100644 index 0000000..4efbed8 --- /dev/null +++ b/gcc/rust/expand/rust-derive-cmp-common.h @@ -0,0 +1,99 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_DERIVE_CMP_COMMON_H +#define RUST_DERIVE_CMP_COMMON_H + +#include "rust-ast.h" +#include "rust-ast-builder.h" +#include "rust-item.h" +#include "rust-path.h" + +namespace Rust { +namespace AST { + +/** + * A pair of two expressions from each instance being compared. E.g. this + * could be `self.0` and `other.0`, or `self.field` and `other.field` + */ +struct SelfOther +{ + std::unique_ptr<Expr> self_expr; + std::unique_ptr<Expr> other_expr; + + /* Create a <self.i> and an <other.i> expression */ + static SelfOther index (Builder builder, int idx); + static std::vector<SelfOther> indexes (Builder builder, + const std::vector<TupleField> &fields); + + /* Create a <self.field> and an <other.field> expression */ + static SelfOther field (Builder builder, const std::string &field_name); + static std::vector<SelfOther> fields (Builder builder, + const std::vector<StructField> &fields); +}; + +/** + * Builder for common match cases used when comparing two enum instances. This + * builder takes care of creating the unique patterns for the `self` instance + * and `other` instance, as well as the entire `MatchCase` required for building + * a proper comparision expression for an implementation of a comparision trait + * for an enum type. The functions take a lambda to use when creating the + * expression of the generated `MatchCase`. + */ +class EnumMatchBuilder +{ +public: + /** + * The type of functions to call when creating the resulting expression in the + * generated `MatchCase` + */ + using ExprFn + = std::function<std::unique_ptr<Expr> (std::vector<SelfOther> &&)>; + + EnumMatchBuilder (const std::string &enum_path, + const std::string &variant_path, ExprFn fn, + Builder &builder) + : enum_path (enum_path), variant_path (variant_path), fn (fn), + builder (builder) + {} + + /** + * Generate a `MatchCase` for an enum tuple variant + * + * (&Enum::Tuple(self0, self1), &Enum::Tuple(other0, other1)) => <fn> + */ + MatchCase tuple (EnumItem &variant); + + /** + * Generate a `MatchCase` for an enum struct variant + * + * (&Enum::Struct { a: self_a }, &Enum::Struct { a: other_a }) => <fn> + */ + MatchCase strukt (EnumItem &variant); + +private: + const std::string &enum_path; + const std::string &variant_path; + ExprFn fn; + Builder &builder; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_CMP_COMMON_H diff --git a/gcc/rust/expand/rust-derive-copy.h b/gcc/rust/expand/rust-derive-copy.h index 71972eb..664a8e0 100644 --- a/gcc/rust/expand/rust-derive-copy.h +++ b/gcc/rust/expand/rust-derive-copy.h @@ -44,10 +44,10 @@ private: copy_impl (std::string name, const std::vector<std::unique_ptr<GenericParam>> &type_generics); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-default.cc b/gcc/rust/expand/rust-derive-default.cc index 2e8b456..26ee546 100644 --- a/gcc/rust/expand/rust-derive-default.cc +++ b/gcc/rust/expand/rust-derive-default.cc @@ -98,7 +98,8 @@ DeriveDefault::visit_struct (StructStruct &item) for (auto &field : item.get_fields ()) { auto name = field.get_field_name ().as_string (); - auto expr = default_call (field.get_field_type ().clone_type ()); + auto type = field.get_field_type ().reconstruct (); + auto expr = default_call (std::move (type)); cloned_fields.emplace_back ( builder.struct_expr_field (std::move (name), std::move (expr))); @@ -119,7 +120,7 @@ DeriveDefault::visit_tuple (TupleStruct &tuple_item) for (auto &field : tuple_item.get_fields ()) { - auto type = field.get_field_type ().clone_type (); + auto type = field.get_field_type ().reconstruct (); defaulted_fields.emplace_back (default_call (std::move (type))); } diff --git a/gcc/rust/expand/rust-derive-eq.cc b/gcc/rust/expand/rust-derive-eq.cc index 5e7a894..7da137f 100644 --- a/gcc/rust/expand/rust-derive-eq.cc +++ b/gcc/rust/expand/rust-derive-eq.cc @@ -142,7 +142,7 @@ DeriveEq::visit_tuple (TupleStruct &item) auto types = std::vector<std::unique_ptr<Type>> (); for (auto &field : item.get_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), item.get_identifier ().as_string (), @@ -155,7 +155,7 @@ DeriveEq::visit_struct (StructStruct &item) auto types = std::vector<std::unique_ptr<Type>> (); for (auto &field : item.get_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), item.get_identifier ().as_string (), @@ -175,19 +175,20 @@ DeriveEq::visit_enum (Enum &item) case EnumItem::Kind::Discriminant: // nothing to do as they contain no inner types continue; - case EnumItem::Kind::Tuple: { + case EnumItem::Kind::Tuple: + { auto &tuple = static_cast<EnumItemTuple &> (*variant); for (auto &field : tuple.get_tuple_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); - + types.emplace_back (field.get_field_type ().reconstruct ()); break; } - case EnumItem::Kind::Struct: { + case EnumItem::Kind::Struct: + { auto &tuple = static_cast<EnumItemStruct &> (*variant); for (auto &field : tuple.get_struct_fields ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); break; } @@ -205,7 +206,7 @@ DeriveEq::visit_union (Union &item) auto types = std::vector<std::unique_ptr<Type>> (); for (auto &field : item.get_variants ()) - types.emplace_back (field.get_field_type ().clone_type ()); + types.emplace_back (field.get_field_type ().reconstruct ()); expanded = eq_impls (assert_receiver_is_total_eq_fn (std::move (types)), item.get_identifier ().as_string (), diff --git a/gcc/rust/expand/rust-derive-eq.h b/gcc/rust/expand/rust-derive-eq.h index 17af526..fb187cc 100644 --- a/gcc/rust/expand/rust-derive-eq.h +++ b/gcc/rust/expand/rust-derive-eq.h @@ -31,7 +31,7 @@ class DeriveEq : DeriveVisitor public: DeriveEq (location_t loc); - std::vector<std::unique_ptr<AST::Item>> go (Item &item); + std::vector<std::unique_ptr<Item>> go (Item &item); private: std::vector<std::unique_ptr<Item>> expanded; @@ -70,10 +70,10 @@ private: */ std::unique_ptr<Stmt> assert_type_is_eq (std::unique_ptr<Type> &&type); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-hash.cc b/gcc/rust/expand/rust-derive-hash.cc index 0c9b0f7..94aede2 100644 --- a/gcc/rust/expand/rust-derive-hash.cc +++ b/gcc/rust/expand/rust-derive-hash.cc @@ -231,14 +231,7 @@ DeriveHash::visit_enum (Enum &item) auto cases = std::vector<MatchCase> (); auto type_name = item.get_identifier ().as_string (); - auto intrinsic = ptrify ( - builder.path_in_expression ({"core", "intrinsics", "discriminant_value"}, - true)); - - auto let_discr - = builder.let (builder.identifier_pattern (DeriveHash::discr), nullptr, - builder.call (std::move (intrinsic), - builder.identifier ("self"))); + auto let_discr = builder.discriminant_value (DeriveHash::discr); auto discr_hash = builder.statementify ( hash_call (builder.ref (builder.identifier (DeriveHash::discr)))); diff --git a/gcc/rust/expand/rust-derive-hash.h b/gcc/rust/expand/rust-derive-hash.h index 02b0bee..67170d0 100644 --- a/gcc/rust/expand/rust-derive-hash.h +++ b/gcc/rust/expand/rust-derive-hash.h @@ -29,7 +29,7 @@ class DeriveHash : DeriveVisitor public: DeriveHash (location_t loc); - std::unique_ptr<AST::Item> go (Item &item); + std::unique_ptr<Item> go (Item &item); private: std::unique_ptr<Item> expanded; @@ -49,10 +49,10 @@ private: MatchCase match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive-ord.cc b/gcc/rust/expand/rust-derive-ord.cc new file mode 100644 index 0000000..afc4b71 --- /dev/null +++ b/gcc/rust/expand/rust-derive-ord.cc @@ -0,0 +1,323 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-derive-ord.h" +#include "rust-ast.h" +#include "rust-derive-cmp-common.h" +#include "rust-derive.h" +#include "rust-item.h" +#include "rust-system.h" + +namespace Rust { +namespace AST { + +DeriveOrd::DeriveOrd (Ordering ordering, location_t loc) + : DeriveVisitor (loc), ordering (ordering) +{} + +std::unique_ptr<Item> +DeriveOrd::go (Item &item) +{ + item.accept_vis (*this); + + return std::move (expanded); +} + +std::unique_ptr<Expr> +DeriveOrd::cmp_call (std::unique_ptr<Expr> &&self_expr, + std::unique_ptr<Expr> &&other_expr) +{ + auto cmp_fn_path = builder.path_in_expression ( + {"core", "cmp", trait (ordering), fn (ordering)}, true); + + return builder.call (ptrify (cmp_fn_path), + vec (builder.ref (std::move (self_expr)), + builder.ref (std::move (other_expr)))); +} + +std::unique_ptr<Item> +DeriveOrd::cmp_impl ( + std::unique_ptr<BlockExpr> &&fn_block, Identifier type_name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics) +{ + auto fn = cmp_fn (std::move (fn_block), type_name); + + auto trait = ordering == Ordering::Partial ? "PartialOrd" : "Ord"; + auto trait_path = builder.type_path ({"core", "cmp", trait}, true); + + auto trait_bound + = builder.trait_bound (builder.type_path ({"core", "cmp", trait}, true)); + + auto trait_items = vec (std::move (fn)); + + auto cmp_generics + = setup_impl_generics (type_name.as_string (), type_generics, + std::move (trait_bound)); + + return builder.trait_impl (trait_path, std::move (cmp_generics.self_type), + std::move (trait_items), + std::move (cmp_generics.impl)); +} + +std::unique_ptr<AssociatedItem> +DeriveOrd::cmp_fn (std::unique_ptr<BlockExpr> &&block, Identifier type_name) +{ + // Ordering + auto return_type = builder.type_path ({"core", "cmp", "Ordering"}, true); + + // In the case of PartialOrd, we return an Option<Ordering> + if (ordering == Ordering::Partial) + { + auto generic = GenericArg::create_type (ptrify (return_type)); + + auto generic_seg = builder.type_path_segment_generic ( + "Option", GenericArgs ({}, {generic}, {}, loc)); + auto core = builder.type_path_segment ("core"); + auto option = builder.type_path_segment ("option"); + + return_type + = builder.type_path (vec (std::move (core), std::move (option), + std::move (generic_seg)), + true); + } + + // &self, other: &Self + auto params = vec ( + builder.self_ref_param (), + builder.function_param (builder.identifier_pattern ("other"), + builder.reference_type (ptrify ( + builder.type_path (type_name.as_string ()))))); + + auto function_name = fn (ordering); + + return builder.function (function_name, std::move (params), + ptrify (return_type), std::move (block)); +} + +std::unique_ptr<Pattern> +DeriveOrd::make_equal () +{ + std::unique_ptr<Pattern> equal = ptrify ( + builder.path_in_expression ({"core", "cmp", "Ordering", "Equal"}, true)); + + // We need to wrap the pattern in Option::Some if we are doing partial + // ordering + if (ordering == Ordering::Partial) + { + auto pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (vec (std::move (equal)))); + + equal + = std::make_unique<TupleStructPattern> (builder.path_in_expression ( + LangItem::Kind::OPTION_SOME), + std::move (pattern_items)); + } + + return equal; +} + +std::pair<MatchArm, MatchArm> +DeriveOrd::make_cmp_arms () +{ + // All comparison results other than Ordering::Equal + auto non_equal = builder.identifier_pattern (DeriveOrd::not_equal); + auto equal = make_equal (); + + return {builder.match_arm (std::move (equal)), + builder.match_arm (std::move (non_equal))}; +} + +std::unique_ptr<Expr> +DeriveOrd::recursive_match (std::vector<SelfOther> &&members) +{ + if (members.empty ()) + { + std::unique_ptr<Expr> value = ptrify ( + builder.path_in_expression ({"core", "cmp", "Ordering", "Equal"}, + true)); + + if (ordering == Ordering::Partial) + value = builder.call (ptrify (builder.path_in_expression ( + LangItem::Kind::OPTION_SOME)), + std::move (value)); + + return value; + } + + std::unique_ptr<Expr> final_expr = nullptr; + + for (auto it = members.rbegin (); it != members.rend (); it++) + { + auto &member = *it; + + auto call = cmp_call (std::move (member.self_expr), + std::move (member.other_expr)); + + // For the last member (so the first iterator), we just create a call + // expression + if (it == members.rbegin ()) + { + final_expr = std::move (call); + continue; + } + + // If we aren't dealing with the last member, then we need to wrap all of + // that in a big match expression and keep going + auto match_arms = make_cmp_arms (); + + auto match_cases + = {builder.match_case (std::move (match_arms.first), + std::move (final_expr)), + builder.match_case (std::move (match_arms.second), + builder.identifier (DeriveOrd::not_equal))}; + + final_expr = builder.match (std::move (call), std::move (match_cases)); + } + + return final_expr; +} + +// we need to do a recursive match expression for all of the fields used in a +// struct so for something like struct Foo { a: i32, b: i32, c: i32 } we must +// first compare each `a` field, then `b`, then `c`, like this: +// +// match cmp_fn(self.<field>, other.<field>) { +// Ordering::Equal => <recurse>, +// cmp => cmp, +// } +// +// and the recurse will be the exact same expression, on the next field. so that +// our result looks like this: +// +// match cmp_fn(self.a, other.a) { +// Ordering::Equal => match cmp_fn(self.b, other.b) { +// Ordering::Equal =>cmp_fn(self.c, other.c), +// cmp => cmp, +// } +// cmp => cmp, +// } +// +// the last field comparison needs not to be a match but just the function call. +// this is going to be annoying lol +void +DeriveOrd::visit_struct (StructStruct &item) +{ + auto fields = SelfOther::fields (builder, item.get_fields ()); + + auto match_expr = recursive_match (std::move (fields)); + + expanded = cmp_impl (builder.block (std::move (match_expr)), + item.get_identifier (), item.get_generic_params ()); +} + +// same as structs, but for each field index instead of each field name - +// straightforward once we have `visit_struct` working +void +DeriveOrd::visit_tuple (TupleStruct &item) +{ + auto fields = SelfOther::indexes (builder, item.get_fields ()); + + auto match_expr = recursive_match (std::move (fields)); + + expanded = cmp_impl (builder.block (std::move (match_expr)), + item.get_identifier (), item.get_generic_params ()); +} + +// for enums, we need to generate a match for each of the enum's variant that +// contains data and then do the same thing as visit_struct or visit_enum. if +// the two aren't the same variant, then compare the two discriminant values for +// all the dataless enum variants and in the general case. +// +// so for enum Foo { A(i32, i32), B, C } we need to do the following +// +// match (self, other) { +// (A(self_0, self_1), A(other_0, other_1)) => { +// match cmp_fn(self_0, other_0) { +// Ordering::Equal => cmp_fn(self_1, other_1), +// cmp => cmp, +// }, +// _ => cmp_fn(discr_value(self), discr_value(other)) +// } +void +DeriveOrd::visit_enum (Enum &item) +{ + // NOTE: We can factor this even further with DerivePartialEq, but this is + // getting out of scope for this PR surely + + auto cases = std::vector<MatchCase> (); + auto type_name = item.get_identifier ().as_string (); + + auto let_sd = builder.discriminant_value (DeriveOrd::self_discr, "self"); + auto let_od = builder.discriminant_value (DeriveOrd::other_discr, "other"); + + auto discr_cmp = cmp_call (builder.identifier (DeriveOrd::self_discr), + builder.identifier (DeriveOrd::other_discr)); + + auto recursive_match_fn = [this] (std::vector<SelfOther> &&fields) { + return recursive_match (std::move (fields)); + }; + + for (auto &variant : item.get_variants ()) + { + auto enum_builder + = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (), + recursive_match_fn, builder); + + switch (variant->get_enum_item_kind ()) + { + case EnumItem::Kind::Struct: + cases.emplace_back (enum_builder.strukt (*variant)); + break; + case EnumItem::Kind::Tuple: + cases.emplace_back (enum_builder.tuple (*variant)); + break; + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // We don't need to do anything for these, as they are handled by the + // discriminant value comparison + break; + } + } + + // Add the last case which compares the discriminant values in case `self` and + // `other` are actually different variants of the enum + cases.emplace_back ( + builder.match_case (builder.wildcard (), std::move (discr_cmp))); + + auto match + = builder.match (builder.tuple (vec (builder.identifier ("self"), + builder.identifier ("other"))), + std::move (cases)); + + expanded + = cmp_impl (builder.block (vec (std::move (let_sd), std::move (let_od)), + std::move (match)), + type_name, item.get_generic_params ()); +} + +void +DeriveOrd::visit_union (Union &item) +{ + auto trait_name = trait (ordering); + + rust_error_at (item.get_locus (), "derive(%s) cannot be used on unions", + trait_name.c_str ()); +} + +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-derive-ord.h b/gcc/rust/expand/rust-derive-ord.h new file mode 100644 index 0000000..90ce9c8 --- /dev/null +++ b/gcc/rust/expand/rust-derive-ord.h @@ -0,0 +1,122 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_DERIVE_ORD_H +#define RUST_DERIVE_ORD_H + +#include "rust-ast.h" +#include "rust-derive-cmp-common.h" +#include "rust-derive.h" + +namespace Rust { +namespace AST { + +/** + * DeriveOrd is a bit special as the expansion of both `PartialOrd` and `Ord` + * is extremely similar. The only difference is that `PartialOrd` concerns + * partial-ordering, and thus its main method returns an `Option<Ordering>`, + * while `Ord` concerns total-ordering, and its main method returns an + * `Ordering`. Otherwise, the expansion logic is the same, so we factor both + * derives into one. + */ +class DeriveOrd : public DeriveVisitor +{ +public: + enum class Ordering + { + Total, + Partial + }; + + std::string fn (Ordering ordering) + { + if (ordering == Ordering::Total) + return "cmp"; + else + return "partial_cmp"; + } + + std::string trait (Ordering ordering) + { + if (ordering == Ordering::Total) + return "Ord"; + else + return "PartialOrd"; + } + + DeriveOrd (Ordering ordering, location_t loc); + + std::unique_ptr<Item> go (Item &item); + +private: + std::unique_ptr<Item> expanded; + + Ordering ordering; + + /* Identifier patterns for the non-equal match arms */ + constexpr static const char *not_equal = "#non_eq"; + constexpr static const char *self_discr = "#self_discr"; + constexpr static const char *other_discr = "#other_discr"; + + /** + * Create the recursive matching structure used when implementing the + * comparison function on multiple sub items (fields, tuple indexes...) + */ + std::unique_ptr<Expr> recursive_match (std::vector<SelfOther> &&members); + + /** + * Create a pattern for the `Ordering::Equal` case. In the case of partial + * ordering, `Option::Some(Ordering::Equal)`. + */ + std::unique_ptr<Pattern> make_equal (); + + /** + * Make the match arms for one inner match in a comparison function block. + * This returns the "equal" match arm and the "rest" match arm, so something + * like `Ordering::Equal` and `non_eq` in the following match expression: + * + * match cmp(...) { + * Ordering::Equal => match cmp(...) { ... } + * non_eq => non_eq, + * } + */ + std::pair<MatchArm, MatchArm> make_cmp_arms (); + + /** + * Generate a call to the proper trait function, based on the ordering, in + * order to compare two given expressions + */ + std::unique_ptr<Expr> cmp_call (std::unique_ptr<Expr> &&self_expr, + std::unique_ptr<Expr> &&other_expr); + + std::unique_ptr<Item> + cmp_impl (std::unique_ptr<BlockExpr> &&fn_block, Identifier type_name, + const std::vector<std::unique_ptr<GenericParam>> &type_generics); + std::unique_ptr<AssociatedItem> cmp_fn (std::unique_ptr<BlockExpr> &&block, + Identifier type_name); + + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; +}; + +} // namespace AST +} // namespace Rust + +#endif // ! RUST_DERIVE_ORD_H diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc b/gcc/rust/expand/rust-derive-partial-eq.cc index ff66faa..a0bf87a 100644 --- a/gcc/rust/expand/rust-derive-partial-eq.cc +++ b/gcc/rust/expand/rust-derive-partial-eq.cc @@ -64,11 +64,9 @@ DerivePartialEq::partialeq_impls ( } std::unique_ptr<AssociatedItem> -DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression, +DerivePartialEq::eq_fn (std::unique_ptr<BlockExpr> &&block, std::string type_name) { - auto block = builder.block (tl::nullopt, std::move (cmp_expression)); - auto self_type = std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self"))); @@ -83,24 +81,6 @@ DerivePartialEq::eq_fn (std::unique_ptr<Expr> &&cmp_expression, std::move (block)); } -DerivePartialEq::SelfOther -DerivePartialEq::tuple_indexes (int idx) -{ - return SelfOther{ - builder.tuple_idx ("self", idx), - builder.tuple_idx ("other", idx), - }; -} - -DerivePartialEq::SelfOther -DerivePartialEq::field_acccesses (const std::string &field_name) -{ - return SelfOther{ - builder.field_access (builder.identifier ("self"), field_name), - builder.field_access (builder.identifier ("other"), field_name), - }; -} - std::unique_ptr<Expr> DerivePartialEq::build_eq_expression ( std::vector<SelfOther> &&field_expressions) @@ -134,12 +114,10 @@ void DerivePartialEq::visit_tuple (TupleStruct &item) { auto type_name = item.get_struct_name ().as_string (); - auto fields = std::vector<SelfOther> (); - - for (size_t idx = 0; idx < item.get_fields ().size (); idx++) - fields.emplace_back (tuple_indexes (idx)); + auto fields = SelfOther::indexes (builder, item.get_fields ()); - auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); @@ -149,13 +127,10 @@ void DerivePartialEq::visit_struct (StructStruct &item) { auto type_name = item.get_struct_name ().as_string (); - auto fields = std::vector<SelfOther> (); + auto fields = SelfOther::fields (builder, item.get_fields ()); - for (auto &field : item.get_fields ()) - fields.emplace_back ( - field_acccesses (field.get_field_name ().as_string ())); - - auto fn = eq_fn (build_eq_expression (std::move (fields)), type_name); + auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); @@ -199,8 +174,6 @@ DerivePartialEq::match_enum_tuple (PathInExpression variant_path, auto self_pattern_str = "__self_" + std::to_string (i); auto other_pattern_str = "__other_" + std::to_string (i); - rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ()); - self_patterns.emplace_back ( builder.identifier_pattern (self_pattern_str)); other_patterns.emplace_back ( @@ -240,15 +213,55 @@ MatchCase DerivePartialEq::match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant) { - // NOTE: We currently do not support compiling struct patterns where an - // identifier is assigned a new pattern, e.g. Bloop { f0: x } - // This is what we should be using to compile PartialEq for enum struct - // variants, as we need to be comparing the field of each instance meaning we - // need to give two different names to two different instances of the same - // field. We cannot just use the field's name like we do when deriving - // `Clone`. - - rust_unreachable (); + auto self_fields = std::vector<std::unique_ptr<StructPatternField>> (); + auto other_fields = std::vector<std::unique_ptr<StructPatternField>> (); + + auto self_other_exprs = std::vector<SelfOther> (); + + for (auto &field : variant.get_struct_fields ()) + { + // The patterns we're creating for each field are `self_<field>` and + // `other_<field>` where `field` is the name of the field. It doesn't + // actually matter what we use, as long as it's ordered, unique, and that + // we can reuse it in the match case's return expression to check that + // they are equal. + + auto field_name = field.get_field_name ().as_string (); + + auto self_pattern_str = "__self_" + field_name; + auto other_pattern_str = "__other_" + field_name; + + self_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (self_pattern_str))); + other_fields.emplace_back (builder.struct_pattern_ident_pattern ( + field_name, builder.identifier_pattern (other_pattern_str))); + + self_other_exprs.emplace_back (SelfOther{ + builder.identifier (self_pattern_str), + builder.identifier (other_pattern_str), + }); + } + + auto self_elts = StructPatternElements (std::move (self_fields)); + auto other_elts = StructPatternElements (std::move (other_fields)); + + auto self_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( + variant_path, loc, std::move (self_elts))), + false, false, loc)); + auto other_pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern ( + variant_path, loc, std::move (other_elts))), + false, false, loc)); + + auto tuple_items = std::make_unique<TuplePatternItemsMultiple> ( + vec (std::move (self_pattern), std::move (other_pattern))); + + auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc); + + auto expr = build_eq_expression (std::move (self_other_exprs)); + + return builder.match_case (std::move (pattern), std::move (expr)); } void @@ -257,46 +270,56 @@ DerivePartialEq::visit_enum (Enum &item) auto cases = std::vector<MatchCase> (); auto type_name = item.get_identifier ().as_string (); + auto eq_expr_fn = [this] (std::vector<SelfOther> &&fields) { + return build_eq_expression (std::move (fields)); + }; + + auto let_sd + = builder.discriminant_value (DerivePartialEq::self_discr, "self"); + auto let_od + = builder.discriminant_value (DerivePartialEq::other_discr, "other"); + + auto discr_cmp + = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr), + builder.identifier ( + DerivePartialEq::other_discr), + ComparisonOperator::EQUAL); + for (auto &variant : item.get_variants ()) { - auto variant_path - = builder.variant_path (type_name, - variant->get_identifier ().as_string ()); + auto enum_builder + = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (), + eq_expr_fn, builder); switch (variant->get_enum_item_kind ()) { - case EnumItem::Kind::Identifier: - case EnumItem::Kind::Discriminant: - cases.emplace_back (match_enum_identifier (variant_path, variant)); - break; case EnumItem::Kind::Tuple: - cases.emplace_back ( - match_enum_tuple (variant_path, - static_cast<EnumItemTuple &> (*variant))); + cases.emplace_back (enum_builder.tuple (*variant)); break; case EnumItem::Kind::Struct: - rust_sorry_at ( - item.get_locus (), - "cannot derive(PartialEq) for enum struct variants yet"); + cases.emplace_back (enum_builder.strukt (*variant)); + break; + case EnumItem::Kind::Identifier: + case EnumItem::Kind::Discriminant: + // We don't need to do anything for these, as they are handled by the + // discriminant value comparison break; } } - // NOTE: Mention using discriminant_value and skipping that last case, and - // instead skipping all identifiers/discriminant enum items and returning - // `true` in the wildcard case - // In case the two instances of `Self` don't have the same discriminant, // automatically return false. cases.emplace_back ( - builder.match_case (builder.wildcard (), builder.literal_bool (false))); + builder.match_case (builder.wildcard (), std::move (discr_cmp))); auto match = builder.match (builder.tuple (vec (builder.identifier ("self"), builder.identifier ("other"))), std::move (cases)); - auto fn = eq_fn (std::move (match), type_name); + auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)), + std::move (match)), + type_name); expanded = partialeq_impls (std::move (fn), type_name, item.get_generic_params ()); diff --git a/gcc/rust/expand/rust-derive-partial-eq.h b/gcc/rust/expand/rust-derive-partial-eq.h index ac963a6..7985414 100644 --- a/gcc/rust/expand/rust-derive-partial-eq.h +++ b/gcc/rust/expand/rust-derive-partial-eq.h @@ -21,6 +21,7 @@ #include "rust-derive.h" #include "rust-path.h" +#include "rust-derive-cmp-common.h" namespace Rust { namespace AST { @@ -30,7 +31,7 @@ class DerivePartialEq : DeriveVisitor public: DerivePartialEq (location_t loc); - std::vector<std::unique_ptr<AST::Item>> go (Item &item); + std::vector<std::unique_ptr<Item>> go (Item &item); private: std::vector<std::unique_ptr<Item>> expanded; @@ -43,23 +44,10 @@ private: std::unique_ptr<AssociatedItem> &&eq_fn, std::string name, const std::vector<std::unique_ptr<GenericParam>> &type_generics); - std::unique_ptr<AssociatedItem> eq_fn (std::unique_ptr<Expr> &&cmp_expression, + std::unique_ptr<AssociatedItem> eq_fn (std::unique_ptr<BlockExpr> &&block, std::string type_name); /** - * A pair of two expressions from each instance being compared. E.g. this - * could be `self.0` and `other.0`, or `self.field` and `other.field` - */ - struct SelfOther - { - std::unique_ptr<Expr> self_expr; - std::unique_ptr<Expr> other_expr; - }; - - SelfOther tuple_indexes (int idx); - SelfOther field_acccesses (const std::string &field_name); - - /** * Build a suite of equality arithmetic expressions chained together by a * boolean AND operator */ @@ -73,10 +61,13 @@ private: MatchCase match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); - virtual void visit_struct (StructStruct &item); - virtual void visit_tuple (TupleStruct &item); - virtual void visit_enum (Enum &item); - virtual void visit_union (Union &item); + constexpr static const char *self_discr = "#self_discr"; + constexpr static const char *other_discr = "#other_discr"; + + virtual void visit_struct (StructStruct &item) override; + virtual void visit_tuple (TupleStruct &item) override; + virtual void visit_enum (Enum &item) override; + virtual void visit_union (Union &item) override; }; } // namespace AST diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc index 015b81e..55147df 100644 --- a/gcc/rust/expand/rust-derive.cc +++ b/gcc/rust/expand/rust-derive.cc @@ -22,6 +22,7 @@ #include "rust-derive-debug.h" #include "rust-derive-default.h" #include "rust-derive-eq.h" +#include "rust-derive-ord.h" #include "rust-derive-partial-eq.h" #include "rust-derive-hash.h" @@ -59,10 +60,11 @@ DeriveVisitor::derive (Item &item, const Attribute &attr, case BuiltinMacro::Hash: return vec (DeriveHash (loc).go (item)); case BuiltinMacro::Ord: + return vec (DeriveOrd (DeriveOrd::Ordering::Total, loc).go (item)); case BuiltinMacro::PartialOrd: + return vec (DeriveOrd (DeriveOrd::Ordering::Partial, loc).go (item)); default: - rust_sorry_at (loc, "unimplemented builtin derive macro"); - return {}; + rust_unreachable (); }; } @@ -79,7 +81,8 @@ DeriveVisitor::setup_impl_generics ( { switch (generic->get_kind ()) { - case GenericParam::Kind::Lifetime: { + case GenericParam::Kind::Lifetime: + { LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get (); Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ()); @@ -91,7 +94,8 @@ DeriveVisitor::setup_impl_generics ( } break; - case GenericParam::Kind::Type: { + case GenericParam::Kind::Type: + { TypeParam &type_param = (TypeParam &) *generic.get (); std::unique_ptr<Type> associated_type = builder.single_type_path ( @@ -104,7 +108,8 @@ DeriveVisitor::setup_impl_generics ( std::vector<std::unique_ptr<TypeParamBound>> extra_bounds; if (extra_bound) - extra_bounds.emplace_back (std::move (*extra_bound)); + extra_bounds.emplace_back ( + extra_bound.value ()->clone_type_param_bound ()); auto impl_type_param = builder.new_type_param (type_param, std::move (extra_bounds)); @@ -113,17 +118,20 @@ DeriveVisitor::setup_impl_generics ( } break; - case GenericParam::Kind::Const: { - rust_unreachable (); + case GenericParam::Kind::Const: + { + ConstGenericParam &const_param + = (ConstGenericParam &) *generic.get (); - // TODO - // const ConstGenericParam *const_param - // = (const ConstGenericParam *) generic.get (); - // std::unique_ptr<Expr> const_expr = nullptr; + std::unique_ptr<Type> associated_type + = builder.single_type_path (const_param.get_name ().as_string ()); - // GenericArg type_arg - // = GenericArg::create_const (std::move (const_expr)); - // generic_args.push_back (std::move (type_arg)); + GenericArg type_arg + = GenericArg::create_type (std::move (associated_type)); + generic_args.push_back (std::move (type_arg)); + + auto impl_const_param = builder.new_const_param (const_param); + impl_generics.push_back (std::move (impl_const_param)); } break; } diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h index 5fca49c..10c146c 100644 --- a/gcc/rust/expand/rust-derive.h +++ b/gcc/rust/expand/rust-derive.h @@ -118,7 +118,7 @@ private: virtual void visit (LiteralExpr &expr) override final{}; virtual void visit (AttrInputLiteral &attr_input) override final{}; virtual void visit (MetaItemLitExpr &meta_item) override final{}; - virtual void visit (MetaItemPathLit &meta_item) override final{}; + virtual void visit (MetaItemPathExpr &meta_item) override final{}; virtual void visit (BorrowExpr &expr) override final{}; virtual void visit (DereferenceExpr &expr) override final{}; virtual void visit (ErrorPropagationExpr &expr) override final{}; @@ -147,6 +147,8 @@ private: virtual void visit (FieldAccessExpr &expr) override final{}; virtual void visit (ClosureExprInner &expr) override final{}; virtual void visit (BlockExpr &expr) override final{}; + virtual void visit (AnonConst &expr) override final{}; + virtual void visit (ConstBlock &expr) override final{}; virtual void visit (ClosureExprInnerTyped &expr) override final{}; virtual void visit (ContinueExpr &expr) override final{}; virtual void visit (BreakExpr &expr) override final{}; @@ -157,6 +159,7 @@ private: virtual void visit (RangeFromToInclExpr &expr) override final{}; virtual void visit (RangeToInclExpr &expr) override final{}; virtual void visit (ReturnExpr &expr) override final{}; + virtual void visit (TryExpr &expr) override final{}; virtual void visit (BoxExpr &expr) override final{}; virtual void visit (UnsafeBlockExpr &expr) override final{}; virtual void visit (LoopExpr &expr) override final{}; @@ -228,6 +231,8 @@ private: virtual void visit (TuplePatternItemsRanged &tuple_items) override final{}; virtual void visit (TuplePattern &pattern) override final{}; virtual void visit (GroupedPattern &pattern) override final{}; + virtual void visit (SlicePatternItemsNoRest &items) override final{}; + virtual void visit (SlicePatternItemsHasRest &items) override final{}; virtual void visit (SlicePattern &pattern) override final{}; virtual void visit (AltPattern &pattern) override final{}; virtual void visit (EmptyStmt &stmt) override final{}; @@ -251,6 +256,7 @@ private: virtual void visit (FunctionParam ¶m) override final{}; virtual void visit (VariadicParam ¶m) override final{}; virtual void visit (FormatArgs ¶m) override final{}; + virtual void visit (OffsetOf ¶m) override final{}; }; } // namespace AST diff --git a/gcc/rust/expand/rust-expand-format-args.cc b/gcc/rust/expand/rust-expand-format-args.cc index af6182f..bda28dd 100644 --- a/gcc/rust/expand/rust-expand-format-args.cc +++ b/gcc/rust/expand/rust-expand-format-args.cc @@ -85,11 +85,13 @@ expand_format_args (AST::FormatArgs &fmt, static_pieces.emplace_back ( builder.literal_string (node.string._0.to_string ())); break; - case ffi::Piece::Tag::NextArgument: { + case ffi::Piece::Tag::NextArgument: + { auto next_argument = node.next_argument._0; switch (node.next_argument._0.position.tag) { - case ffi::Position::Tag::ArgumentImplicitlyIs: { + case ffi::Position::Tag::ArgumentImplicitlyIs: + { auto idx = next_argument.position.argument_implicitly_is._0; auto trait = next_argument.format; auto arg = arguments.at (idx); diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc index 42df5e1..8f6e7fa 100644 --- a/gcc/rust/expand/rust-expand-visitor.cc +++ b/gcc/rust/expand/rust-expand-visitor.cc @@ -233,10 +233,7 @@ ExpandVisitor::expand_inner_items ( } } - std::function<std::unique_ptr<AST::Item> (AST::SingleASTNode)> extractor - = [] (AST::SingleASTNode node) { return node.take_item (); }; - - expand_macro_children (items, extractor); + expand_macro_children (items, &AST::SingleASTNode::take_item); expander.pop_context (); } @@ -324,10 +321,7 @@ ExpandVisitor::expand_inner_stmts (AST::BlockExpr &expr) if (!expr.has_tail_expr ()) expr.normalize_tail_expr (); - std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor - = [] (AST::SingleASTNode node) { return node.take_stmt (); }; - - expand_macro_children (stmts, extractor); + expand_macro_children (stmts, &AST::SingleASTNode::take_stmt); expander.pop_context (); } @@ -544,7 +538,7 @@ ExpandVisitor::visit (AST::MetaItemLitExpr &) {} void -ExpandVisitor::visit (AST::MetaItemPathLit &) +ExpandVisitor::visit (AST::MetaItemPathExpr &) {} void @@ -641,7 +635,7 @@ ExpandVisitor::visit (AST::ClosureExprInnerTyped &expr) maybe_expand_type (expr.get_return_type_ptr ()); - visit (expr.get_definition_block ()); + visit (expr.get_definition_expr ()); } void @@ -866,12 +860,9 @@ ExpandVisitor::visit (AST::Trait &trait) expander.push_context (MacroExpander::ContextType::TRAIT); - std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; - expand_macro_children (MacroExpander::ContextType::TRAIT, - trait.get_trait_items (), extractor); + trait.get_trait_items (), + &AST::SingleASTNode::take_assoc_item); expander.pop_context (); } @@ -894,12 +885,9 @@ ExpandVisitor::visit (AST::InherentImpl &impl) if (impl.has_where_clause ()) expand_where_clause (impl.get_where_clause ()); - std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; - expand_macro_children (MacroExpander::ContextType::IMPL, - impl.get_impl_items (), extractor); + impl.get_impl_items (), + &AST::SingleASTNode::take_assoc_item); } void @@ -922,12 +910,9 @@ ExpandVisitor::visit (AST::TraitImpl &impl) if (impl.has_where_clause ()) expand_where_clause (impl.get_where_clause ()); - std::function<std::unique_ptr<AST::AssociatedItem> (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_assoc_item (); }; - expand_macro_children (MacroExpander::ContextType::TRAIT_IMPL, - impl.get_impl_items (), extractor); + impl.get_impl_items (), + &AST::SingleASTNode::take_assoc_item); } void @@ -944,12 +929,10 @@ void ExpandVisitor::visit (AST::ExternBlock &block) { visit_inner_attrs (block); - std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)> - extractor - = [] (AST::SingleASTNode node) { return node.take_external_item (); }; expand_macro_children (MacroExpander::ContextType::EXTERN, - block.get_extern_items (), extractor); + block.get_extern_items (), + &AST::SingleASTNode::take_external_item); } void diff --git a/gcc/rust/expand/rust-expand-visitor.h b/gcc/rust/expand/rust-expand-visitor.h index ad237c0..845e10c 100644 --- a/gcc/rust/expand/rust-expand-visitor.h +++ b/gcc/rust/expand/rust-expand-visitor.h @@ -28,14 +28,12 @@ namespace Rust { /** * Whether or not an attribute is a derive attribute */ -bool -is_derive (AST::Attribute &attr); +bool is_derive (AST::Attribute &attr); /** * Whether or not an attribute is builtin */ -bool -is_builtin (AST::Attribute &attr); +bool is_builtin (AST::Attribute &attr); class ExpandVisitor : public AST::DefaultASTVisitor { @@ -107,7 +105,7 @@ public: */ template <typename T, typename U> void expand_macro_children (MacroExpander::ContextType ctx, T &values, - std::function<U (AST::SingleASTNode)> extractor) + U (AST::SingleASTNode::*extractor) (void)) { expander.push_context (ctx); @@ -123,7 +121,7 @@ public: */ template <typename T, typename U> void expand_macro_children (T &values, - std::function<U (AST::SingleASTNode)> extractor) + U (AST::SingleASTNode::*extractor) (void)) { for (auto it = values.begin (); it != values.end ();) { @@ -140,7 +138,7 @@ public: it = values.erase (it); for (auto &node : final_fragment.get_nodes ()) { - U new_node = extractor (node); + U new_node = (node.*extractor) (); if (new_node != nullptr) { it = values.insert (it, std::move (new_node)); @@ -211,7 +209,7 @@ public: void visit (AST::AttrInputLiteral &) override; void visit (AST::AttrInputMacro &) override; void visit (AST::MetaItemLitExpr &) override; - void visit (AST::MetaItemPathLit &) override; + void visit (AST::MetaItemPathExpr &) override; void visit (AST::ErrorPropagationExpr &expr) override; void visit (AST::ArithmeticOrLogicalExpr &expr) override; void visit (AST::ComparisonExpr &expr) override; diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc index e255729..61222db 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.cc +++ b/gcc/rust/expand/rust-macro-builtins-asm.cc @@ -25,18 +25,6 @@ #include "rust-parse.h" namespace Rust { -std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{ - {AST::InlineAsmOption::PURE, "pure"}, - {AST::InlineAsmOption::NOMEM, "nomem"}, - {AST::InlineAsmOption::READONLY, "readonly"}, - {AST::InlineAsmOption::PRESERVES_FLAGS, "preserves_flags"}, - {AST::InlineAsmOption::NORETURN, "noreturn"}, - {AST::InlineAsmOption::NOSTACK, "nostack"}, - {AST::InlineAsmOption::MAY_UNWIND, "may_unwind"}, - {AST::InlineAsmOption::ATT_SYNTAX, "att_syntax"}, - {AST::InlineAsmOption::RAW, "raw"}, -}; - std::set<std::string> potentially_nonpromoted_keywords = {"in", "out", "lateout", "inout", "inlateout", "const", "sym", "label"}; @@ -396,6 +384,7 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) { auto &parser = inline_asm_ctx.parser; auto token = parser.peek_current_token (); + location_t locus = token->get_locus (); if (!inline_asm_ctx.is_global_asm () && check_identifier (parser, "inout")) { @@ -413,10 +402,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) // TODO: Is error propogation our top priority, the ? in rust's asm.rs is // doing a lot of work. - // TODO: Not sure how to use parse_expr - if (!check_identifier (parser, "")) - rust_unreachable (); - // auto expr = parse_format_string (inline_asm_ctx); + std::unique_ptr<AST::Expr> in_expr = parser.parse_expr (); + rust_assert (in_expr != nullptr); std::unique_ptr<AST::Expr> out_expr; @@ -426,11 +413,19 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) { // auto result = parse_format_string (inline_asm_ctx); - if (!check_identifier (parser, "")) - rust_unreachable (); - // out_expr = parser.parse_expr(); + out_expr = parser.parse_expr (); + + AST::InlineAsmOperand::SplitInOut splitinout ( + reg, false, std::move (in_expr), std::move (out_expr)); + + inline_asm_ctx.inline_asm.operands.emplace_back (splitinout, + locus); + + return inline_asm_ctx; } + rust_unreachable (); + // TODO: Rembmer to pass in clone_expr() instead of nullptr // https://github.com/rust-lang/rust/blob/a3167859f2fd8ff2241295469876a2b687280bdc/compiler/rustc_builtin_macros/src/asm.rs#L135 // RUST VERSION: ast::InlineAsmOperand::SplitInOut { reg, in_expr: @@ -444,6 +439,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx) } else { + AST::InlineAsmOperand::InOut inout (reg, false, std::move (in_expr)); + inline_asm_ctx.inline_asm.operands.emplace_back (inout, locus); // https://github.com/rust-lang/rust/blob/a3167859f2fd8ff2241295469876a2b687280bdc/compiler/rustc_builtin_macros/src/asm.rs#L137 // RUST VERSION: ast::InlineAsmOperand::InOut { reg, expr, late: false // } @@ -500,7 +497,7 @@ parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx) } void -check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option) +check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsm::Option option) { auto &parser = inline_asm_ctx.parser; auto &inline_asm = inline_asm_ctx.inline_asm; @@ -509,7 +506,7 @@ check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option) // TODO: report an error of duplication rust_error_at (parser.peek_current_token ()->get_locus (), "the %qs option was already provided", - InlineAsmOptionMap[option].c_str ()); + AST::InlineAsm::option_to_string (option).c_str ()); return; } else @@ -536,39 +533,40 @@ parse_options (InlineAsmContext &inline_asm_ctx) { if (!is_global_asm && check_identifier (parser, "pure")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::PURE); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::PURE); } else if (!is_global_asm && check_identifier (parser, "nomem")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::NOMEM); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NOMEM); } else if (!is_global_asm && check_identifier (parser, "readonly")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::READONLY); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::READONLY); } else if (!is_global_asm && check_identifier (parser, "preserves_flags")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::PRESERVES_FLAGS); + check_and_set (inline_asm_ctx, + AST::InlineAsm::Option::PRESERVES_FLAGS); } else if (!is_global_asm && check_identifier (parser, "noreturn")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::NORETURN); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NORETURN); } else if (!is_global_asm && check_identifier (parser, "nostack")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::NOSTACK); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::NOSTACK); } else if (!is_global_asm && check_identifier (parser, "may_unwind")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::MAY_UNWIND); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::MAY_UNWIND); } else if (check_identifier (parser, "att_syntax")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::ATT_SYNTAX); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::ATT_SYNTAX); } else if (check_identifier (parser, "raw")) { - check_and_set (inline_asm_ctx, AST::InlineAsmOption::RAW); + check_and_set (inline_asm_ctx, AST::InlineAsm::Option::RAW); } else { @@ -807,7 +805,8 @@ expand_inline_asm_strings (InlineAsmContext inline_asm_ctx) auto next_argument = piece.next_argument._0; switch (piece.next_argument._0.position.tag) { - case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: { + case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: + { auto idx = next_argument.position.argument_implicitly_is._0; /*auto trait = next_argument.format;*/ /*auto arg = arguments.at (idx);*/ @@ -829,6 +828,11 @@ expand_inline_asm_strings (InlineAsmContext inline_asm_ctx) } break; case Fmt::ffi::Position::Tag::ArgumentIs: + { + auto idx = next_argument.position.argument_is._0; + transformed_template_str += "%" + std::to_string (idx); + break; + } case Fmt::ffi::Position::Tag::ArgumentNamed: rust_sorry_at (inline_asm.get_locus (), "unhandled argument position specifier"); @@ -933,7 +937,9 @@ parse_format_strings (InlineAsmContext inline_asm_ctx) { if (!parser.skip_token (COMMA)) { - break; + rust_error_at (parser.peek_current_token ()->get_locus (), + "expected token %qs", ";"); + return tl::unexpected<InlineAsmParseError> (COMMITTED); } // Ok after the comma is good, we better be parsing correctly // everything in here, which is formatted string in ABNF diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h index bd64a7f..3196a5a 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.h +++ b/gcc/rust/expand/rust-macro-builtins-asm.h @@ -142,16 +142,16 @@ tl::expected<InlineAsmContext, InlineAsmParseError> parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx); WARN_UNUSED_RESULT -tl::optional<AST::Fragment> -parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc, - AST::InvocKind semicolon, AST::AsmKind is_global_asm); +tl::optional<AST::Fragment> parse_asm (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon, + AST::AsmKind is_global_asm); WARN_UNUSED_RESULT -bool -check_identifier (Parser<MacroInvocLexer> &parser, std::string ident); +bool check_identifier (Parser<MacroInvocLexer> &parser, std::string ident); -void -check_and_set (InlineAsmContext &inline_asm_ctx, AST::InlineAsmOption option); +void check_and_set (InlineAsmContext &inline_asm_ctx, + AST::InlineAsm::Option option); // From rustc WARN_UNUSED_RESULT @@ -168,9 +168,9 @@ tl::optional<std::string> parse_format_string (InlineAsmContext &inline_asm_ctx); WARN_UNUSED_RESULT -tl::optional<std::string> -parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id, - InlineAsmContext &inline_asm_ctx); +tl::optional<std::string> parse_label (Parser<MacroInvocLexer> &parser, + TokenId last_token_id, + InlineAsmContext &inline_asm_ctx); // LLVM ASM bits @@ -188,17 +188,13 @@ public: {} }; -void -parse_llvm_outputs (LlvmAsmContext &ctx); +void parse_llvm_outputs (LlvmAsmContext &ctx); -void -parse_llvm_inputs (LlvmAsmContext &ctx); +void parse_llvm_inputs (LlvmAsmContext &ctx); -void -parse_llvm_clobbers (LlvmAsmContext &ctx); +void parse_llvm_clobbers (LlvmAsmContext &ctx); -void -parse_llvm_options (LlvmAsmContext &ctx); +void parse_llvm_options (LlvmAsmContext &ctx); WARN_UNUSED_RESULT tl::optional<AST::Fragment> parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc, diff --git a/gcc/rust/expand/rust-macro-builtins-format-args.cc b/gcc/rust/expand/rust-macro-builtins-format-args.cc index 3e1249d..b20c849 100644 --- a/gcc/rust/expand/rust-macro-builtins-format-args.cc +++ b/gcc/rust/expand/rust-macro-builtins-format-args.cc @@ -52,8 +52,15 @@ format_args_parse_arguments (AST::MacroInvocData &invoc) // TODO: Handle the case where we're not parsing a string literal (macro // invocation for e.g.) - if (parser.peek_current_token ()->get_id () == STRING_LITERAL) - format_expr = parser.parse_literal_expr (); + switch (parser.peek_current_token ()->get_id ()) + { + case STRING_LITERAL: + case RAW_STRING_LITERAL: + format_expr = parser.parse_literal_expr (); + default: + // do nothing + ; + } rust_assert (format_expr); diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.cc b/gcc/rust/expand/rust-macro-builtins-helpers.cc index 864379a..ee01f65 100644 --- a/gcc/rust/expand/rust-macro-builtins-helpers.cc +++ b/gcc/rust/expand/rust-macro-builtins-helpers.cc @@ -68,6 +68,7 @@ make_eager_builtin_invocation ( { auto path_str = make_macro_path_str (kind); + auto token_stream = arguments.to_token_stream (); std::unique_ptr<AST::Expr> node = AST::MacroInvocation::Builtin ( kind, AST::MacroInvocData (AST::SimplePath ( @@ -76,7 +77,7 @@ make_eager_builtin_invocation ( {}, locus, std::move (pending_invocations)); return AST::Fragment ({AST::SingleASTNode (std::move (node))}, - arguments.to_token_stream ()); + std::move (token_stream)); } /* Match the end token of a macro given the start delimiter of the macro */ @@ -110,9 +111,9 @@ std::unique_ptr<AST::LiteralExpr> try_extract_string_literal_from_fragment (const location_t &parent_locus, std::unique_ptr<AST::Expr> &node) { - auto maybe_lit = static_cast<AST::LiteralExpr *> (node.get ()); if (!node || !node->is_literal () - || maybe_lit->get_lit_type () != AST::Literal::STRING) + || static_cast<AST::LiteralExpr &> (*node).get_lit_type () + != AST::Literal::STRING) { rust_error_at (parent_locus, "argument must be a string literal"); if (node) diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.h b/gcc/rust/expand/rust-macro-builtins-helpers.h index 429537e..32cf58f 100644 --- a/gcc/rust/expand/rust-macro-builtins-helpers.h +++ b/gcc/rust/expand/rust-macro-builtins-helpers.h @@ -33,29 +33,23 @@ #include "rust-token.h" namespace Rust { -std::string -make_macro_path_str (BuiltinMacro kind); +std::string make_macro_path_str (BuiltinMacro kind); -std::vector<std::unique_ptr<AST::MacroInvocation>> -check_for_eager_invocations ( +std::vector<std::unique_ptr<AST::MacroInvocation>> check_for_eager_invocations ( std::vector<std::unique_ptr<AST::Expr>> &expressions); // Shorthand function for creating unique_ptr tokens -std::unique_ptr<AST::Token> -make_token (const TokenPtr tok); +std::unique_ptr<AST::Token> make_token (const TokenPtr tok); -std::unique_ptr<AST::Expr> -make_string (location_t locus, std::string value); +std::unique_ptr<AST::Expr> make_string (location_t locus, std::string value); // TODO: Is this correct? -AST::Fragment -make_eager_builtin_invocation ( +AST::Fragment make_eager_builtin_invocation ( BuiltinMacro kind, location_t locus, AST::DelimTokenTree arguments, std::vector<std::unique_ptr<AST::MacroInvocation>> &&pending_invocations); // Match the end token of a macro given the start delimiter of the macro -TokenId -macro_end_token (AST::DelimTokenTree &invoc_token_tree, - Parser<MacroInvocLexer> &parser); +TokenId macro_end_token (AST::DelimTokenTree &invoc_token_tree, + Parser<MacroInvocLexer> &parser); // Expand and then extract a string literal from the macro std::unique_ptr<AST::LiteralExpr> try_extract_string_literal_from_fragment (const location_t &parent_locus, @@ -70,21 +64,18 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser, // and return the LiteralExpr for it. Allow for an optional trailing comma, // but otherwise enforce that these are the only tokens. -std::unique_ptr<AST::Expr> -parse_single_string_literal (BuiltinMacro kind, - AST::DelimTokenTree &invoc_token_tree, - location_t invoc_locus, MacroExpander *expander, - bool is_semicoloned = false); +std::unique_ptr<AST::Expr> parse_single_string_literal ( + BuiltinMacro kind, AST::DelimTokenTree &invoc_token_tree, + location_t invoc_locus, MacroExpander *expander, bool is_semicoloned = false); // Treat PATH as a path relative to the source file currently being // compiled, and return the absolute path for it. -std::string -source_relative_path (std::string path, location_t locus); +std::string source_relative_path (std::string path, location_t locus); // Read the full contents of the file FILENAME and return them in a vector. // FIXME: platform specific. -tl::optional<std::vector<uint8_t>> -load_file_bytes (location_t invoc_locus, const char *filename); +tl::optional<std::vector<uint8_t>> load_file_bytes (location_t invoc_locus, + const char *filename); } // namespace Rust #endif // GCCRS_RUST_MACRO_BUILTINS_HELPERS_H diff --git a/gcc/rust/expand/rust-macro-builtins-offset-of.cc b/gcc/rust/expand/rust-macro-builtins-offset-of.cc new file mode 100644 index 0000000..53efe74 --- /dev/null +++ b/gcc/rust/expand/rust-macro-builtins-offset-of.cc @@ -0,0 +1,78 @@ +// Copyright (C) 2020-2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "optional.h" +#include "rust-ast-fragment.h" +#include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" +#include "rust-diagnostics.h" +#include "rust-macro-builtins-helpers.h" +#include "rust-macro-builtins.h" +#include "rust-macro-invoc-lexer.h" +#include "rust-parse.h" + +namespace Rust { + +tl::optional<AST::Fragment> +MacroBuiltin::offset_of_handler (location_t invoc_locus, + AST::MacroInvocData &invoc, + AST::InvocKind semicolon) +{ + MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); + Parser<MacroInvocLexer> parser (lex); + + auto last_token = macro_end_token (invoc.get_delim_tok_tree (), parser); + + auto type = parser.parse_type (); + + // if we don't see a type, there might be an eager macro expansion missing + // FIXME: handle that + if (!type) + { + rust_error_at (invoc_locus, "could not parse type argument for %qs", + "offset_of"); + + // we skip so we can still parse the field arg and check if it is correct + while (parser.peek_current_token ()->get_id () != COMMA + && parser.peek_current_token ()->get_id () != last_token) + parser.skip_token (); + } + + parser.skip_token (COMMA); + + auto field_tok = parser.parse_identifier_or_keyword_token (); + auto invalid_field = !field_tok || !field_tok->has_str (); + + if (invalid_field) + rust_error_at (invoc_locus, "could not parse field argument for %qs", + "offset_of"); + + if (!type || invalid_field) + return tl::nullopt; + + auto field = Identifier (field_tok->get_str ()); + + // FIXME: Do we need to do anything to handle the optional comma at the end? + parser.maybe_skip_token (COMMA); + + return AST::Fragment ({AST::SingleASTNode (std::make_unique<AST::OffsetOf> ( + std::move (type), field, invoc_locus))}, + invoc.get_delim_tok_tree ().to_token_stream ()); +} + +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index b58ed71..a7ae220 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -162,6 +162,9 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc> {"Ord", MacroBuiltin::proc_macro_builtin}, {"PartialOrd", MacroBuiltin::proc_macro_builtin}, {"Hash", MacroBuiltin::proc_macro_builtin}, + /* offset_of is not declared in Rust 1.49 but still needed for + Rust-for-Linux, so we still create a transcriber and warn the user */ + {"offset_of", MacroBuiltin::offset_of_handler}, }; tl::optional<BuiltinMacro> diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h index 541e956..b6c2907 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -19,6 +19,7 @@ #ifndef RUST_MACRO_BUILTINS_H #define RUST_MACRO_BUILTINS_H +#include "optional.h" #include "rust-ast.h" #include "rust-builtin-ast-nodes.h" #include "rust-ast-fragment.h" @@ -188,6 +189,9 @@ public: format_args_handler (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon, AST::FormatArgs::Newline nl); + static tl::optional<AST::Fragment> + offset_of_handler (location_t, AST::MacroInvocData &, AST::InvocKind); + static tl::optional<AST::Fragment> sorry (location_t invoc_locus, AST::MacroInvocData &invoc, AST::InvocKind semicolon); diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 673b8fb..4c54cef 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -19,6 +19,7 @@ #include "rust-macro-expand.h" #include "optional.h" #include "rust-ast-fragment.h" +#include "rust-macro-builtins.h" #include "rust-macro-substitute-ctx.h" #include "rust-ast-full.h" #include "rust-ast-visitor.h" @@ -287,6 +288,26 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc, // lookup the rules auto rules_def = mappings.lookup_macro_invocation (invoc); + // We special case the `offset_of!()` macro if the flag is here and manually + // resolve to the builtin transcriber we have specified + auto assume_builtin_offset_of + = flag_assume_builtin_offset_of + && (invoc.get_invoc_data ().get_path ().as_string () == "offset_of") + && !rules_def; + + // TODO: This is *massive hack* which should be removed as we progress to + // Rust 1.71 when offset_of gets added to core + if (assume_builtin_offset_of) + { + fragment = MacroBuiltin::offset_of_handler (invoc.get_locus (), + invoc_data, semicolon) + .value_or (AST::Fragment::create_empty ()); + + set_expanded_fragment (std::move (fragment)); + + return; + } + // If there's no rule associated with the invocation, we can simply return // early. The early name resolver will have already emitted an error. if (!rules_def) @@ -430,7 +451,8 @@ MacroExpander::match_fragment (Parser<MacroInvocLexer> &parser, parser.parse_visibility (); break; - case AST::MacroFragSpec::STMT: { + case AST::MacroFragSpec::STMT: + { auto restrictions = ParseRestrictions (); restrictions.consume_semi = false; parser.parse_stmt (restrictions); @@ -480,19 +502,22 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser, // this is used so we can check that we delimit the stream correctly. switch (delimiter->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { if (!check_delim (AST::DelimType::PARENS)) return false; } break; - case LEFT_SQUARE: { + case LEFT_SQUARE: + { if (!check_delim (AST::DelimType::SQUARE)) return false; } break; - case LEFT_CURLY: { + case LEFT_CURLY: + { if (!check_delim (AST::DelimType::CURLY)) return false; } @@ -510,7 +535,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser, switch (match->get_macro_match_type ()) { - case AST::MacroMatch::MacroMatchType::Fragment: { + case AST::MacroMatch::MacroMatchType::Fragment: + { AST::MacroMatchFragment *fragment = static_cast<AST::MacroMatchFragment *> (match.get ()); if (!match_fragment (parser, *fragment)) @@ -524,14 +550,16 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser, } break; - case AST::MacroMatch::MacroMatchType::Tok: { + case AST::MacroMatch::MacroMatchType::Tok: + { AST::Token *tok = static_cast<AST::Token *> (match.get ()); if (!match_token (parser, *tok)) return false; } break; - case AST::MacroMatch::MacroMatchType::Repetition: { + case AST::MacroMatch::MacroMatchType::Repetition: + { AST::MacroMatchRepetition *rep = static_cast<AST::MacroMatchRepetition *> (match.get ()); if (!match_repetition (parser, *rep)) @@ -539,7 +567,8 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser, } break; - case AST::MacroMatch::MacroMatchType::Matcher: { + case AST::MacroMatch::MacroMatchType::Matcher: + { AST::MacroMatcher *m = static_cast<AST::MacroMatcher *> (match.get ()); expansion_depth++; @@ -556,19 +585,22 @@ MacroExpander::match_matcher (Parser<MacroInvocLexer> &parser, switch (delimiter->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { if (!parser.skip_token (RIGHT_PAREN)) return false; } break; - case LEFT_SQUARE: { + case LEFT_SQUARE: + { if (!parser.skip_token (RIGHT_SQUARE)) return false; } break; - case LEFT_CURLY: { + case LEFT_CURLY: + { if (!parser.skip_token (RIGHT_CURLY)) return false; } @@ -617,7 +649,8 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, size_t offs_begin = source.get_offs (); switch (match->get_macro_match_type ()) { - case AST::MacroMatch::MacroMatchType::Fragment: { + case AST::MacroMatch::MacroMatchType::Fragment: + { AST::MacroMatchFragment *fragment = static_cast<AST::MacroMatchFragment *> (match.get ()); valid_current_match = match_fragment (parser, *fragment); @@ -632,20 +665,23 @@ MacroExpander::match_n_matches (Parser<MacroInvocLexer> &parser, } break; - case AST::MacroMatch::MacroMatchType::Tok: { + case AST::MacroMatch::MacroMatchType::Tok: + { AST::Token *tok = static_cast<AST::Token *> (match.get ()); valid_current_match = match_token (parser, *tok); } break; - case AST::MacroMatch::MacroMatchType::Repetition: { + case AST::MacroMatch::MacroMatchType::Repetition: + { AST::MacroMatchRepetition *rep = static_cast<AST::MacroMatchRepetition *> (match.get ()); valid_current_match = match_repetition (parser, *rep); } break; - case AST::MacroMatch::MacroMatchType::Matcher: { + case AST::MacroMatch::MacroMatchType::Matcher: + { AST::MacroMatcher *m = static_cast<AST::MacroMatcher *> (match.get ()); valid_current_match = match_matcher (parser, *m, true); diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc index 02e4e3b..ac36ed8 100644 --- a/gcc/rust/expand/rust-macro-substitute-ctx.cc +++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc @@ -273,7 +273,8 @@ SubstituteCtx::substitute_token (size_t token_idx) // don't substitute, dollar sign is alone/metavar is unknown return {std::vector<std::unique_ptr<AST::Token>> (), 0}; - case LEFT_PAREN: { + case LEFT_PAREN: + { // We need to parse up until the closing delimiter and expand this // fragment->n times. rust_debug ("expanding repetition"); diff --git a/gcc/rust/expand/rust-proc-macro.h b/gcc/rust/expand/rust-proc-macro.h index 6ffaaf6..058c93a 100644 --- a/gcc/rust/expand/rust-proc-macro.h +++ b/gcc/rust/expand/rust-proc-macro.h @@ -82,11 +82,9 @@ public: * * @param The path to the shared object file to load. */ -const std::vector<ProcMacro::Procmacro> -load_macros (std::string path); +const std::vector<ProcMacro::Procmacro> load_macros (std::string path); -std::string -generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id); +std::string generate_proc_macro_decls_symbol (std::uint32_t stable_crate_id); } // namespace Rust diff --git a/gcc/rust/expand/rust-token-tree-desugar.cc b/gcc/rust/expand/rust-token-tree-desugar.cc index 3b47180..aa20d50 100644 --- a/gcc/rust/expand/rust-token-tree-desugar.cc +++ b/gcc/rust/expand/rust-token-tree-desugar.cc @@ -68,5 +68,5 @@ TokenTreeDesugar::visit (Token &tts) } } -}; // namespace AST -}; // namespace Rust +} // namespace AST +} // namespace Rust diff --git a/gcc/rust/expand/rust-token-tree-desugar.h b/gcc/rust/expand/rust-token-tree-desugar.h index ccba53b..da9d732 100644 --- a/gcc/rust/expand/rust-token-tree-desugar.h +++ b/gcc/rust/expand/rust-token-tree-desugar.h @@ -49,7 +49,7 @@ private: virtual void visit (Token &tts) override; }; -}; // namespace AST -}; // namespace Rust +} // namespace AST +} // namespace Rust #endif //! RUST_TOKEN_TREE_DESUGAR_H diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index 2d9a445..b723f59 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -47,6 +47,27 @@ ASTLoweringBase::visit (AST::ErrorPropagationExpr &expr) } void +ASTLoweringBase::visit (AST::TryExpr &expr) +{ + rust_fatal_error (expr.get_locus (), "missing desugar for try-blocks"); + rust_unreachable (); +} + +void +ASTLoweringBase::visit (AST::ForLoopExpr &expr) +{ + rust_fatal_error (expr.get_locus (), "missing desugar for for-loops"); + rust_unreachable (); +} + +void +ASTLoweringBase::visit (AST::WhileLetLoopExpr &expr) +{ + rust_fatal_error (expr.get_locus (), "missing desugar for while-let loops"); + rust_unreachable (); +} + +void ASTLoweringBase::visit (AST::Token &) {} void @@ -115,7 +136,7 @@ void ASTLoweringBase::visit (AST::MetaItemLitExpr &) {} void -ASTLoweringBase::visit (AST::MetaItemPathLit &) +ASTLoweringBase::visit (AST::MetaItemPathExpr &) {} void ASTLoweringBase::visit (AST::BorrowExpr &) @@ -201,6 +222,12 @@ void ASTLoweringBase::visit (AST::BlockExpr &) {} void +ASTLoweringBase::visit (AST::AnonConst &) +{} +void +ASTLoweringBase::visit (AST::ConstBlock &) +{} +void ASTLoweringBase::visit (AST::ClosureExprInnerTyped &) {} void @@ -245,12 +272,6 @@ void ASTLoweringBase::visit (AST::WhileLoopExpr &) {} void -ASTLoweringBase::visit (AST::WhileLetLoopExpr &) -{} -void -ASTLoweringBase::visit (AST::ForLoopExpr &) -{} -void ASTLoweringBase::visit (AST::IfExpr &) {} void @@ -474,6 +495,12 @@ void ASTLoweringBase::visit (AST::GroupedPattern &) {} void +ASTLoweringBase::visit (AST::SlicePatternItemsNoRest &) +{} +void +ASTLoweringBase::visit (AST::SlicePatternItemsHasRest &) +{} +void ASTLoweringBase::visit (AST::SlicePattern &) {} void @@ -551,6 +578,10 @@ void ASTLoweringBase::visit (AST::FormatArgs &fmt) {} +void +ASTLoweringBase::visit (AST::OffsetOf &offset_of) +{} + HIR::Lifetime ASTLoweringBase::lower_lifetime (AST::Lifetime &lifetime, bool default_to_static_lifetime) @@ -648,12 +679,14 @@ ASTLoweringBase::lower_generic_args (AST::GenericArgs &args) { switch (arg.get_kind ()) { - case AST::GenericArg::Kind::Type: { + case AST::GenericArg::Kind::Type: + { auto type = ASTLoweringType::translate (arg.get_type ()); type_args.emplace_back (std::unique_ptr<HIR::Type> (type)); break; } - case AST::GenericArg::Kind::Const: { + case AST::GenericArg::Kind::Const: + { auto expr = ASTLoweringExpr::translate (arg.get_expression ()); const_args.emplace_back ( HIR::ConstGenericArg (std::unique_ptr<HIR::Expr> (expr), @@ -887,7 +920,8 @@ ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) std::unique_ptr<HIR::RangePatternBound> hir_bound = nullptr; switch (bound.get_bound_type ()) { - case AST::RangePatternBound::RangePatternBoundType::LITERAL: { + case AST::RangePatternBound::RangePatternBoundType::LITERAL: + { AST::RangePatternBoundLiteral &ref = static_cast<AST::RangePatternBoundLiteral &> (bound); @@ -898,7 +932,8 @@ ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) ref.get_has_minus ())); } break; - case AST::RangePatternBound::RangePatternBoundType::PATH: { + case AST::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast<AST::RangePatternBoundPath &> (bound); HIR::PathInExpression *path @@ -908,7 +943,8 @@ ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound &bound) new HIR::RangePatternBoundPath (*path)); } break; - case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast<AST::RangePatternBoundQualPath &> (bound); HIR::QualifiedPathInExpression *qualpath diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 3116181..e86aacb 100644 --- a/gcc/rust/hir/rust-ast-lower-base.h +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -20,6 +20,8 @@ #define RUST_AST_LOWER_BASE #include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" +#include "rust-expr.h" #include "rust-system.h" #include "rust-ast-full.h" #include "rust-ast-visitor.h" @@ -63,6 +65,9 @@ public: // Special casing nodes that should never reach the HIR lowering stage virtual void visit (AST::MacroInvocation &) override final; virtual void visit (AST::ErrorPropagationExpr &) override final; + virtual void visit (AST::ForLoopExpr &) override final; + virtual void visit (AST::TryExpr &) override final; + virtual void visit (AST::WhileLetLoopExpr &) override final; // visitor impl // rust-ast.h @@ -101,7 +106,7 @@ public: virtual void visit (AST::AttrInputLiteral &attr_input) override; virtual void visit (AST::AttrInputMacro &attr_input) override; virtual void visit (AST::MetaItemLitExpr &meta_item) override; - virtual void visit (AST::MetaItemPathLit &meta_item) override; + virtual void visit (AST::MetaItemPathExpr &meta_item) override; virtual void visit (AST::BorrowExpr &expr) override; virtual void visit (AST::DereferenceExpr &expr) override; virtual void visit (AST::NegationExpr &expr) override; @@ -131,6 +136,8 @@ public: virtual void visit (AST::FieldAccessExpr &expr) override; virtual void visit (AST::ClosureExprInner &expr) override; virtual void visit (AST::BlockExpr &expr) override; + virtual void visit (AST::AnonConst &expr) override; + virtual void visit (AST::ConstBlock &expr) override; virtual void visit (AST::ClosureExprInnerTyped &expr) override; virtual void visit (AST::ContinueExpr &expr) override; virtual void visit (AST::BreakExpr &expr) override; @@ -145,8 +152,6 @@ public: virtual void visit (AST::UnsafeBlockExpr &expr) override; virtual void visit (AST::LoopExpr &expr) override; virtual void visit (AST::WhileLoopExpr &expr) override; - virtual void visit (AST::WhileLetLoopExpr &expr) override; - virtual void visit (AST::ForLoopExpr &expr) override; virtual void visit (AST::IfExpr &expr) override; virtual void visit (AST::IfExprConseqElse &expr) override; virtual void visit (AST::IfLetExpr &expr) override; @@ -231,6 +236,8 @@ public: virtual void visit (AST::TuplePatternItemsRanged &tuple_items) override; virtual void visit (AST::TuplePattern &pattern) override; virtual void visit (AST::GroupedPattern &pattern) override; + virtual void visit (AST::SlicePatternItemsNoRest &items) override; + virtual void visit (AST::SlicePatternItemsHasRest &items) override; virtual void visit (AST::SlicePattern &pattern) override; virtual void visit (AST::AltPattern &pattern) override; @@ -259,6 +266,7 @@ public: virtual void visit (AST::SelfParam ¶m) override; virtual void visit (AST::FormatArgs &fmt) override; + virtual void visit (AST::OffsetOf &offset_of) override; protected: ASTLoweringBase () diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h index 93cd443..f10039b 100644 --- a/gcc/rust/hir/rust-ast-lower-block.h +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -213,8 +213,6 @@ public: void visit (AST::WhileLoopExpr &expr) override; - void visit (AST::ForLoopExpr &expr) override; - void visit (AST::MatchExpr &expr) override; private: diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc index 07d0c835..4ed51d9 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -24,7 +24,9 @@ #include "rust-ast-lower-pattern.h" #include "rust-ast-lower-type.h" #include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" #include "rust-diagnostics.h" +#include "rust-hir-map.h" #include "rust-system.h" #include "tree/rust-hir-expr.h" @@ -127,6 +129,50 @@ ASTLoweringExpr::visit (AST::BlockExpr &expr) } void +ASTLoweringExpr::visit (AST::AnonConst &expr) +{ + auto &mappings = Analysis::Mappings::get (); + auto crate_num = mappings.get_current_crate (); + auto mapping = Analysis::NodeMapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + if (expr.is_deferred ()) + { + translated = new HIR::AnonConst (std::move (mapping), expr.get_locus ()); + } + else + { + auto inner_expr = ASTLoweringExpr::translate (expr.get_inner_expr ()); + + translated = new HIR::AnonConst (std::move (mapping), + std::unique_ptr<Expr> (inner_expr), + expr.get_locus ()); + } +} + +void +ASTLoweringExpr::visit (AST::ConstBlock &expr) +{ + auto inner_expr = ASTLoweringExpr::translate (expr.get_const_expr ()); + + // we know this will always be an `AnonConst`, or we have an issue. Let's + // assert just to be sure. + rust_assert (inner_expr->get_expression_type () == Expr::ExprType::AnonConst); + auto anon_const = static_cast<AnonConst *> (inner_expr); + + auto &mappings = Analysis::Mappings::get (); + auto crate_num = mappings.get_current_crate (); + auto mapping = Analysis::NodeMapping (crate_num, expr.get_node_id (), + mappings.get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ConstBlock (std::move (mapping), std::move (*anon_const), + expr.get_locus (), expr.get_outer_attrs ()); +} + +void ASTLoweringExpr::visit (AST::UnsafeBlockExpr &expr) { translated = ASTLoweringBlock::translate (expr, &terminated); @@ -589,12 +635,6 @@ ASTLoweringExpr::visit (AST::WhileLoopExpr &expr) } void -ASTLoweringExpr::visit (AST::ForLoopExpr &expr) -{ - rust_unreachable (); -} - -void ASTLoweringExpr::visit (AST::BreakExpr &expr) { tl::optional<HIR::Lifetime> break_label = tl::nullopt; @@ -798,7 +838,7 @@ ASTLoweringExpr::visit (AST::ClosureExprInnerTyped &expr) { HIR::Type *closure_return_type = nullptr; HIR::Expr *closure_expr - = ASTLoweringExpr::translate (expr.get_definition_block ()); + = ASTLoweringExpr::translate (expr.get_definition_expr ()); std::vector<HIR::ClosureParam> closure_params; for (auto ¶m : expr.get_params ()) @@ -841,6 +881,7 @@ translate_operand_out (const AST::InlineAsmOperand &operand) *out_value.expr.get ()))); return out; } + HIR::InlineAsmOperand translate_operand_inout (const AST::InlineAsmOperand &operand) { @@ -851,6 +892,7 @@ translate_operand_inout (const AST::InlineAsmOperand &operand) *inout_value.expr.get ()))); return inout; } + HIR::InlineAsmOperand translate_operand_split_in_out (const AST::InlineAsmOperand &operand) { @@ -863,19 +905,21 @@ translate_operand_split_in_out (const AST::InlineAsmOperand &operand) ASTLoweringExpr::translate (*split_in_out_value.out_expr.get ()))); return split_in_out; } + HIR::InlineAsmOperand translate_operand_const (const AST::InlineAsmOperand &operand) { auto const_value = operand.get_const (); - struct HIR::AnonConst anon_const (const_value.anon_const.id, - std::unique_ptr<Expr> ( - ASTLoweringExpr::translate ( - *const_value.anon_const.expr.get ()))); - struct HIR::InlineAsmOperand::Const cnst - { - anon_const - }; - return cnst; + + auto inner_expr = ASTLoweringExpr::translate (const_value.anon_const); + + // Like `ConstBlock`, we know this should only be an `AnonConst` - let's + // assert to make sure and static cast + rust_assert (inner_expr->get_expression_type () == Expr::ExprType::AnonConst); + + auto anon_const = static_cast<AnonConst *> (inner_expr); + + return HIR::InlineAsmOperand::Const{*anon_const}; } HIR::InlineAsmOperand @@ -1006,5 +1050,20 @@ ASTLoweringExpr::visit (AST::FormatArgs &fmt) "FormatArgs lowering is not implemented yet"); } +void +ASTLoweringExpr::visit (AST::OffsetOf &offset_of) +{ + auto type = std::unique_ptr<Type> ( + ASTLoweringType::translate (offset_of.get_type ())); + + auto crate_num = mappings.get_current_crate (); + Analysis::NodeMapping mapping (crate_num, offset_of.get_node_id (), + mappings.get_next_hir_id (crate_num), + mappings.get_next_localdef_id (crate_num)); + + translated = new HIR::OffsetOf (std::move (type), offset_of.get_field (), + mapping, offset_of.get_locus ()); +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h index adedeb3..4eed4ec 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.h +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -21,6 +21,7 @@ #include "rust-ast-lower-base.h" #include "rust-ast.h" +#include "rust-expr.h" namespace Rust { namespace HIR { @@ -82,6 +83,8 @@ public: void visit (AST::IfLetExpr &expr) override; void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; + void visit (AST::AnonConst &expr) override; + void visit (AST::ConstBlock &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; void visit (AST::PathInExpression &expr) override; void visit (AST::QualifiedPathInExpression &expr) override; @@ -108,7 +111,6 @@ public: void visit (AST::FieldAccessExpr &expr) override; void visit (AST::LoopExpr &expr) override; void visit (AST::WhileLoopExpr &expr) override; - void visit (AST::ForLoopExpr &expr) override; void visit (AST::BreakExpr &expr) override; void visit (AST::ContinueExpr &expr) override; void visit (AST::BorrowExpr &expr) override; @@ -124,8 +126,9 @@ public: void visit (AST::InlineAsm &expr) override; void visit (AST::LlvmInlineAsm &expr) override; - // Extra visitor for FormatArgs nodes + // Extra visitor for builtin macro nodes void visit (AST::FormatArgs &fmt) override; + void visit (AST::OffsetOf &offset_of) override; private: ASTLoweringExpr (); diff --git a/gcc/rust/hir/rust-ast-lower-extern.h b/gcc/rust/hir/rust-ast-lower-extern.h index 0105e38..3dca1b6 100644 --- a/gcc/rust/hir/rust-ast-lower-extern.h +++ b/gcc/rust/hir/rust-ast-lower-extern.h @@ -99,7 +99,7 @@ public: = static_cast<AST::IdentifierPattern &> (param.get_pattern ()); Identifier param_name = param_kind == AST::Pattern::Kind::Identifier ? param_ident.get_ident () - : std::string ("_"); + : Identifier ("_", param.get_locus ()); HIR::Type *param_type = ASTLoweringType::translate (param.get_type ()); diff --git a/gcc/rust/hir/rust-ast-lower-implitem.cc b/gcc/rust/hir/rust-ast-lower-implitem.cc index d815a71..5db11cb 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.cc +++ b/gcc/rust/hir/rust-ast-lower-implitem.cc @@ -138,7 +138,8 @@ ASTLowerImplItem::visit (AST::Function &function) std::unique_ptr<HIR::Type> return_type = function.has_return_type () ? std::unique_ptr<HIR::Type> ( - ASTLoweringType::translate (function.get_return_type ())) + ASTLoweringType::translate (function.get_return_type (), false, + true /* impl trait is allowed here*/)) : nullptr; Defaultness defaultness @@ -274,7 +275,16 @@ ASTLowerTraitItem::visit (AST::Function &func) auto hir_param = HIR::FunctionParam (mapping, std::move (translated_pattern), std::move (translated_type), param.get_locus ()); - function_params.push_back (hir_param); + function_params.push_back (std::move (hir_param)); + } + + if (func.has_self_param ()) + { + // insert mappings for self + // TODO: Is this correct ? Looks fishy + mappings.insert_hir_self_param (&*self_param); + mappings.insert_location (self_param->get_mappings ().get_hirid (), + self_param->get_locus ()); } HIR::TraitFunctionDecl decl (func.get_function_name (), @@ -300,14 +310,6 @@ ASTLowerTraitItem::visit (AST::Function &func) = new HIR::TraitItemFunc (mapping, std::move (decl), std::move (block_expr), func.get_outer_attrs (), func.get_locus ()); translated = trait_item; - if (func.has_self_param ()) - { - // insert mappings for self - // TODO: Is this correct ? Looks fishy - mappings.insert_hir_self_param (&*self_param); - mappings.insert_location (self_param->get_mappings ().get_hirid (), - self_param->get_locus ()); - } // add the mappings for the function params at the end for (auto ¶m : trait_item->get_decl ().get_function_params ()) diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc index f4396b5..4e5a747 100644 --- a/gcc/rust/hir/rust-ast-lower-item.cc +++ b/gcc/rust/hir/rust-ast-lower-item.cc @@ -217,7 +217,7 @@ ASTLoweringItem::visit (AST::StructStruct &struct_decl) field.get_outer_attrs ()); if (struct_field_name_exists (fields, translated_field)) - break; + continue; fields.push_back (std::move (translated_field)); } @@ -367,7 +367,9 @@ ASTLoweringItem::visit (AST::ConstantItem &constant) HIR::Visibility vis = translate_visibility (constant.get_visibility ()); HIR::Type *type = ASTLoweringType::translate (constant.get_type (), true); - HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ()); + HIR::Expr *expr = nullptr; + if (constant.has_expr ()) + expr = ASTLoweringExpr::translate (constant.get_expr ()); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), @@ -411,7 +413,8 @@ ASTLoweringItem::visit (AST::Function &function) std::unique_ptr<HIR::Type> return_type = function.has_return_type () ? std::unique_ptr<HIR::Type> ( - ASTLoweringType::translate (function.get_return_type ())) + ASTLoweringType::translate (function.get_return_type (), false, + true /* impl trait is allowed here*/)) : nullptr; std::vector<HIR::FunctionParam> function_params; @@ -494,7 +497,8 @@ ASTLoweringItem::visit (AST::InherentImpl &impl_block) { switch (generic_param->get_kind ()) { - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { const HIR::TypeParam &t = static_cast<const HIR::TypeParam &> (*generic_param); @@ -651,7 +655,8 @@ ASTLoweringItem::visit (AST::TraitImpl &impl_block) { switch (generic_param->get_kind ()) { - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { const HIR::TypeParam &t = static_cast<const HIR::TypeParam &> (*generic_param); @@ -729,6 +734,25 @@ ASTLoweringItem::visit (AST::MacroRulesDefinition &def) lower_macro_definition (def); } +void +ASTLoweringItem::visit (AST::ExternCrate &extern_crate) +{ + if (extern_crate.references_self ()) + return; + + auto &mappings = Analysis::Mappings::get (); + CrateNum num + = mappings.lookup_crate_name (extern_crate.get_referenced_crate ()) + .value (); + AST::Crate &crate = mappings.get_ast_crate (num); + + auto saved_crate_num = mappings.get_current_crate (); + mappings.set_current_crate (num); + auto lowered = ASTLowering::Resolve (crate); + mappings.insert_hir_crate (std::move (lowered)); + mappings.set_current_crate (saved_crate_num); +} + HIR::SimplePath ASTLoweringSimplePath::translate (const AST::SimplePath &path) { diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h index 4e142ed..dc75057 100644 --- a/gcc/rust/hir/rust-ast-lower-item.h +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -45,6 +45,7 @@ public: void visit (AST::TraitImpl &impl_block) override; void visit (AST::ExternBlock &extern_block) override; void visit (AST::MacroRulesDefinition &rules_def) override; + void visit (AST::ExternCrate &extern_crate) override; private: ASTLoweringItem () : translated (nullptr) {} diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc index b7a4c56..8aabcd8 100644 --- a/gcc/rust/hir/rust-ast-lower-pattern.cc +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -23,7 +23,9 @@ namespace Rust { namespace HIR { -ASTLoweringPattern::ASTLoweringPattern () : translated (nullptr) {} +ASTLoweringPattern::ASTLoweringPattern () + : translated (nullptr), is_let_top_level (false) +{} HIR::Pattern * ASTLoweringPattern::translate (AST::Pattern &pattern, bool is_let_top_level) @@ -49,13 +51,18 @@ ASTLoweringPattern::visit (AST::IdentifierPattern &pattern) mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); - std::unique_ptr<Pattern> to_bind; + std::unique_ptr<Pattern> subpattern; + if (pattern.has_subpattern ()) + { + subpattern = std::unique_ptr<Pattern> ( + ASTLoweringPattern::translate (pattern.get_subpattern ())); + } translated = new HIR::IdentifierPattern (mapping, pattern.get_ident (), pattern.get_locus (), pattern.get_is_ref (), pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm, - std::move (to_bind)); + std::move (subpattern)); } void @@ -74,13 +81,15 @@ ASTLoweringPattern::visit (AST::TupleStructPattern &pattern) auto &items = pattern.get_items (); switch (items.get_item_type ()) { - case AST::TupleStructItems::RANGE: { + case AST::TupleStructItems::RANGE: + { // TODO rust_unreachable (); } break; - case AST::TupleStructItems::NO_RANGE: { + case AST::TupleStructItems::NO_RANGE: + { AST::TupleStructItemsNoRange &items_no_range = static_cast<AST::TupleStructItemsNoRange &> (items); @@ -120,7 +129,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) HIR::StructPatternField *f = nullptr; switch (field->get_item_type ()) { - case AST::StructPatternField::ItemType::TUPLE_PAT: { + case AST::StructPatternField::ItemType::TUPLE_PAT: + { auto &tuple = static_cast<AST::StructPatternFieldTuplePat &> (*field); @@ -140,7 +150,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT_PAT: { + case AST::StructPatternField::ItemType::IDENT_PAT: + { AST::StructPatternFieldIdentPat &ident = static_cast<AST::StructPatternFieldIdentPat &> (*field); @@ -160,7 +171,8 @@ ASTLoweringPattern::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT: { + case AST::StructPatternField::ItemType::IDENT: + { AST::StructPatternFieldIdent &ident = static_cast<AST::StructPatternFieldIdent &> (*field.get ()); @@ -213,7 +225,8 @@ ASTLoweringPattern::visit (AST::TuplePattern &pattern) std::unique_ptr<HIR::TuplePatternItems> items; switch (pattern.get_items ().get_pattern_type ()) { - case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: + { AST::TuplePatternItemsMultiple &ref = static_cast<AST::TuplePatternItemsMultiple &> ( pattern.get_items ()); @@ -221,7 +234,8 @@ ASTLoweringPattern::visit (AST::TuplePattern &pattern) } break; - case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + case AST::TuplePatternItems::TuplePatternItemType::RANGED: + { AST::TuplePatternItemsRanged &ref = static_cast<AST::TuplePatternItemsRanged &> (pattern.get_items ()); items = lower_tuple_pattern_ranged (ref); @@ -309,10 +323,27 @@ void ASTLoweringPattern::visit (AST::SlicePattern &pattern) { std::vector<std::unique_ptr<HIR::Pattern>> items; - for (auto &p : pattern.get_items ()) + + switch (pattern.get_items ().get_pattern_type ()) { - HIR::Pattern *item = ASTLoweringPattern::translate (*p); - items.push_back (std::unique_ptr<HIR::Pattern> (item)); + case AST::SlicePatternItems::SlicePatternItemType::NO_REST: + { + AST::SlicePatternItemsNoRest &ref + = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ()); + for (auto &p : ref.get_patterns ()) + { + HIR::Pattern *item = ASTLoweringPattern::translate (*p); + items.push_back (std::unique_ptr<HIR::Pattern> (item)); + } + } + break; + case AST::SlicePatternItems::SlicePatternItemType::HAS_REST: + { + rust_error_at (pattern.get_locus (), + "lowering of slice patterns with rest elements are not " + "supported yet"); + } + break; } auto crate_num = mappings.get_current_crate (); diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc index a678f18..1841576 100644 --- a/gcc/rust/hir/rust-ast-lower-type.cc +++ b/gcc/rust/hir/rust-ast-lower-type.cc @@ -209,10 +209,17 @@ ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path) path.get_locus ()); } +ASTLoweringType::ASTLoweringType (bool default_to_static_lifetime, + bool impl_trait_allowed) + : ASTLoweringBase (), default_to_static_lifetime (default_to_static_lifetime), + impl_trait_allowed (impl_trait_allowed), translated (nullptr) +{} + HIR::Type * -ASTLoweringType::translate (AST::Type &type, bool default_to_static_lifetime) +ASTLoweringType::translate (AST::Type &type, bool default_to_static_lifetime, + bool impl_trait_allowed) { - ASTLoweringType resolver (default_to_static_lifetime); + ASTLoweringType resolver (default_to_static_lifetime, impl_trait_allowed); type.accept_vis (resolver); rust_assert (resolver.translated != nullptr); @@ -260,7 +267,8 @@ ASTLoweringType::visit (AST::BareFunctionType &fntype) HIR::Type *param_type = ASTLoweringType::translate (param.get_type (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); HIR::MaybeNamedParam p (param.get_name (), kind, std::unique_ptr<HIR::Type> (param_type), @@ -272,7 +280,8 @@ ASTLoweringType::visit (AST::BareFunctionType &fntype) if (fntype.has_return_type ()) { return_type = ASTLoweringType::translate (fntype.get_return_type (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); } auto crate_num = mappings.get_current_crate (); @@ -292,8 +301,8 @@ ASTLoweringType::visit (AST::TupleType &tuple) std::vector<std::unique_ptr<HIR::Type>> elems; for (auto &e : tuple.get_elems ()) { - HIR::Type *t - = ASTLoweringType::translate (*e, default_to_static_lifetime); + HIR::Type *t = ASTLoweringType::translate (*e, default_to_static_lifetime, + impl_trait_allowed); elems.push_back (std::unique_ptr<HIR::Type> (t)); } @@ -323,7 +332,8 @@ ASTLoweringType::visit (AST::ArrayType &type) { HIR::Type *translated_type = ASTLoweringType::translate (type.get_elem_type (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); HIR::Expr *array_size = ASTLoweringExpr::translate (type.get_size_expr ()); auto crate_num = mappings.get_current_crate (); @@ -343,9 +353,9 @@ ASTLoweringType::visit (AST::ReferenceType &type) HIR::Lifetime lifetime = lower_lifetime (type.get_lifetime (), default_to_static_lifetime); - HIR::Type *base_type - = ASTLoweringType::translate (type.get_base_type (), - default_to_static_lifetime); + HIR::Type *base_type = ASTLoweringType::translate (type.get_base_type (), + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -364,7 +374,8 @@ ASTLoweringType::visit (AST::RawPointerType &type) { HIR::Type *base_type = ASTLoweringType::translate (type.get_type_pointed_to (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -384,9 +395,9 @@ ASTLoweringType::visit (AST::RawPointerType &type) void ASTLoweringType::visit (AST::SliceType &type) { - HIR::Type *base_type - = ASTLoweringType::translate (type.get_elem_type (), - default_to_static_lifetime); + HIR::Type *base_type = ASTLoweringType::translate (type.get_elem_type (), + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -463,7 +474,8 @@ void ASTLoweringType::visit (AST::ParenthesisedType &type) { auto *inner = ASTLoweringType::translate (*type.get_type_in_parens (), - default_to_static_lifetime); + default_to_static_lifetime, + impl_trait_allowed); auto crate_num = mappings.get_current_crate (); Analysis::NodeMapping mapping (crate_num, type.get_node_id (), @@ -480,6 +492,9 @@ ASTLoweringType::visit (AST::ParenthesisedType &type) void ASTLoweringType::visit (AST::ImplTraitType &type) { + if (!impl_trait_allowed) + emit_impl_trait_error (type.get_locus ()); + std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds; for (auto &bound : type.get_type_param_bounds ()) { @@ -499,9 +514,12 @@ ASTLoweringType::visit (AST::ImplTraitType &type) void ASTLoweringType::visit (AST::ImplTraitTypeOneBound &type) { + if (!impl_trait_allowed) + emit_impl_trait_error (type.get_locus ()); + std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds; - auto b = ASTLoweringTypeBounds::translate (type.get_trait_bound ()); + auto b = ASTLoweringTypeBounds::translate (*type.get_trait_bound ().get ()); bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (b)); auto crate_num = mappings.get_current_crate (); @@ -513,6 +531,15 @@ ASTLoweringType::visit (AST::ImplTraitTypeOneBound &type) = new HIR::ImplTraitType (mapping, std::move (bounds), type.get_locus ()); } +void +ASTLoweringType::emit_impl_trait_error (location_t locus) +{ + rich_location r (line_table, locus); + rust_error_at (r, ErrorCode::E0562, + "%<impl Trait%> not allowed outside of function and inherent " + "method return types"); +} + HIR::GenericParam * ASTLowerGenericParam::translate (AST::GenericParam ¶m) { @@ -593,7 +620,8 @@ ASTLowerGenericParam::visit (AST::TypeParam ¶m) translated = new HIR::TypeParam (mapping, param.get_type_representation (), param.get_locus (), std::move (type_param_bounds), - std::move (type), param.get_outer_attrs ()); + std::move (type), param.get_outer_attrs (), + param.from_impl_trait ()); } HIR::TypeParamBound * diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 4efaeee..50f543a 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -66,7 +66,8 @@ class ASTLoweringType : public ASTLoweringBase public: static HIR::Type *translate (AST::Type &type, - bool default_to_static_lifetime = false); + bool default_to_static_lifetime = false, + bool impl_trait_allowed = false); void visit (AST::BareFunctionType &fntype) override; void visit (AST::TupleType &tuple) override; @@ -81,19 +82,17 @@ public: void visit (AST::TraitObjectTypeOneBound &type) override; void visit (AST::TraitObjectType &type) override; void visit (AST::ParenthesisedType &type) override; - void visit (AST::ImplTraitType &type) override; void visit (AST::ImplTraitTypeOneBound &type) override; + void emit_impl_trait_error (location_t locus); + private: - ASTLoweringType (bool default_to_static_lifetime) - : ASTLoweringBase (), - default_to_static_lifetime (default_to_static_lifetime), - translated (nullptr) - {} + ASTLoweringType (bool default_to_static_lifetime, bool impl_trait_allowed); /** Used when compiling const and static items. */ bool default_to_static_lifetime; + bool impl_trait_allowed; HIR::Type *translated; }; diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc index 76bd135..e6e327f 100644 --- a/gcc/rust/hir/rust-ast-lower.cc +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -423,12 +423,6 @@ ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) } void -ASTLoweringExprWithBlock::visit (AST::ForLoopExpr &expr) -{ - rust_unreachable (); -} - -void ASTLoweringExprWithBlock::visit (AST::MatchExpr &expr) { HIR::Expr *branch_value diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h index cc74082..0787ddf 100644 --- a/gcc/rust/hir/rust-ast-lower.h +++ b/gcc/rust/hir/rust-ast-lower.h @@ -28,16 +28,14 @@ namespace HIR { /* Checks whether the name of a field already exists. Returns true and produces an error if so. */ -bool -struct_field_name_exists (std::vector<HIR::StructField> &fields, - HIR::StructField &new_field); +bool struct_field_name_exists (std::vector<HIR::StructField> &fields, + HIR::StructField &new_field); /** * Lowers a Visibility from the AST into an HIR Visibility, desugaring it in * the process */ -Visibility -translate_visibility (const AST::Visibility &vis); +Visibility translate_visibility (const AST::Visibility &vis); /** * Main base class used for lowering AST to HIR. diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index cb32f68..a0cdcb2 100644 --- a/gcc/rust/hir/rust-hir-dump.cc +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -92,7 +92,7 @@ Dump::go (HIR::Crate &e) end ("Crate"); } -Dump::Dump (std::ostream &stream) : stream (stream) {} +Dump::Dump (std::ostream &stream) : beg_of_line (false), stream (stream) {} /** * Writes TEXT with a final newline if ENDLINE is true. @@ -1297,6 +1297,31 @@ Dump::visit (BlockExpr &e) } void +Dump::visit (AnonConst &e) +{ + begin ("AnonConst"); + do_expr (e); + + if (e.is_deferred ()) + put_field ("inner", "_"); + else + visit_field ("inner", e.get_inner_expr ()); + + end ("AnonConst"); +} + +void +Dump::visit (ConstBlock &e) +{ + begin ("ConstBlock"); + do_expr (e); + + visit_field ("inner", e.get_const_expr ()); + + end ("ConstBlock"); +} + +void Dump::visit (ContinueExpr &e) { begin ("ContinueExpr"); @@ -1507,13 +1532,91 @@ Dump::visit (AsyncBlockExpr &e) void Dump::visit (InlineAsm &e) -{} +{ + begin ("InlineAsm"); + do_expr (e); + for (auto &temp : e.get_template_ ()) + { + put_field ("template", temp.string); + } + + for (auto &temp_str : e.get_template_strs ()) + { + put_field ("template_str", temp_str.symbol); + } + + for (auto &operand : e.get_operands ()) + { + switch (operand.get_register_type ()) + { + case HIR::InlineAsmOperand::RegisterType::In: + { + const auto &in = operand.get_in (); + visit_field ("in expr", *in.expr); + break; + } + case HIR::InlineAsmOperand::RegisterType::Out: + { + const auto &out = operand.get_out (); + visit_field ("out expr", *out.expr); + break; + } + case HIR::InlineAsmOperand::RegisterType::InOut: + { + const auto &inout = operand.get_in_out (); + visit_field ("inout expr", *inout.expr); + break; + } + case HIR::InlineAsmOperand::RegisterType::SplitInOut: + { + const auto &inout = operand.get_split_in_out (); + begin ("Split in out"); + visit_field ("in expr", *inout.in_expr); + visit_field ("out expr", *inout.out_expr); + end ("Split in out"); + + break; + } + case HIR::InlineAsmOperand::RegisterType::Const: + { + auto &cnst = operand.get_const (); + visit_field ("const expr", cnst.anon_const.get_inner_expr ()); + break; + } + case HIR::InlineAsmOperand::RegisterType::Sym: + { + auto &sym = operand.get_sym (); + visit_field ("sym expr", *sym.expr); + break; + } + case HIR::InlineAsmOperand::RegisterType::Label: + { + auto &label = operand.get_label (); + put_field ("label name", label.label_name); + do_expr (*label.expr); + break; + } + } + } + end ("InlineAsm"); +} void Dump::visit (LlvmInlineAsm &e) {} void +Dump::visit (OffsetOf &e) +{ + begin ("OffsetOf"); + + put_field ("type", e.get_type ().as_string ()); + put_field ("field", e.get_field ()); + + end ("OffsetOf"); +} + +void Dump::visit (TypeParam &e) { begin ("TypeParam"); @@ -1602,7 +1705,8 @@ Dump::visit (UseTreeGlob &e) case UseTreeGlob::PathType::GLOBAL: glob = "::*"; break; - case UseTreeGlob::PathType::PATH_PREFIXED: { + case UseTreeGlob::PathType::PATH_PREFIXED: + { path = e.get_path ().as_string (); glob = "::*"; break; @@ -1630,7 +1734,8 @@ Dump::visit (UseTreeList &e) case UseTreeList::PathType::GLOBAL: path_type = "::*"; break; - case UseTreeList::PathType::PATH_PREFIXED: { + case UseTreeList::PathType::PATH_PREFIXED: + { path = e.get_path ().as_string (); path_type = "::*"; break; @@ -1902,7 +2007,8 @@ Dump::visit (ConstantItem &e) do_vis_item (e); put_field ("identifier", e.get_identifier ().as_string ()); visit_field ("type", e.get_type ()); - visit_field ("const_expr", e.get_expr ()); + if (e.has_expr ()) + visit_field ("const_expr", e.get_expr ()); end ("ConstantItem"); } @@ -2091,10 +2197,10 @@ Dump::visit (IdentifierPattern &e) put_field ("is_ref", std::to_string (e.get_is_ref ())); put_field ("mut", std::to_string (e.is_mut ())); - if (e.has_pattern_to_bind ()) - put_field ("to_bind", e.get_to_bind ().as_string ()); + if (e.has_subpattern ()) + visit_field ("subpattern", e.get_subpattern ()); else - put_field ("to_bind", "none"); + put_field ("subpattern", "none"); end ("IdentifierPattern"); } @@ -2172,7 +2278,7 @@ Dump::visit (StructPatternFieldIdentPat &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); put_field ("ident", e.get_identifier ().as_string ()); - put_field ("ident_pattern", e.get_pattern ().as_string ()); + visit_field ("ident_pattern", e.get_pattern ()); end ("StructPatternFieldIdentPat"); } @@ -2290,7 +2396,7 @@ Dump::visit (LetStmt &e) auto oa = e.get_outer_attrs (); do_outer_attrs (oa); - put_field ("variable_pattern", e.get_pattern ().as_string ()); + visit_field ("variable_pattern", e.get_pattern ()); if (e.has_type ()) visit_field ("type", e.get_type ()); diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h index 45b1708..3e6ae30 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -146,6 +146,8 @@ private: virtual void visit (FieldAccessExpr &) override; virtual void visit (ClosureExpr &) override; virtual void visit (BlockExpr &) override; + virtual void visit (AnonConst &) override; + virtual void visit (ConstBlock &) override; virtual void visit (ContinueExpr &) override; virtual void visit (BreakExpr &) override; virtual void visit (RangeFromToExpr &) override; @@ -167,6 +169,7 @@ private: virtual void visit (AsyncBlockExpr &) override; virtual void visit (InlineAsm &) override; virtual void visit (LlvmInlineAsm &) override; + virtual void visit (OffsetOf &) override; virtual void visit (TypeParam &) override; virtual void visit (ConstGenericParam &) override; @@ -252,7 +255,6 @@ private: } // namespace Rust // In the global namespace to make it easier to call from debugger -void -debug (Rust::HIR::FullVisitable &v); +void debug (Rust::HIR::FullVisitable &v); #endif // !RUST_HIR_DUMP_H diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h index 5bc5d89..371daa8 100644 --- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h +++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h @@ -43,7 +43,7 @@ public: WITHOUT_BLOCK, }; - enum ExprType + enum class ExprType { Lit, Operator, @@ -58,6 +58,8 @@ public: FieldAccess, Closure, Block, + AnonConst, + ConstBlock, Continue, Break, Range, @@ -72,6 +74,7 @@ public: Path, InlineAsm, LlvmInlineAsm, + OffsetOf, }; BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; } diff --git a/gcc/rust/hir/tree/rust-hir-expr.cc b/gcc/rust/hir/tree/rust-hir-expr.cc index 266c79c..14786ad 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.cc +++ b/gcc/rust/hir/tree/rust-hir-expr.cc @@ -17,6 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-expr.h" +#include "rust-hir-map.h" +#include "optional.h" #include "rust-operators.h" #include "rust-hir-stmt.h" @@ -790,6 +792,61 @@ BlockExpr::operator= (BlockExpr const &other) return *this; } +AnonConst::AnonConst (Analysis::NodeMapping mappings, + std::unique_ptr<Expr> &&expr, location_t locus) + : ExprWithBlock (std::move (mappings), {}), locus (locus), + kind (Kind::Explicit), expr (std::move (expr)) +{ + rust_assert (this->expr.value ()); +} + +AnonConst::AnonConst (Analysis::NodeMapping mappings, location_t locus) + : ExprWithBlock (std::move (mappings), {}), locus (locus), + kind (Kind::DeferredInference), expr (tl::nullopt) +{} + +AnonConst::AnonConst (const AnonConst &other) + : ExprWithBlock (other), locus (other.locus), kind (other.kind) +{ + if (other.expr) + expr = other.expr.value ()->clone_expr (); +} + +AnonConst +AnonConst::operator= (const AnonConst &other) +{ + ExprWithBlock::operator= (other); + + locus = other.locus; + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); + + return *this; +} + +ConstBlock::ConstBlock (Analysis::NodeMapping mappings, AnonConst &&expr, + location_t locus, AST::AttrVec outer_attrs) + : ExprWithBlock (std::move (mappings), std::move (outer_attrs)), + expr (std::move (expr)), locus (locus) +{} + +ConstBlock::ConstBlock (const ConstBlock &other) + : ExprWithBlock (other), expr (other.expr), locus (other.locus) +{} + +ConstBlock +ConstBlock::operator= (const ConstBlock &other) +{ + ExprWithBlock::operator= (other); + + expr = other.expr; + locus = other.locus; + + return *this; +} + ContinueExpr::ContinueExpr (Analysis::NodeMapping mappings, location_t locus, tl::optional<Lifetime> label, AST::AttrVec outer_attribs) @@ -1277,59 +1334,42 @@ AsyncBlockExpr::operator= (AsyncBlockExpr const &other) OperatorExprMeta::OperatorExprMeta (HIR::CompoundAssignmentExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), - locus (expr.get_locus ()) + rvalue_mappings (expr.get_rhs ().get_mappings ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::ArithmeticOrLogicalExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), - locus (expr.get_locus ()) + rvalue_mappings (expr.get_rhs ().get_mappings ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::NegationExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), + rvalue_mappings (Analysis::NodeMapping::get_error ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::DereferenceExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), + rvalue_mappings (Analysis::NodeMapping::get_error ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::ArrayIndexExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_array_expr ().get_mappings ()), + rvalue_mappings (expr.get_index_expr ().get_mappings ()), locus (expr.get_locus ()) {} OperatorExprMeta::OperatorExprMeta (HIR::ComparisonExpr &expr) : node_mappings (expr.get_mappings ()), lvalue_mappings (expr.get_expr ().get_mappings ()), - locus (expr.get_locus ()) + rvalue_mappings (expr.get_rhs ().get_mappings ()), locus (expr.get_locus ()) {} -AnonConst::AnonConst (NodeId id, std::unique_ptr<Expr> expr) - : id (id), expr (std::move (expr)) -{ - rust_assert (this->expr != nullptr); -} - -AnonConst::AnonConst (const AnonConst &other) -{ - id = other.id; - expr = other.expr->clone_expr (); -} - -AnonConst -AnonConst::operator= (const AnonConst &other) -{ - id = other.id; - expr = other.expr->clone_expr (); - return *this; -} - InlineAsmOperand::In::In ( const tl::optional<struct AST::InlineAsmRegOrRegClass> ®, std::unique_ptr<Expr> expr) @@ -1476,7 +1516,7 @@ InlineAsm::InlineAsm (location_t locus, bool is_global_asm, std::vector<AST::TupleTemplateStr> template_strs, std::vector<HIR::InlineAsmOperand> operands, std::vector<AST::TupleClobber> clobber_abi, - std::set<AST::InlineAsmOption> options, + std::set<AST::InlineAsm::Option> options, Analysis::NodeMapping mappings, AST::AttrVec outer_attribs) : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs)), @@ -1486,5 +1526,41 @@ InlineAsm::InlineAsm (location_t locus, bool is_global_asm, clobber_abi (std::move (clobber_abi)), options (std::move (options)) {} +OffsetOf & +OffsetOf::operator= (const OffsetOf &other) +{ + ExprWithoutBlock::operator= (other); + + type = other.type->clone_type (); + field = other.field; + loc = other.loc; + + return *this; +} + +ExprWithoutBlock * +OffsetOf::clone_expr_without_block_impl () const +{ + return new OffsetOf (*this); +} + +std::string +OffsetOf::as_string () const +{ + return "OffsetOf(" + type->as_string () + ", " + field.as_string () + ")"; +} + +void +OffsetOf::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void +OffsetOf::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h index 375f474..61e3590 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -19,12 +19,15 @@ #ifndef RUST_HIR_EXPR_H #define RUST_HIR_EXPR_H +#include "rust-ast.h" #include "rust-hir-expr-abstract.h" #include "rust-hir-literal.h" #include "rust-common.h" #include "rust-hir-bound.h" #include "rust-hir-attrs.h" #include "rust-expr.h" +#include "rust-hir-map.h" +#include "rust-mapping-common.h" namespace Rust { namespace HIR { @@ -1800,6 +1803,92 @@ protected: } }; +class AnonConst : public ExprWithBlock +{ +public: + enum class Kind + { + Explicit, + DeferredInference + }; + + AnonConst (Analysis::NodeMapping mappings, std::unique_ptr<Expr> &&expr, + location_t locus = UNKNOWN_LOCATION); + AnonConst (Analysis::NodeMapping mappings, + location_t locus = UNKNOWN_LOCATION); + AnonConst (const AnonConst &other); + AnonConst operator= (const AnonConst &other); + + std::string as_string () const override; + + void accept_vis (HIRFullVisitor &vis) override; + void accept_vis (HIRExpressionVisitor &vis) override; + + ExprType get_expression_type () const final override + { + return ExprType::AnonConst; + } + + location_t get_locus () const override { return locus; } + + Expr &get_inner_expr () + { + rust_assert (kind == Kind::Explicit); + return *expr.value (); + } + + const Expr &get_inner_expr () const + { + rust_assert (kind == Kind::Explicit); + return *expr.value (); + } + + bool is_deferred () const { return kind == Kind::DeferredInference; } + +private: + location_t locus; + Kind kind; + tl::optional<std::unique_ptr<Expr>> expr; + + AnonConst *clone_expr_with_block_impl () const override + { + return new AnonConst (*this); + } +}; + +class ConstBlock : public ExprWithBlock +{ +public: + ConstBlock (Analysis::NodeMapping mappings, AnonConst &&expr, + location_t locus = UNKNOWN_LOCATION, + AST::AttrVec outer_attrs = {}); + ConstBlock (const ConstBlock &other); + ConstBlock operator= (const ConstBlock &other); + + void accept_vis (HIRFullVisitor &vis) override; + void accept_vis (HIRExpressionVisitor &vis) override; + + std::string as_string () const override; + + ExprType get_expression_type () const final override + { + return ExprType::ConstBlock; + } + + location_t get_locus () const override { return locus; } + AnonConst &get_const_expr () { return expr; } + const AnonConst &get_const_expr () const { return expr; } + +private: + AnonConst expr; + location_t locus; + + ConstBlock *clone_expr_with_block_impl () const override + { + return new ConstBlock (*this); + } +}; + // HIR node representing continue expression within loops class ContinueExpr : public ExprWithoutBlock { @@ -2631,6 +2720,8 @@ public: Expr &get_guard_expr () { return *guard_expr; } location_t get_locus () const { return locus; } + + AST::AttrVec &get_outer_attrs () { return outer_attrs; } }; /* A "match case" - a correlated match arm and resulting expression. Not @@ -2823,6 +2914,22 @@ public: OperatorExprMeta (HIR::ComparisonExpr &expr); + OperatorExprMeta (const OperatorExprMeta &other) + : node_mappings (other.node_mappings), + lvalue_mappings (other.lvalue_mappings), + rvalue_mappings (other.rvalue_mappings), locus (other.locus) + {} + + OperatorExprMeta &operator= (const OperatorExprMeta &other) + { + node_mappings = other.node_mappings; + lvalue_mappings = other.lvalue_mappings; + rvalue_mappings = other.rvalue_mappings; + locus = other.locus; + + return *this; + } + const Analysis::NodeMapping &get_mappings () const { return node_mappings; } const Analysis::NodeMapping &get_lvalue_mappings () const @@ -2830,11 +2937,22 @@ public: return lvalue_mappings; } + const Analysis::NodeMapping &get_rvalue_mappings () const + { + return rvalue_mappings; + } + + bool has_rvalue_mappings () const + { + return rvalue_mappings.get_hirid () != UNKNOWN_HIRID; + } + location_t get_locus () const { return locus; } private: - const Analysis::NodeMapping node_mappings; - const Analysis::NodeMapping lvalue_mappings; + Analysis::NodeMapping node_mappings; + Analysis::NodeMapping lvalue_mappings; + Analysis::NodeMapping rvalue_mappings; location_t locus; }; @@ -2892,18 +3010,6 @@ class InlineAsmRegClass std::string placeholder; }; -struct AnonConst -{ - NodeId id; - std::unique_ptr<Expr> expr; - - AnonConst (NodeId id, std::unique_ptr<Expr> expr); - - AnonConst (const AnonConst &other); - - AnonConst operator= (const AnonConst &other); -}; - class InlineAsmOperand { public: @@ -2992,8 +3098,9 @@ public: Label operator= (const struct Label &other); }; -private: using RegisterType = AST::InlineAsmOperand::RegisterType; + +private: AST::InlineAsmOperand::RegisterType register_type; tl::optional<struct In> in; @@ -3037,13 +3144,24 @@ public: RegisterType get_register_type () const { return register_type; } // Potentially unsafe without get_register_type() check - struct In get_in () const { return in.value (); } - struct Out get_out () const { return out.value (); } - struct InOut get_in_out () const { return in_out.value (); } - struct SplitInOut get_split_in_out () const { return split_in_out.value (); } - struct Const get_const () const { return cnst.value (); } - struct Sym get_sym () const { return sym.value (); } - struct Label get_label () const { return label.value (); } + const struct In &get_in () const { return in.value (); } + const struct Out &get_out () const { return out.value (); } + const struct InOut &get_in_out () const { return in_out.value (); } + const struct SplitInOut &get_split_in_out () const + { + return split_in_out.value (); + } + const struct Const &get_const () const { return cnst.value (); } + const struct Sym &get_sym () const { return sym.value (); } + const struct Label &get_label () const { return label.value (); } + + struct In &get_in () { return in.value (); } + struct Out &get_out () { return out.value (); } + struct InOut &get_in_out () { return in_out.value (); } + struct SplitInOut &get_split_in_out () { return split_in_out.value (); } + struct Const &get_const () { return cnst.value (); } + struct Sym &get_sym () { return sym.value (); } + struct Label &get_label () { return label.value (); } }; // Inline Assembly Node @@ -3059,7 +3177,7 @@ public: std::vector<AST::TupleTemplateStr> template_strs; std::vector<HIR::InlineAsmOperand> operands; std::vector<AST::TupleClobber> clobber_abi; - std::set<AST::InlineAsmOption> options; + std::set<AST::InlineAsm::Option> options; std::vector<location_t> line_spans; @@ -3090,11 +3208,11 @@ public: return template_strs; } - std::vector<HIR::InlineAsmOperand> get_operands () { return operands; } + std::vector<HIR::InlineAsmOperand> &get_operands () { return operands; } std::vector<AST::TupleClobber> get_clobber_abi () { return clobber_abi; } - std::set<AST::InlineAsmOption> get_options () { return options; } + std::set<AST::InlineAsm::Option> get_options () { return options; } bool is_simple_asm () { @@ -3113,11 +3231,47 @@ public: std::vector<AST::TupleTemplateStr> template_strs, std::vector<HIR::InlineAsmOperand> operands, std::vector<AST::TupleClobber> clobber_abi, - std::set<AST::InlineAsmOption> options, + std::set<AST::InlineAsm::Option> options, Analysis::NodeMapping mappings, AST::AttrVec outer_attribs = AST::AttrVec ()); }; +class OffsetOf : public ExprWithoutBlock +{ +public: + OffsetOf (std::unique_ptr<Type> &&type, Identifier field, + Analysis::NodeMapping mappings, location_t loc) + : ExprWithoutBlock (mappings), type (std::move (type)), field (field), + loc (loc) + {} + + OffsetOf (const OffsetOf &other) + : ExprWithoutBlock (other), type (other.type->clone_type ()), + field (other.field), loc (other.loc) + {} + + OffsetOf &operator= (const OffsetOf &other); + + ExprWithoutBlock *clone_expr_without_block_impl () const override; + std::string as_string () const override; + + void accept_vis (HIRExpressionVisitor &vis) override; + void accept_vis (HIRFullVisitor &vis) override; + + ExprType get_expression_type () const override { return ExprType::OffsetOf; } + + location_t get_locus () const override { return loc; } + + Type &get_type () { return *type; } + const Type &get_type () const { return *type; } + const Identifier &get_field () const { return field; } + +private: + std::unique_ptr<Type> type; + Identifier field; + location_t loc; +}; + struct LlvmOperand { std::string constraint; diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h index 1e313ec..57b3a4d 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -95,6 +95,8 @@ class FieldAccessExpr; struct ClosureParam; class ClosureExpr; class BlockExpr; +class AnonConst; +class ConstBlock; class ContinueExpr; class BreakExpr; class RangeExpr; @@ -123,10 +125,10 @@ class AwaitExpr; class AsyncBlockExpr; class InlineAsmReg; class InlineAsmRegClass; -struct AnonConst; class InlineAsmOperand; class InlineAsm; class LlvmInlineAsm; +class OffsetOf; // rust-stmt.h class EmptyStmt; diff --git a/gcc/rust/hir/tree/rust-hir-generic-param.h b/gcc/rust/hir/tree/rust-hir-generic-param.h index 960de56..340b5c6 100644 --- a/gcc/rust/hir/tree/rust-hir-generic-param.h +++ b/gcc/rust/hir/tree/rust-hir-generic-param.h @@ -150,7 +150,7 @@ public: location_t get_locus () const override final { return locus; }; - bool has_default_expression () { return default_expression != nullptr; } + bool has_default_expression () const { return default_expression != nullptr; } std::string get_name () { return name; } Type &get_type () @@ -160,6 +160,8 @@ public: } Expr &get_default_expression () { return *default_expression; } + const Expr &get_default_expression () const { return *default_expression; } + protected: /* Use covariance to implement clone function as returning this object rather * than base */ diff --git a/gcc/rust/hir/tree/rust-hir-item.cc b/gcc/rust/hir/tree/rust-hir-item.cc index 160f710..1406e7a 100644 --- a/gcc/rust/hir/tree/rust-hir-item.cc +++ b/gcc/rust/hir/tree/rust-hir-item.cc @@ -26,16 +26,18 @@ TypeParam::TypeParam ( Analysis::NodeMapping mappings, Identifier type_representation, location_t locus, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds, - tl::optional<std::unique_ptr<Type>> type, AST::AttrVec outer_attrs) + tl::optional<std::unique_ptr<Type>> type, AST::AttrVec outer_attrs, + bool was_impl_trait) : GenericParam (mappings), outer_attrs (std::move (outer_attrs)), type_representation (std::move (type_representation)), type_param_bounds (std::move (type_param_bounds)), type (std::move (type)), - locus (locus) + locus (locus), was_impl_trait (was_impl_trait) {} TypeParam::TypeParam (TypeParam const &other) : GenericParam (other.mappings), outer_attrs (other.outer_attrs), - type_representation (other.type_representation), locus (other.locus) + type_representation (other.type_representation), locus (other.locus), + was_impl_trait (other.was_impl_trait) { // guard to prevent null pointer dereference if (other.has_type ()) @@ -55,6 +57,7 @@ TypeParam::operator= (TypeParam const &other) outer_attrs = other.outer_attrs; locus = other.locus; mappings = other.mappings; + was_impl_trait = other.was_impl_trait; // guard to prevent null pointer dereference if (other.has_type ()) diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h index 37f599c..d9df602 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -95,17 +95,11 @@ protected: class TypeParam : public GenericParam { AST::AttrVec outer_attrs; - Identifier type_representation; - - // bool has_type_param_bounds; - // TypeParamBounds type_param_bounds; - std::vector<std::unique_ptr<TypeParamBound>> - type_param_bounds; // inlined form - + std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds; tl::optional<std::unique_ptr<Type>> type; - location_t locus; + bool was_impl_trait; public: // Returns whether the type of the type param has been specified. @@ -121,9 +115,9 @@ public: TypeParam (Analysis::NodeMapping mappings, Identifier type_representation, location_t locus = UNDEF_LOCATION, std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds - = std::vector<std::unique_ptr<TypeParamBound>> (), + = {}, tl::optional<std::unique_ptr<Type>> type = tl::nullopt, - AST::AttrVec outer_attrs = std::vector<AST::Attribute> ()); + AST::AttrVec outer_attrs = {}, bool was_impl_trait = false); // Copy constructor uses clone TypeParam (TypeParam const &other); @@ -154,6 +148,8 @@ public: std::vector<std::unique_ptr<TypeParamBound>> &get_type_param_bounds (); + bool from_impl_trait () const { return was_impl_trait; } + protected: // Clone function implementation as (not pure) virtual method TypeParam *clone_generic_param_impl () const override @@ -213,6 +209,8 @@ public: std::string as_string () const override; + location_t get_locus () const { return locus; } + void accept_vis (HIRFullVisitor &vis) override; Lifetime &get_lifetime () { return lifetime; } @@ -406,6 +404,8 @@ public: const Lifetime &get_lifetime () const { return lifetime.value (); } + Lifetime &get_lifetime () { return lifetime.value (); } + std::string as_string () const; location_t get_locus () const { return locus; } @@ -1801,6 +1801,8 @@ public: return *type; } + bool has_expr () const { return const_expr != nullptr; } + Expr &get_expr () { return *const_expr; } Identifier get_identifier () const { return identifier; } diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index 3ce2662..4f296d8 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -41,11 +41,15 @@ public: : segment_name (std::move (segment_name)) {} - /* TODO: insert check in constructor for this? Or is this a semantic error - * best handled then? */ + PathIdentSegment (const PathIdentSegment &other) + : segment_name (other.segment_name) + {} - /* TODO: does this require visitor? pretty sure this isn't polymorphic, but - * not entirely sure */ + PathIdentSegment &operator= (PathIdentSegment const &other) + { + segment_name = other.segment_name; + return *this; + } // Creates an error PathIdentSegment. static PathIdentSegment create_error () { return PathIdentSegment (""); } @@ -128,6 +132,8 @@ public: std::unique_ptr<Expr> &get_expression () { return expression; } + location_t get_locus () const { return locus; } + private: std::unique_ptr<Expr> expression; location_t locus; @@ -146,7 +152,7 @@ public: bool has_generic_args () const { return !(lifetime_args.empty () && type_args.empty () - && binding_args.empty ()); + && binding_args.empty () && const_args.empty ()); } GenericArgs (std::vector<Lifetime> lifetime_args, diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h b/gcc/rust/hir/tree/rust-hir-pattern.h index 5cc5c95..9c636ca 100644 --- a/gcc/rust/hir/tree/rust-hir-pattern.h +++ b/gcc/rust/hir/tree/rust-hir-pattern.h @@ -80,7 +80,7 @@ class IdentifierPattern : public Pattern Identifier variable_ident; bool is_ref; Mutability mut; - std::unique_ptr<Pattern> to_bind; + std::unique_ptr<Pattern> subpattern; location_t locus; Analysis::NodeMapping mappings; @@ -88,15 +88,15 @@ public: std::string as_string () const override; // Returns whether the IdentifierPattern has a pattern to bind. - bool has_pattern_to_bind () const { return to_bind != nullptr; } + bool has_subpattern () const { return subpattern != nullptr; } // Constructor IdentifierPattern (Analysis::NodeMapping mappings, Identifier ident, location_t locus, bool is_ref = false, Mutability mut = Mutability::Imm, - std::unique_ptr<Pattern> to_bind = nullptr) + std::unique_ptr<Pattern> subpattern = nullptr) : variable_ident (std::move (ident)), is_ref (is_ref), mut (mut), - to_bind (std::move (to_bind)), locus (locus), mappings (mappings) + subpattern (std::move (subpattern)), locus (locus), mappings (mappings) {} // Copy constructor with clone @@ -105,8 +105,8 @@ public: mut (other.mut), locus (other.locus), mappings (other.mappings) { // fix to get prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); } // Overload assignment operator to use clone @@ -119,8 +119,8 @@ public: mappings = other.mappings; // fix to get prevent null pointer dereference - if (other.to_bind != nullptr) - to_bind = other.to_bind->clone_pattern (); + if (other.subpattern != nullptr) + subpattern = other.subpattern->clone_pattern (); return *this; } @@ -133,7 +133,7 @@ public: bool is_mut () const { return mut == Mutability::Mut; } bool get_is_ref () const { return is_ref; } - Pattern &get_to_bind () { return *to_bind; } + Pattern &get_subpattern () { return *subpattern; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRPatternVisitor &vis) override; diff --git a/gcc/rust/hir/tree/rust-hir-visibility.h b/gcc/rust/hir/tree/rust-hir-visibility.h index a750d88..9dd6ff2 100644 --- a/gcc/rust/hir/tree/rust-hir-visibility.h +++ b/gcc/rust/hir/tree/rust-hir-visibility.h @@ -73,6 +73,8 @@ public: } std::string as_string () const; + + location_t get_locus () const { return locus; } }; } // namespace HIR } // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc b/gcc/rust/hir/tree/rust-hir-visitor.cc new file mode 100644 index 0000000..58c1e1a --- /dev/null +++ b/gcc/rust/hir/tree/rust-hir-visitor.cc @@ -0,0 +1,1187 @@ +// Copyright (C) 2021-2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-expr.h" +#include "rust-hir-full-decls.h" +#include "rust-hir-visitor.h" +#include "rust-hir-full.h" +#include "rust-system.h" + +namespace Rust { +namespace HIR { + +void +DefaultHIRVisitor::walk (Lifetime &) +{} + +void +DefaultHIRVisitor::walk (LifetimeParam &lifetime_param) +{ + visit_outer_attrs (lifetime_param); + lifetime_param.get_lifetime ().accept_vis (*this); + for (Lifetime &lifetime_bound : lifetime_param.get_lifetime_bounds ()) + lifetime_bound.accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_generic_args (GenericArgs &generic_args) +{ + for (auto &lifetime : generic_args.get_lifetime_args ()) + lifetime.accept_vis (*this); + for (auto &type : generic_args.get_type_args ()) + type->accept_vis (*this); + for (auto &binding : generic_args.get_binding_args ()) + binding.get_type ().accept_vis (*this); + for (auto &const_arg : generic_args.get_const_args ()) + const_arg.get_expression ()->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (PathInExpression &path_in_expr) +{ + visit_outer_attrs (path_in_expr); + if (!path_in_expr.is_lang_item ()) + for (auto &segment : path_in_expr.get_segments ()) + visit_path_expr_segment (segment); +} + +void +DefaultHIRVisitor::walk (TypePathSegment &) +{} + +void +DefaultHIRVisitor::walk (TypePathSegmentFunction &segment_function) +{ + TypePathFunction &function_path = segment_function.get_function_path (); + if (function_path.has_inputs ()) + for (auto ¶m : function_path.get_params ()) + param->accept_vis (*this); + if (function_path.has_return_type ()) + function_path.get_return_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypePathSegmentGeneric &segment_generic) +{ + if (segment_generic.has_generic_args ()) + visit_generic_args (segment_generic.get_generic_args ()); +} + +void +DefaultHIRVisitor::walk (TypePath &type_path) +{ + for (auto &segment : type_path.get_segments ()) + segment->accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_qualified_path_type (QualifiedPathType &path) +{ + path.get_type ().accept_vis (*this); + if (path.has_as_clause ()) + path.get_trait ().accept_vis (*this); +} + +// TODO: Implement visit_path_expr_segment +void +DefaultHIRVisitor::visit_path_expr_segment (PathExprSegment &segment) +{ + if (segment.has_generic_args ()) + visit_generic_args (segment.get_generic_args ()); +} + +void +DefaultHIRVisitor::walk (QualifiedPathInExpression &path_in_expr) +{ + visit_outer_attrs (path_in_expr); + visit_qualified_path_type (path_in_expr.get_path_type ()); + for (auto &segment : path_in_expr.get_segments ()) + visit_path_expr_segment (segment); +} + +void +DefaultHIRVisitor::walk (QualifiedPathInType &path_in_type) +{ + visit_qualified_path_type (path_in_type.get_path_type ()); + path_in_type.get_associated_segment ().accept_vis (*this); + for (auto &segment : path_in_type.get_segments ()) + segment->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LiteralExpr &expr) +{ + visit_outer_attrs (expr); +} + +void +DefaultHIRVisitor::walk (BorrowExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (DereferenceExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ErrorPropagationExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (NegationExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArithmeticOrLogicalExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ComparisonExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LazyBooleanExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeCastExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_expr ().accept_vis (*this); + expr.get_type_to_convert_to ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AssignmentExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (CompoundAssignmentExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_lhs ().accept_vis (*this); + expr.get_rhs ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (GroupedExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_expr_in_parens ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + elem->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayElemsCopied &elems) +{ + elems.get_elem_to_copy ().accept_vis (*this); + elems.get_num_copies_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_internal_elements ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayIndexExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_array_expr ().accept_vis (*this); + expr.get_index_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + for (auto &elem : expr.get_tuple_elems ()) + elem->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleIndexExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_tuple_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprStruct &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_struct_name ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprFieldIdentifier &) +{} + +void +DefaultHIRVisitor::walk (StructExprFieldIdentifierValue &field) +{ + field.get_value ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprFieldIndexValue &field) +{ + field.get_value ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprStructFields &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_struct_name ().accept_vis (*this); + if (expr.has_struct_base ()) + { + StructBase &base = expr.get_struct_base (); + base.get_base ().accept_vis (*this); + } + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructExprStructBase &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_struct_name ().accept_vis (*this); + StructBase &base = expr.get_struct_base (); + base.get_base ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (CallExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_fnexpr ().accept_vis (*this); + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (MethodCallExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_receiver ().accept_vis (*this); + visit_path_expr_segment (expr.get_method_name ()); + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (FieldAccessExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_receiver_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_closure_param (ClosureParam ¶m) +{ + visit_outer_attrs (param); + param.get_pattern ().accept_vis (*this); + if (param.has_type_given ()) + { + param.get_type ().accept_vis (*this); + } +} + +void +DefaultHIRVisitor::walk (ClosureExpr &expr) +{ + visit_outer_attrs (expr); + for (auto ¶m : expr.get_params ()) + visit_closure_param (param); + if (expr.has_return_type ()) + expr.get_return_type ().accept_vis (*this); + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (BlockExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + if (expr.has_expr ()) + expr.get_final_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AnonConst &expr) +{ + if (!expr.is_deferred ()) + expr.get_inner_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ConstBlock &expr) +{ + expr.get_const_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ContinueExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_label ()) + expr.get_label ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (BreakExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_label ()) + expr.get_label ().accept_vis (*this); + + if (expr.has_break_expr ()) + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeFromToExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeFromExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeToExpr &expr) +{ + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeFullExpr &) +{} + +void +DefaultHIRVisitor::walk (RangeFromToInclExpr &expr) +{ + expr.get_from_expr ().accept_vis (*this); + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangeToInclExpr &expr) +{ + expr.get_to_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ReturnExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_return_expr ()) + expr.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (UnsafeBlockExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_block_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_loop_label (LoopLabel &label) +{ + label.get_lifetime ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LoopExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_loop_label ()) + visit_loop_label (expr.get_loop_label ()); + expr.get_loop_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (WhileLoopExpr &expr) +{ + visit_outer_attrs (expr); + if (expr.has_loop_label ()) + visit_loop_label (expr.get_loop_label ()); + expr.get_predicate_expr ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (WhileLetLoopExpr &expr) +{ + visit_outer_attrs (expr); + for (auto &pattern : expr.get_patterns ()) + pattern->accept_vis (*this); + if (expr.has_loop_label ()) + visit_loop_label (expr.get_loop_label ()); + expr.get_cond ().accept_vis (*this); + expr.get_loop_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (IfExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_if_condition ().accept_vis (*this); + expr.get_if_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (IfExprConseqElse &expr) +{ + expr.IfExpr::accept_vis (*this); + expr.get_else_block ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_match_arm (MatchArm &arm) +{ + // visit_outer_attrs (arm); + for (auto &pattern : arm.get_patterns ()) + pattern->accept_vis (*this); + if (arm.has_match_arm_guard ()) + arm.get_guard_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_match_case (MatchCase &arm) +{ + visit_match_arm (arm.get_arm ()); + arm.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (MatchExpr &expr) +{ + visit_outer_attrs (expr); + visit_inner_attrs (expr); + expr.get_scrutinee_expr ().accept_vis (*this); + for (auto &arm : expr.get_match_cases ()) + visit_match_case (arm); +} + +void +DefaultHIRVisitor::walk (AwaitExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_awaited_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AsyncBlockExpr &expr) +{ + visit_outer_attrs (expr); + expr.get_block_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (InlineAsm &expr) +{ + visit_outer_attrs (expr); + auto &operands = expr.get_operands (); + using RegisterType = AST::InlineAsmOperand::RegisterType; + for (auto &operand : operands) + { + switch (operand.get_register_type ()) + { + case RegisterType::In: + { + operand.get_in ().expr->accept_vis (*this); + break; + } + case RegisterType::Out: + { + operand.get_out ().expr->accept_vis (*this); + break; + } + case RegisterType::InOut: + { + operand.get_in_out ().expr->accept_vis (*this); + break; + } + case RegisterType::SplitInOut: + { + operand.get_split_in_out ().in_expr->accept_vis (*this); + operand.get_split_in_out ().out_expr->accept_vis (*this); + break; + } + case RegisterType::Const: + { + operand.get_const ().anon_const.get_inner_expr ().accept_vis ( + *this); + break; + } + case RegisterType::Sym: + { + operand.get_sym ().expr->accept_vis (*this); + break; + } + case RegisterType::Label: + { + operand.get_label ().expr->accept_vis (*this); + break; + } + } + } +} + +void +DefaultHIRVisitor::walk (LlvmInlineAsm &expr) +{ + for (auto &output : expr.outputs) + output.expr->accept_vis (*this); + for (auto &input : expr.inputs) + input.expr->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (OffsetOf &expr) +{ + expr.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeParam ¶m) +{ + visit_outer_attrs (param); + for (auto &bounds : param.get_type_param_bounds ()) + bounds->accept_vis (*this); + if (param.has_type ()) + param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ConstGenericParam &const_param) +{ + visit_outer_attrs (const_param); + const_param.get_type ().accept_vis (*this); + if (const_param.has_default_expression ()) + const_param.get_default_expression ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LifetimeWhereClauseItem &item) +{ + item.get_lifetime ().accept_vis (*this); + for (auto &bound : item.get_lifetime_bounds ()) + bound.accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeBoundWhereClauseItem &item) +{ + for (auto &lifetime : item.get_for_lifetimes ()) + lifetime.accept_vis (*this); + item.get_bound_type ().accept_vis (*this); + for (auto ¶m : item.get_type_param_bounds ()) + param->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Module &module) +{ + visit_outer_attrs (module); + visit_inner_attrs (module); + for (auto &item : module.get_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExternCrate &crate) +{ + visit_outer_attrs (crate); +} + +void +DefaultHIRVisitor::walk (UseTreeGlob &) +{} + +void +DefaultHIRVisitor::walk (UseTreeList &) +{} + +void +DefaultHIRVisitor::walk (UseTreeRebind &) +{} + +void +DefaultHIRVisitor::walk (UseDeclaration &) +{} + +void +DefaultHIRVisitor::visit_function_param (FunctionParam ¶m) +{ + param.get_param_name ().accept_vis (*this); + param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Function &function) +{ + visit_outer_attrs (function); + for (auto &generic : function.get_generic_params ()) + generic->accept_vis (*this); + for (auto ¶m : function.get_function_params ()) + visit_function_param (param); + if (function.has_return_type ()) + function.get_return_type ().accept_vis (*this); + if (function.has_where_clause ()) + visit_where_clause (function.get_where_clause ()); + function.get_definition ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TypeAlias &type_alias) +{ + visit_outer_attrs (type_alias); + for (auto &generic : type_alias.get_generic_params ()) + generic->accept_vis (*this); + if (type_alias.has_where_clause ()) + visit_where_clause (type_alias.get_where_clause ()); + type_alias.get_type_aliased ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_struct_field (StructField &field) +{ + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructStruct &struct_item) +{ + visit_outer_attrs (struct_item); + for (auto &generic : struct_item.get_generic_params ()) + generic->accept_vis (*this); + if (struct_item.has_where_clause ()) + visit_where_clause (struct_item.get_where_clause ()); + for (auto &field : struct_item.get_fields ()) + visit_struct_field (field); +} + +void +DefaultHIRVisitor::walk (TupleStruct &tuple_struct) +{ + visit_outer_attrs (tuple_struct); + for (auto &generic : tuple_struct.get_generic_params ()) + generic->accept_vis (*this); + if (tuple_struct.has_where_clause ()) + visit_where_clause (tuple_struct.get_where_clause ()); + for (auto &field : tuple_struct.get_fields ()) + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EnumItem &item) +{ + visit_outer_attrs (item); +} + +void +DefaultHIRVisitor::walk (EnumItemTuple &item_tuple) +{ + item_tuple.EnumItem::accept_vis (*this); + for (auto &field : item_tuple.get_tuple_fields ()) + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EnumItemStruct &item_struct) +{ + item_struct.EnumItem::accept_vis (*this); + for (auto &field : item_struct.get_struct_fields ()) + field.get_field_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EnumItemDiscriminant &item) +{ + item.EnumItem::accept_vis (*this); + item.get_discriminant_expression ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Enum &enum_item) +{ + visit_outer_attrs (enum_item); + for (auto &generic : enum_item.get_generic_params ()) + generic->accept_vis (*this); + if (enum_item.has_where_clause ()) + visit_where_clause (enum_item.get_where_clause ()); + for (auto &item : enum_item.get_variants ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (Union &union_item) +{ + visit_outer_attrs (union_item); + for (auto &generic : union_item.get_generic_params ()) + generic->accept_vis (*this); + if (union_item.has_where_clause ()) + visit_where_clause (union_item.get_where_clause ()); + for (auto &variant : union_item.get_variants ()) + visit_struct_field (variant); +} + +void +DefaultHIRVisitor::walk (ConstantItem &const_item) +{ + visit_outer_attrs (const_item); + const_item.get_type ().accept_vis (*this); + const_item.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StaticItem &static_item) +{ + visit_outer_attrs (static_item); + static_item.get_type ().accept_vis (*this); + static_item.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_self_param (SelfParam &self_param) +{ + if (self_param.has_lifetime ()) + { + Lifetime lifetime = self_param.get_lifetime (); + lifetime.accept_vis (*this); + } + if (self_param.has_type ()) + self_param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitItemFunc &item) +{ + visit_outer_attrs (item); + TraitFunctionDecl &decl = item.get_decl (); + for (auto &generic : decl.get_generic_params ()) + generic->accept_vis (*this); + if (decl.get_self ().has_value ()) + visit_self_param (decl.get_self ().value ()); + for (auto ¶m : decl.get_function_params ()) + visit_function_param (param); + if (decl.has_return_type ()) + decl.get_return_type ().accept_vis (*this); + if (decl.has_where_clause ()) + visit_where_clause (decl.get_where_clause ()); + if (item.has_definition ()) + item.get_block_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitItemConst &item) +{ + visit_outer_attrs (item); + item.get_type ().accept_vis (*this); + if (item.has_expr ()) + item.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitItemType &item) +{ + visit_outer_attrs (item); + for (auto &bound : item.get_type_param_bounds ()) + bound->accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_where_clause (const WhereClause &where_clause) +{ + for (auto &item : where_clause.get_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_where_clause (WhereClause &where_clause) +{ + for (auto &item : where_clause.get_items ()) + { + item->accept_vis (*this); + } +} + +void +DefaultHIRVisitor::walk (WhereClauseItem &node) +{} + +void +DefaultHIRVisitor::walk (Trait &trait) +{ + visit_outer_attrs (trait); + for (auto &generic : trait.get_generic_params ()) + generic->accept_vis (*this); + if (trait.has_where_clause ()) + visit_where_clause (trait.get_where_clause ()); + for (auto &bound : trait.get_type_param_bounds ()) + bound->accept_vis (*this); + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ImplBlock &impl) +{ + visit_outer_attrs (impl); + for (auto &generic : impl.get_generic_params ()) + generic->accept_vis (*this); + if (impl.has_trait_ref ()) + impl.get_trait_ref ().accept_vis (*this); + impl.get_type ().accept_vis (*this); + if (impl.has_where_clause ()) + visit_where_clause (impl.get_where_clause ()); + visit_inner_attrs (impl); + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExternalStaticItem &item) +{ + visit_outer_attrs (item); + item.get_item_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::visit_named_function_param (NamedFunctionParam ¶m) +{ + param.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExternalFunctionItem &item) +{ + visit_outer_attrs (item); + for (auto &generic : item.get_generic_params ()) + generic->accept_vis (*this); + for (auto ¶m : item.get_function_params ()) + visit_named_function_param (param); + if (item.has_return_type ()) + item.get_return_type ().accept_vis (*this); + if (item.has_where_clause ()) + visit_where_clause (item.get_where_clause ()); +} + +void +DefaultHIRVisitor::walk (ExternalTypeItem &item) +{ + visit_outer_attrs (item); +} + +void +DefaultHIRVisitor::walk (ExternBlock &block) +{ + visit_outer_attrs (block); + visit_inner_attrs (block); + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (LiteralPattern &) +{} + +void +DefaultHIRVisitor::walk (IdentifierPattern &pattern) +{ + if (pattern.has_subpattern ()) + pattern.get_subpattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (WildcardPattern &) +{} + +void +DefaultHIRVisitor::walk (RangePatternBoundLiteral &) +{} + +void +DefaultHIRVisitor::walk (RangePatternBoundPath &bound) +{ + bound.get_path ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangePatternBoundQualPath &bound) +{ + bound.get_qualified_path ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (RangePattern &pattern) +{ + pattern.get_lower_bound ().accept_vis (*this); + pattern.get_upper_bound ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ReferencePattern &pattern) +{ + pattern.get_referenced_pattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructPatternFieldTuplePat &field) +{ + visit_outer_attrs (field); + field.get_tuple_pattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructPatternFieldIdentPat &field) +{ + visit_outer_attrs (field); + field.get_pattern ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (StructPatternFieldIdent &field) +{ + visit_outer_attrs (field); +} + +void +DefaultHIRVisitor::walk (StructPattern &pattern) +{ + pattern.get_path ().accept_vis (*this); + StructPatternElements &elements = pattern.get_struct_pattern_elems (); + for (auto &field : elements.get_struct_pattern_fields ()) + field->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleStructItemsNoRange &tuple_items) +{ + for (auto &item : tuple_items.get_patterns ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleStructItemsRange &tuple_items) +{ + for (auto &lower : tuple_items.get_lower_patterns ()) + lower->accept_vis (*this); + for (auto &upper : tuple_items.get_upper_patterns ()) + upper->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleStructPattern &pattern) +{ + pattern.get_path ().accept_vis (*this); + pattern.get_items ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TuplePatternItemsMultiple &tuple_items) +{ + for (auto &pattern : tuple_items.get_patterns ()) + pattern->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TuplePatternItemsRanged &tuple_items) +{ + for (auto &lower : tuple_items.get_lower_patterns ()) + lower->accept_vis (*this); + for (auto &upper : tuple_items.get_upper_patterns ()) + upper->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TuplePattern &pattern) +{ + pattern.get_items ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (SlicePattern &pattern) +{ + for (auto &item : pattern.get_items ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (AltPattern &pattern) +{ + for (auto &item : pattern.get_alts ()) + item->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (EmptyStmt &stmt) +{} + +void +DefaultHIRVisitor::walk (LetStmt &stmt) +{ + visit_outer_attrs (stmt); + stmt.get_pattern ().accept_vis (*this); + if (stmt.has_type ()) + stmt.get_type ().accept_vis (*this); + if (stmt.has_init_expr ()) + stmt.get_init_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ExprStmt &stmt) +{ + stmt.get_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitBound &bound) +{ + for (auto &lifetime : bound.get_for_lifetimes ()) + lifetime.accept_vis (*this); + bound.get_path ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ImplTraitType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + bound->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TraitObjectType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + bound->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ParenthesisedType &type) +{ + type.get_type_in_parens ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (TupleType &type) +{ + for (auto &elem : type.get_elems ()) + elem->accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (NeverType &type) +{} + +void +DefaultHIRVisitor::walk (RawPointerType &type) +{ + type.get_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ReferenceType &type) +{ + if (type.has_lifetime ()) + type.get_lifetime ().accept_vis (*this); + type.get_base_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (ArrayType &type) +{ + type.get_element_type ().accept_vis (*this); + type.get_size_expr ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (SliceType &type) +{ + type.get_element_type ().accept_vis (*this); +} + +void +DefaultHIRVisitor::walk (InferredType &type) +{} + +void +DefaultHIRVisitor::walk (BareFunctionType &type) +{ + for (auto &lifetime : type.get_for_lifetimes ()) + lifetime.accept_vis (*this); + for (auto ¶m : type.get_function_params ()) + param.get_type ().accept_vis (*this); + if (type.has_return_type ()) + type.get_return_type ().accept_vis (*this); +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h index 283cc34..7996260 100644 --- a/gcc/rust/hir/tree/rust-hir-visitor.h +++ b/gcc/rust/hir/tree/rust-hir-visitor.h @@ -20,6 +20,7 @@ #define RUST_HIR_VISITOR_H #include "rust-hir-full-decls.h" +#include "rust-ast.h" namespace Rust { namespace HIR { @@ -64,6 +65,8 @@ public: virtual void visit (MethodCallExpr &expr) = 0; virtual void visit (FieldAccessExpr &expr) = 0; virtual void visit (BlockExpr &expr) = 0; + virtual void visit (AnonConst &expr) = 0; + virtual void visit (ConstBlock &expr) = 0; virtual void visit (ClosureExpr &expr) = 0; virtual void visit (ContinueExpr &expr) = 0; virtual void visit (BreakExpr &expr) = 0; @@ -85,6 +88,7 @@ public: virtual void visit (AsyncBlockExpr &expr) = 0; virtual void visit (InlineAsm &expr) = 0; virtual void visit (LlvmInlineAsm &expr) = 0; + virtual void visit (OffsetOf &expr) = 0; virtual void visit (TypeParam ¶m) = 0; virtual void visit (ConstGenericParam ¶m) = 0; virtual void visit (LifetimeWhereClauseItem &item) = 0; @@ -153,6 +157,312 @@ public: virtual void visit (BareFunctionType &type) = 0; }; +class DefaultHIRVisitor : public HIRFullVisitor +{ +public: + virtual void visit_where_clause (WhereClause &); + virtual void visit_where_clause (const WhereClause &); + virtual void visit_named_function_param (NamedFunctionParam ¶m); + virtual void visit_function_param (FunctionParam ¶m); + virtual void visit_self_param (SelfParam ¶m); + virtual void visit_match_arm (MatchArm &arm); + virtual void visit_match_case (MatchCase &); + virtual void visit_struct_field (StructField &field); + virtual void visit_generic_args (GenericArgs &args); + virtual void visit_qualified_path_type (QualifiedPathType &); + virtual void visit_path_expr_segment (PathExprSegment &segment); + virtual void visit_closure_param (ClosureParam ¶m); + virtual void visit_loop_label (LoopLabel &); + + virtual void visit_attribute (AST::Attribute &attr) + { + visit_attribute (static_cast<const AST::Attribute &> (attr)); + } + virtual void visit_attribute (const AST::Attribute &attr) {} + template <typename T> void visit_outer_attrs (T &node) + { + for (auto &attr : node.get_outer_attrs ()) + visit_attribute (attr); + } + template <typename T> void visit_inner_attrs (T &node) + { + for (auto &attr : node.get_inner_attrs ()) + visit_attribute (attr); + } + + virtual void visit (WhereClauseItem &node) { walk (node); } + + virtual void visit (Lifetime &node) override { walk (node); } + virtual void visit (LifetimeParam &node) override { walk (node); } + virtual void visit (PathInExpression &node) override { walk (node); } + virtual void visit (TypePathSegment &node) override { walk (node); } + virtual void visit (TypePathSegmentGeneric &node) override { walk (node); } + virtual void visit (TypePathSegmentFunction &node) override { walk (node); } + virtual void visit (TypePath &node) override { walk (node); } + virtual void visit (QualifiedPathInExpression &node) override { walk (node); } + virtual void visit (QualifiedPathInType &node) override { walk (node); } + virtual void visit (LiteralExpr &node) override { walk (node); } + virtual void visit (BorrowExpr &node) override { walk (node); } + virtual void visit (DereferenceExpr &node) override { walk (node); } + virtual void visit (ErrorPropagationExpr &node) override { walk (node); } + virtual void visit (NegationExpr &node) override { walk (node); } + virtual void visit (ArithmeticOrLogicalExpr &node) override { walk (node); } + virtual void visit (ComparisonExpr &node) override { walk (node); } + virtual void visit (LazyBooleanExpr &node) override { walk (node); } + virtual void visit (TypeCastExpr &node) override { walk (node); } + virtual void visit (AssignmentExpr &node) override { walk (node); } + virtual void visit (CompoundAssignmentExpr &node) override { walk (node); } + virtual void visit (GroupedExpr &node) override { walk (node); } + virtual void visit (ArrayElemsValues &node) override { walk (node); } + virtual void visit (ArrayElemsCopied &node) override { walk (node); } + virtual void visit (ArrayExpr &node) override { walk (node); } + virtual void visit (ArrayIndexExpr &node) override { walk (node); } + virtual void visit (TupleExpr &node) override { walk (node); } + virtual void visit (TupleIndexExpr &node) override { walk (node); } + virtual void visit (StructExprStruct &node) override { walk (node); } + virtual void visit (StructExprFieldIdentifier &node) override { walk (node); } + virtual void visit (StructExprFieldIdentifierValue &node) override + { + walk (node); + } + virtual void visit (StructExprFieldIndexValue &node) override { walk (node); } + virtual void visit (StructExprStructFields &node) override { walk (node); } + virtual void visit (StructExprStructBase &node) override { walk (node); } + virtual void visit (CallExpr &node) override { walk (node); } + virtual void visit (MethodCallExpr &node) override { walk (node); } + virtual void visit (FieldAccessExpr &node) override { walk (node); } + virtual void visit (ClosureExpr &node) override { walk (node); } + virtual void visit (BlockExpr &node) override { walk (node); } + virtual void visit (AnonConst &node) override { walk (node); } + virtual void visit (ConstBlock &node) override { walk (node); } + virtual void visit (ContinueExpr &node) override { walk (node); } + virtual void visit (BreakExpr &node) override { walk (node); } + virtual void visit (RangeFromToExpr &node) override { walk (node); } + virtual void visit (RangeFromExpr &node) override { walk (node); } + virtual void visit (RangeToExpr &node) override { walk (node); } + virtual void visit (RangeFullExpr &node) override { walk (node); } + virtual void visit (RangeFromToInclExpr &node) override { walk (node); } + virtual void visit (RangeToInclExpr &node) override { walk (node); } + virtual void visit (ReturnExpr &node) override { walk (node); } + virtual void visit (UnsafeBlockExpr &node) override { walk (node); } + virtual void visit (LoopExpr &node) override { walk (node); } + virtual void visit (WhileLoopExpr &node) override { walk (node); } + virtual void visit (WhileLetLoopExpr &node) override { walk (node); } + virtual void visit (IfExpr &node) override { walk (node); } + virtual void visit (IfExprConseqElse &node) override { walk (node); } + virtual void visit (MatchExpr &node) override { walk (node); } + virtual void visit (AwaitExpr &node) override { walk (node); } + virtual void visit (AsyncBlockExpr &node) override { walk (node); } + virtual void visit (InlineAsm &node) override { walk (node); } + virtual void visit (LlvmInlineAsm &node) override { walk (node); } + virtual void visit (OffsetOf &node) override { walk (node); } + virtual void visit (TypeParam &node) override { walk (node); } + virtual void visit (ConstGenericParam &node) override { walk (node); } + virtual void visit (LifetimeWhereClauseItem &node) override { walk (node); } + virtual void visit (TypeBoundWhereClauseItem &node) override { walk (node); } + virtual void visit (Module &node) override { walk (node); } + virtual void visit (ExternCrate &node) override { walk (node); } + virtual void visit (UseTreeGlob &node) override { walk (node); } + virtual void visit (UseTreeList &node) override { walk (node); } + virtual void visit (UseTreeRebind &node) override { walk (node); } + virtual void visit (UseDeclaration &node) override { walk (node); } + virtual void visit (Function &node) override { walk (node); } + virtual void visit (TypeAlias &node) override { walk (node); } + virtual void visit (StructStruct &node) override { walk (node); } + virtual void visit (TupleStruct &node) override { walk (node); } + virtual void visit (EnumItem &node) override { walk (node); } + virtual void visit (EnumItemTuple &node) override { walk (node); } + virtual void visit (EnumItemStruct &node) override { walk (node); } + virtual void visit (EnumItemDiscriminant &node) override { walk (node); } + virtual void visit (Enum &node) override { walk (node); } + virtual void visit (Union &node) override { walk (node); } + virtual void visit (ConstantItem &node) override { walk (node); } + virtual void visit (StaticItem &node) override { walk (node); } + virtual void visit (TraitItemFunc &node) override { walk (node); } + virtual void visit (TraitItemConst &node) override { walk (node); } + virtual void visit (TraitItemType &node) override { walk (node); } + virtual void visit (Trait &node) override { walk (node); } + virtual void visit (ImplBlock &node) override { walk (node); } + virtual void visit (ExternalStaticItem &node) override { walk (node); } + virtual void visit (ExternalFunctionItem &node) override { walk (node); } + virtual void visit (ExternalTypeItem &node) override { walk (node); } + virtual void visit (ExternBlock &node) override { walk (node); } + virtual void visit (LiteralPattern &node) override { walk (node); } + virtual void visit (IdentifierPattern &node) override { walk (node); } + virtual void visit (WildcardPattern &node) override { walk (node); } + virtual void visit (RangePatternBoundLiteral &node) override { walk (node); } + virtual void visit (RangePatternBoundPath &node) override { walk (node); } + virtual void visit (RangePatternBoundQualPath &node) override { walk (node); } + virtual void visit (RangePattern &node) override { walk (node); } + virtual void visit (ReferencePattern &node) override { walk (node); } + virtual void visit (StructPatternFieldTuplePat &node) override + { + walk (node); + } + virtual void visit (StructPatternFieldIdentPat &node) override + { + walk (node); + } + virtual void visit (StructPatternFieldIdent &node) override { walk (node); } + virtual void visit (StructPattern &node) override { walk (node); } + virtual void visit (TupleStructItemsNoRange &node) override { walk (node); } + virtual void visit (TupleStructItemsRange &node) override { walk (node); } + virtual void visit (TupleStructPattern &node) override { walk (node); } + virtual void visit (TuplePatternItemsMultiple &node) override { walk (node); } + virtual void visit (TuplePatternItemsRanged &node) override { walk (node); } + virtual void visit (TuplePattern &node) override { walk (node); } + virtual void visit (SlicePattern &node) override { walk (node); } + virtual void visit (AltPattern &node) override { walk (node); } + virtual void visit (EmptyStmt &node) override { walk (node); } + virtual void visit (LetStmt &node) override { walk (node); } + virtual void visit (ExprStmt &node) override { walk (node); } + virtual void visit (TraitBound &node) override { walk (node); } + virtual void visit (ImplTraitType &node) override { walk (node); } + virtual void visit (TraitObjectType &node) override { walk (node); } + virtual void visit (ParenthesisedType &node) override { walk (node); } + virtual void visit (TupleType &node) override { walk (node); } + virtual void visit (NeverType &node) override { walk (node); } + virtual void visit (RawPointerType &node) override { walk (node); } + virtual void visit (ReferenceType &node) override { walk (node); } + virtual void visit (ArrayType &node) override { walk (node); } + virtual void visit (SliceType &node) override { walk (node); } + virtual void visit (InferredType &node) override { walk (node); } + virtual void visit (BareFunctionType &node) override { walk (node); } + +protected: + virtual void walk (WhereClauseItem &) final; + + virtual void walk (Lifetime &) final; + virtual void walk (LifetimeParam &) final; + virtual void walk (PathInExpression &) final; + virtual void walk (TypePathSegment &) final; + virtual void walk (TypePathSegmentGeneric &) final; + virtual void walk (TypePathSegmentFunction &) final; + virtual void walk (TypePath &) final; + virtual void walk (QualifiedPathInExpression &) final; + virtual void walk (QualifiedPathInType &) final; + + virtual void walk (LiteralExpr &) final; + virtual void walk (BorrowExpr &) final; + virtual void walk (DereferenceExpr &) final; + virtual void walk (ErrorPropagationExpr &) final; + virtual void walk (NegationExpr &) final; + virtual void walk (ArithmeticOrLogicalExpr &) final; + virtual void walk (ComparisonExpr &) final; + virtual void walk (LazyBooleanExpr &) final; + virtual void walk (TypeCastExpr &) final; + virtual void walk (AssignmentExpr &) final; + virtual void walk (CompoundAssignmentExpr &) final; + virtual void walk (GroupedExpr &) final; + + virtual void walk (ArrayElemsValues &) final; + virtual void walk (ArrayElemsCopied &) final; + virtual void walk (ArrayExpr &) final; + virtual void walk (ArrayIndexExpr &) final; + virtual void walk (TupleExpr &) final; + virtual void walk (TupleIndexExpr &) final; + virtual void walk (StructExprStruct &) final; + virtual void walk (StructExprFieldIdentifier &) final; + virtual void walk (StructExprFieldIdentifierValue &) final; + virtual void walk (StructExprFieldIndexValue &) final; + virtual void walk (StructExprStructFields &) final; + virtual void walk (StructExprStructBase &) final; + virtual void walk (CallExpr &) final; + virtual void walk (MethodCallExpr &) final; + virtual void walk (FieldAccessExpr &) final; + virtual void walk (ClosureExpr &) final; + virtual void walk (BlockExpr &) final; + virtual void walk (AnonConst &) final; + virtual void walk (ConstBlock &) final; + virtual void walk (ContinueExpr &) final; + virtual void walk (BreakExpr &) final; + virtual void walk (RangeFromToExpr &) final; + virtual void walk (RangeFromExpr &) final; + virtual void walk (RangeToExpr &) final; + virtual void walk (RangeFullExpr &) final; + virtual void walk (RangeFromToInclExpr &) final; + virtual void walk (RangeToInclExpr &) final; + virtual void walk (ReturnExpr &) final; + virtual void walk (UnsafeBlockExpr &) final; + virtual void walk (LoopExpr &) final; + virtual void walk (WhileLoopExpr &) final; + virtual void walk (WhileLetLoopExpr &) final; + virtual void walk (IfExpr &) final; + virtual void walk (IfExprConseqElse &) final; + virtual void walk (MatchExpr &) final; + virtual void walk (AwaitExpr &) final; + virtual void walk (AsyncBlockExpr &) final; + virtual void walk (InlineAsm &) final; + virtual void walk (LlvmInlineAsm &) final; + virtual void walk (OffsetOf &) final; + virtual void walk (TypeParam &) final; + virtual void walk (ConstGenericParam &) final; + virtual void walk (LifetimeWhereClauseItem &) final; + virtual void walk (TypeBoundWhereClauseItem &) final; + virtual void walk (Module &) final; + virtual void walk (ExternCrate &) final; + virtual void walk (UseTreeGlob &) final; + virtual void walk (UseTreeList &) final; + virtual void walk (UseTreeRebind &) final; + virtual void walk (UseDeclaration &) final; + virtual void walk (Function &) final; + virtual void walk (TypeAlias &) final; + virtual void walk (StructStruct &) final; + virtual void walk (TupleStruct &) final; + virtual void walk (EnumItem &) final; + virtual void walk (EnumItemTuple &) final; + virtual void walk (EnumItemStruct &) final; + virtual void walk (EnumItemDiscriminant &) final; + virtual void walk (Enum &) final; + virtual void walk (Union &) final; + virtual void walk (ConstantItem &) final; + virtual void walk (StaticItem &) final; + virtual void walk (TraitItemFunc &) final; + virtual void walk (TraitItemConst &) final; + virtual void walk (TraitItemType &) final; + virtual void walk (Trait &) final; + virtual void walk (ImplBlock &) final; + virtual void walk (ExternalStaticItem &) final; + virtual void walk (ExternalFunctionItem &) final; + virtual void walk (ExternalTypeItem &) final; + virtual void walk (ExternBlock &) final; + virtual void walk (LiteralPattern &) final; + virtual void walk (IdentifierPattern &) final; + virtual void walk (WildcardPattern &) final; + virtual void walk (RangePatternBoundLiteral &) final; + virtual void walk (RangePatternBoundPath &) final; + virtual void walk (RangePatternBoundQualPath &) final; + virtual void walk (RangePattern &) final; + virtual void walk (ReferencePattern &) final; + virtual void walk (StructPatternFieldTuplePat &) final; + virtual void walk (StructPatternFieldIdentPat &) final; + virtual void walk (StructPatternFieldIdent &) final; + virtual void walk (StructPattern &) final; + virtual void walk (TupleStructItemsNoRange &) final; + virtual void walk (TupleStructItemsRange &) final; + virtual void walk (TupleStructPattern &) final; + virtual void walk (TuplePatternItemsMultiple &) final; + virtual void walk (TuplePatternItemsRanged &) final; + virtual void walk (TuplePattern &) final; + virtual void walk (SlicePattern &) final; + virtual void walk (AltPattern &) final; + virtual void walk (EmptyStmt &) final; + virtual void walk (LetStmt &) final; + virtual void walk (ExprStmt &) final; + virtual void walk (TraitBound &) final; + virtual void walk (ImplTraitType &) final; + virtual void walk (TraitObjectType &) final; + virtual void walk (ParenthesisedType &) final; + virtual void walk (TupleType &) final; + virtual void walk (NeverType &) final; + virtual void walk (RawPointerType &) final; + virtual void walk (ReferenceType &) final; + virtual void walk (ArrayType &) final; + virtual void walk (SliceType &) final; + virtual void walk (InferredType &) final; + virtual void walk (BareFunctionType &) final; +}; + class HIRFullVisitorBase : public HIRFullVisitor { public: @@ -201,6 +511,8 @@ public: virtual void visit (FieldAccessExpr &) override {} virtual void visit (ClosureExpr &) override {} virtual void visit (BlockExpr &) override {} + virtual void visit (AnonConst &) override {} + virtual void visit (ConstBlock &) override {} virtual void visit (ContinueExpr &) override {} virtual void visit (BreakExpr &) override {} virtual void visit (RangeFromToExpr &) override {} @@ -222,6 +534,7 @@ public: virtual void visit (AsyncBlockExpr &) override {} virtual void visit (InlineAsm &) override {} virtual void visit (LlvmInlineAsm &) override {} + virtual void visit (OffsetOf &) override {} virtual void visit (TypeParam &) override {} virtual void visit (ConstGenericParam &) override {} @@ -427,6 +740,8 @@ public: virtual void visit (MethodCallExpr &expr) = 0; virtual void visit (FieldAccessExpr &expr) = 0; virtual void visit (BlockExpr &expr) = 0; + virtual void visit (AnonConst &expr) = 0; + virtual void visit (ConstBlock &expr) = 0; virtual void visit (ContinueExpr &expr) = 0; virtual void visit (BreakExpr &expr) = 0; virtual void visit (RangeFromToExpr &expr) = 0; @@ -443,6 +758,7 @@ public: virtual void visit (IfExpr &expr) = 0; virtual void visit (IfExprConseqElse &expr) = 0; virtual void visit (InlineAsm &expr) = 0; + virtual void visit (OffsetOf &expr) = 0; virtual void visit (LlvmInlineAsm &expr) = 0; virtual void visit (MatchExpr &expr) = 0; virtual void visit (AwaitExpr &expr) = 0; diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 093d8d5..a802e8c 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -577,7 +577,8 @@ UseTreeGlob::as_string () const return "*"; case GLOBAL: return "::*"; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { std::string path_str = path.as_string (); return path_str + "::*"; } @@ -600,7 +601,8 @@ UseTreeList::as_string () const case GLOBAL: path_str = "::{"; break; - case PATH_PREFIXED: { + case PATH_PREFIXED: + { path_str = path.as_string () + "::{"; break; } @@ -1048,6 +1050,36 @@ BlockExpr::as_string () const } std::string +AnonConst::as_string () const +{ + std::string istr = indent_spaces (enter); + std::string str = istr + "AnonConst:\n" + istr; + + if (expr.has_value ()) + str += get_inner_expr ().as_string (); + else + str += "_"; + + str += "\n" + indent_spaces (out); + + return str; +} + +std::string +ConstBlock::as_string () const +{ + std::string istr = indent_spaces (enter); + + std::string str = istr + "ConstBlock:\n" + istr; + + str += get_const_expr ().as_string (); + + str += "\n" + indent_spaces (out); + + return str; +} + +std::string TypeAlias::as_string () const { std::string str = VisItem::as_string (); @@ -2579,9 +2611,9 @@ IdentifierPattern::as_string () const str += variable_ident.as_string (); - if (has_pattern_to_bind ()) + if (has_subpattern ()) { - str += " @ " + to_bind->as_string (); + str += " @ " + subpattern->as_string (); } return str; @@ -4055,6 +4087,18 @@ BlockExpr::accept_vis (HIRFullVisitor &vis) } void +AnonConst::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstBlock::accept_vis (HIRFullVisitor &vis) +{ + vis.visit (*this); +} + +void ContinueExpr::accept_vis (HIRFullVisitor &vis) { vis.visit (*this); @@ -5027,6 +5071,18 @@ BlockExpr::accept_vis (HIRExpressionVisitor &vis) } void +AnonConst::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstBlock::accept_vis (HIRExpressionVisitor &vis) +{ + vis.visit (*this); +} + +void Function::accept_vis (HIRStmtVisitor &vis) { vis.visit (*this); diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt index 9cdbce2..d9824f1 100644 --- a/gcc/rust/lang.opt +++ b/gcc/rust/lang.opt @@ -205,7 +205,7 @@ EnumValue Enum(frust_compile_until) String(end) Value(13) frust-name-resolution-2.0 -Rust Var(flag_name_resolution_2_0) +Rust Var(flag_name_resolution_2_0) Init(1) Use the temporary and experimental name resolution pipeline instead of the stable one frust-borrowcheck @@ -229,4 +229,8 @@ frust-overflow-checks Rust Var(flag_overflow_checks) Init(1) Enable the overflow checks in code generation +frust-assume-builtin-offset-of +Rust Var(flag_assume_builtin_offset_of) +Define a built-in offset_of macro in the compiler and assume it is present + ; This comment is to ensure we retain the blank line above. diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc index b143e70..76ff15c 100644 --- a/gcc/rust/lex/rust-lex.cc +++ b/gcc/rust/lex/rust-lex.cc @@ -1317,7 +1317,8 @@ Lexer::parse_escape (char opening_char) switch (current_char.value) { - case 'x': { + case 'x': + { auto hex_escape_pair = parse_partial_hex_escape (); long hexLong = hex_escape_pair.first; additional_length_offset += hex_escape_pair.second; @@ -1400,7 +1401,8 @@ Lexer::parse_utf8_escape () switch (current_char.value) { - case 'x': { + case 'x': + { auto hex_escape_pair = parse_partial_hex_escape (); long hexLong = hex_escape_pair.first; additional_length_offset += hex_escape_pair.second; @@ -1438,7 +1440,8 @@ Lexer::parse_utf8_escape () case '"': output_char = '"'; break; - case 'u': { + case 'u': + { auto unicode_escape_pair = parse_partial_unicode_escape (); output_char = unicode_escape_pair.first; additional_length_offset += unicode_escape_pair.second; @@ -1894,6 +1897,11 @@ Lexer::parse_raw_byte_string (location_t loc) break; } } + else if (current_char.is_eof ()) + { + rust_error_at (string_begin_locus, "unended raw byte string literal"); + return Token::make (END_OF_FILE, get_current_location ()); + } else if (current_char.value > 127) { rust_error_at (get_current_location (), @@ -1901,11 +1909,6 @@ Lexer::parse_raw_byte_string (location_t loc) current_char.as_string ().c_str ()); current_char = 0; } - else if (current_char.is_eof ()) - { - rust_error_at (string_begin_locus, "unended raw byte string literal"); - return Token::make (END_OF_FILE, get_current_location ()); - } length++; current_column++; diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h index 10293e0..383ffac 100644 --- a/gcc/rust/lex/rust-lex.h +++ b/gcc/rust/lex/rust-lex.h @@ -263,8 +263,7 @@ private: #if CHECKING_P namespace selftest { -void -rust_input_source_test (); +void rust_input_source_test (); } // namespace selftest diff --git a/gcc/rust/lex/rust-token.cc b/gcc/rust/lex/rust-token.cc index 8493889..c396e10 100644 --- a/gcc/rust/lex/rust-token.cc +++ b/gcc/rust/lex/rust-token.cc @@ -20,6 +20,7 @@ #include "rust-token.h" #include "rust-diagnostics.h" #include "rust-unicode.h" +#include "rust-ast.h" namespace Rust { // Hackily defined way to get token description for enum value using x-macros @@ -88,7 +89,8 @@ token_id_keyword_string (TokenId id) switch (id) { #define RS_TOKEN_KEYWORD_2015(id, str_ptr) \ - case id: { \ + case id: \ + { \ static const std::string str (str_ptr); \ return str; \ } \ @@ -234,6 +236,13 @@ escape_special_chars (const std::string &source, Context ctx) } // namespace +TokenPtr +Token::make_identifier (const Identifier &ident) +{ + std::string str = ident; + return make_identifier (ident.get_locus (), std::move (str)); +} + std::string Token::as_string () const { diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h index c683ecd..2021aec 100644 --- a/gcc/rust/lex/rust-token.h +++ b/gcc/rust/lex/rust-token.h @@ -24,6 +24,10 @@ #include "rust-unicode.h" namespace Rust { + +// used by Rust::Token::make_identifier +class Identifier; + // "Primitive core types" in Rust - the different int and float types, as well // as some others enum PrimitiveCoreType @@ -221,25 +225,20 @@ typedef std::shared_ptr<Token> TokenPtr; typedef std::shared_ptr<const Token> const_TokenPtr; // Hackily defined way to get token description for enum value using x-macros -const char * -get_token_description (TokenId id); +const char *get_token_description (TokenId id); /* Hackily defined way to get token description as a string for enum value using * x-macros */ -const char * -token_id_to_str (TokenId id); +const char *token_id_to_str (TokenId id); /* checks if a token is a keyword */ -bool -token_id_is_keyword (TokenId id); +bool token_id_is_keyword (TokenId id); /* gets the string associated with a keyword */ -const std::string & -token_id_keyword_string (TokenId id); +const std::string &token_id_keyword_string (TokenId id); // Get type hint description as a string. -const char * -get_type_hint_string (PrimitiveCoreType type); +const char *get_type_hint_string (PrimitiveCoreType type); /* Normalize string if a token is a identifier */ -std::string -nfc_normalize_token_string (location_t loc, TokenId id, const std::string &str); +std::string nfc_normalize_token_string (location_t loc, TokenId id, + const std::string &str); // Represents a single token. Create using factory static methods. class Token @@ -329,6 +328,8 @@ public: return TokenPtr (new Token (IDENTIFIER, locus, std::move (str))); } + static TokenPtr make_identifier (const Identifier &ident); + // Makes and returns a new TokenPtr of type INT_LITERAL. static TokenPtr make_int (location_t locus, std::string &&str, PrimitiveCoreType type_hint = CORETYPE_UNKNOWN) diff --git a/gcc/rust/metadata/rust-export-metadata.cc b/gcc/rust/metadata/rust-export-metadata.cc index 771bec6..1829a85 100644 --- a/gcc/rust/metadata/rust-export-metadata.cc +++ b/gcc/rust/metadata/rust-export-metadata.cc @@ -263,8 +263,7 @@ PublicInterface::write_to_path (const std::string &path) const FILE *nfd = fopen (path.c_str (), "wb"); if (nfd == NULL) { - rust_error_at (UNDEF_LOCATION, - "failed to open file %qs for writing: %s", + rust_error_at (UNDEF_LOCATION, "failed to open file %qs for writing: %s", path.c_str (), xstrerror (errno)); return; } diff --git a/gcc/rust/metadata/rust-import-archive.cc b/gcc/rust/metadata/rust-import-archive.cc index cf24607..f64de4e 100644 --- a/gcc/rust/metadata/rust-import-archive.cc +++ b/gcc/rust/metadata/rust-import-archive.cc @@ -683,7 +683,7 @@ public: const Header &operator* () const { return this->header_; } - const Header *operator-> () const { return &this->header_; } + const Header *operator->() const { return &this->header_; } Archive_iterator &operator++ () { diff --git a/gcc/rust/metadata/rust-imports.h b/gcc/rust/metadata/rust-imports.h index a497c67..65a2af1 100644 --- a/gcc/rust/metadata/rust-imports.h +++ b/gcc/rust/metadata/rust-imports.h @@ -11,8 +11,7 @@ namespace Rust { -extern void -add_search_path (const std::string &path); +extern void add_search_path (const std::string &path); class Import { diff --git a/gcc/rust/parse/rust-cfg-parser.h b/gcc/rust/parse/rust-cfg-parser.h index 0d64016..61db240 100644 --- a/gcc/rust/parse/rust-cfg-parser.h +++ b/gcc/rust/parse/rust-cfg-parser.h @@ -36,15 +36,14 @@ namespace Rust { * * @return false if the given input was invalid, true otherwise */ -bool -parse_cfg_option (std::string &input, std::string &key, std::string &value); +bool parse_cfg_option (std::string &input, std::string &key, + std::string &value); } // namespace Rust #if CHECKING_P namespace selftest { -extern void -rust_cfg_parser_test (void); +extern void rust_cfg_parser_test (void); } // namespace selftest #endif // CHECKING_P diff --git a/gcc/rust/ast/rust-macro.cc b/gcc/rust/parse/rust-parse-impl-lexer.cc index 2703438..fec91e8 100644 --- a/gcc/rust/ast/rust-macro.cc +++ b/gcc/rust/parse/rust-parse-impl-lexer.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2025 Free Software Foundation, Inc. +// Copyright (C) 2025 Free Software Foundation, Inc. // This file is part of GCC. @@ -16,10 +16,10 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -#include "rust-macro.h" +#include "rust-parse-impl.h" namespace Rust { -namespace AST { -} // namespace AST +template class Parser<Lexer>; + } // namespace Rust diff --git a/gcc/rust/parse/rust-parse-impl-macro.cc b/gcc/rust/parse/rust-parse-impl-macro.cc new file mode 100644 index 0000000..e632887 --- /dev/null +++ b/gcc/rust/parse/rust-parse-impl-macro.cc @@ -0,0 +1,26 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-parse-impl.h" +#include "rust-macro-invoc-lexer.h" + +namespace Rust { + +template class Parser<MacroInvocLexer>; + +} // namespace Rust diff --git a/gcc/rust/parse/rust-parse-impl-proc-macro.cc b/gcc/rust/parse/rust-parse-impl-proc-macro.cc new file mode 100644 index 0000000..edc484f --- /dev/null +++ b/gcc/rust/parse/rust-parse-impl-proc-macro.cc @@ -0,0 +1,34 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-parse-impl.h" +#include "rust-proc-macro-invoc-lexer.h" + +namespace Rust { + +template std::unique_ptr<AST::Item> +Parser<ProcMacroInvocLexer>::parse_item (bool); + +template std::unique_ptr<AST::Stmt> + Parser<ProcMacroInvocLexer>::parse_stmt (ParseRestrictions); + +// instantiate entire class (or just more functions) if necessary + +// template class Parser<ProcMacroInvocLexer>; + +} // namespace Rust diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 9dda231..14bccbd 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -19,13 +19,17 @@ /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before * Parser was template). Separated from rust-parse.h for readability. */ -/* DO NOT INCLUDE ANYWHERE - this is automatically included with rust-parse.h +/* DO NOT INCLUDE ANYWHERE - this is automatically included + * by rust-parse-impl-*.cc * This is also the reason why there are no include guards. */ +#include "expected.h" +#include "rust-ast.h" #include "rust-common.h" #include "rust-expr.h" #include "rust-item.h" #include "rust-common.h" +#include "rust-parse.h" #include "rust-token.h" #define INCLUDE_ALGORITHM #include "rust-diagnostics.h" @@ -227,19 +231,22 @@ Parser<ManagedTokenSource>::skip_generics_right_angle () // this is good - skip token lexer.skip_token (); return true; - case RIGHT_SHIFT: { + case RIGHT_SHIFT: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE); lexer.skip_token (); return true; } - case GREATER_OR_EQUAL: { + case GREATER_OR_EQUAL: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, EQUAL); lexer.skip_token (); return true; } - case RIGHT_SHIFT_EQ: { + case RIGHT_SHIFT_EQ: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL); lexer.skip_token (); @@ -651,10 +658,7 @@ Parser<ManagedTokenSource>::parse_simple_path () // Parse all other simple path segments while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) { - // Skip scope resolution operator - lexer.skip_token (); - - AST::SimplePathSegment new_segment = parse_simple_path_segment (); + AST::SimplePathSegment new_segment = parse_simple_path_segment (1); // Return path as currently constructed if segment in error state. if (new_segment.is_error ()) @@ -682,35 +686,36 @@ Parser<ManagedTokenSource>::parse_simple_path () } /* Parses a single SimplePathSegment (does not handle the scope resolution - * operators) */ + * operators) + * Starts parsing at an offset of base_peek */ template <typename ManagedTokenSource> AST::SimplePathSegment -Parser<ManagedTokenSource>::parse_simple_path_segment () +Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek) { using namespace Values; - const_TokenPtr t = lexer.peek_token (); + const_TokenPtr t = lexer.peek_token (base_peek); switch (t->get_id ()) { case IDENTIFIER: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (t->get_str (), t->get_locus ()); case SUPER: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ()); case SELF: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::SELF, t->get_locus ()); case CRATE: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ()); case DOLLAR_SIGN: - if (lexer.peek_token (1)->get_id () == CRATE) + if (lexer.peek_token (base_peek + 1)->get_id () == CRATE) { - lexer.skip_token (1); + lexer.skip_token (base_peek + 1); return AST::SimplePathSegment ("$crate", t->get_locus ()); } @@ -790,7 +795,8 @@ Parser<ManagedTokenSource>::parse_attr_input () { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: { + case LEFT_CURLY: + { // must be a delimited token tree, so parse that std::unique_ptr<AST::AttrInput> input_tree ( new AST::DelimTokenTree (parse_delim_token_tree ())); @@ -799,7 +805,8 @@ Parser<ManagedTokenSource>::parse_attr_input () return input_tree; } - case EQUAL: { + case EQUAL: + { // = LiteralExpr lexer.skip_token (); @@ -877,7 +884,10 @@ Parser<ManagedTokenSource>::parse_attr_input () return attr_input_lit; } break; + case RIGHT_PAREN: case RIGHT_SQUARE: + case RIGHT_CURLY: + case END_OF_FILE: // means AttrInput is missing, which is allowed return nullptr; default: @@ -2117,7 +2127,8 @@ Parser<ManagedTokenSource>::parse_macro_match () { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: { + case LEFT_CURLY: + { // must be macro matcher as delimited AST::MacroMatcher matcher = parse_macro_matcher (); if (matcher.is_error ()) @@ -2131,7 +2142,8 @@ Parser<ManagedTokenSource>::parse_macro_match () return std::unique_ptr<AST::MacroMatcher> ( new AST::MacroMatcher (std::move (matcher))); } - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // have to do more lookahead to determine if fragment or repetition const_TokenPtr t2 = lexer.peek_token (1); switch (t2->get_id ()) @@ -2402,7 +2414,8 @@ Parser<ManagedTokenSource>::parse_visibility () skip_token (RIGHT_PAREN); return AST::Visibility::create_super (path_loc, vis_loc); - case IN: { + case IN: + { lexer.skip_token (); // parse the "in" path as well @@ -2466,7 +2479,8 @@ Parser<ManagedTokenSource>::parse_module (AST::Visibility vis, new AST::Module (std::move (name), std::move (vis), std::move (outer_attrs), locus, safety, lexer.get_filename (), inline_module_stack)); - case LEFT_CURLY: { + case LEFT_CURLY: + { lexer.skip_token (); // parse inner attributes @@ -2730,7 +2744,8 @@ Parser<ManagedTokenSource>::parse_use_tree () return std::unique_ptr<AST::UseTreeGlob> ( new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH, AST::SimplePath::create_empty (), locus)); - case LEFT_CURLY: { + case LEFT_CURLY: + { // nested tree UseTree type lexer.skip_token (); @@ -2794,58 +2809,12 @@ Parser<ManagedTokenSource>::parse_use_tree () } else { - /* Due to aforementioned implementation issues, the trailing :: token is - * consumed by the path, so it can not be used as a disambiguator. - * NOPE, not true anymore - TODO what are the consequences of this? */ - const_TokenPtr t = lexer.peek_token (); + switch (t->get_id ()) { - case ASTERISK: - // glob UseTree type - lexer.skip_token (); - - return std::unique_ptr<AST::UseTreeGlob> ( - new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, - std::move (path), locus)); - case LEFT_CURLY: { - // nested tree UseTree type - lexer.skip_token (); - - std::vector<std::unique_ptr<AST::UseTree>> use_trees; - - // TODO: think of better control structure - const_TokenPtr t = lexer.peek_token (); - while (t->get_id () != RIGHT_CURLY) - { - std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); - if (use_tree == nullptr) - { - break; - } - - use_trees.push_back (std::move (use_tree)); - - if (lexer.peek_token ()->get_id () != COMMA) - break; - - lexer.skip_token (); - t = lexer.peek_token (); - } - - // skip end curly delimiter - if (!skip_token (RIGHT_CURLY)) - { - // skip after somewhere? - return nullptr; - } - - return std::unique_ptr<AST::UseTreeList> ( - new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, - std::move (path), std::move (use_trees), - locus)); - } - case AS: { + case AS: + { // rebind UseTree type lexer.skip_token (); @@ -2884,16 +2853,72 @@ Parser<ManagedTokenSource>::parse_use_tree () // don't skip semicolon - handled in parse_use_tree // lexer.skip_token(); - - return std::unique_ptr<AST::UseTreeRebind> ( - new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), - locus)); case COMMA: case RIGHT_CURLY: // this may occur in recursive calls - assume it is ok and ignore it return std::unique_ptr<AST::UseTreeRebind> ( new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), locus)); + case SCOPE_RESOLUTION: + // keep going + break; + default: + add_error (Error (t->get_locus (), + "unexpected token %qs in use tree with valid path", + t->get_token_description ())); + return nullptr; + } + + skip_token (); + t = lexer.peek_token (); + + switch (t->get_id ()) + { + case ASTERISK: + // glob UseTree type + lexer.skip_token (); + + return std::unique_ptr<AST::UseTreeGlob> ( + new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, + std::move (path), locus)); + case LEFT_CURLY: + { + // nested tree UseTree type + lexer.skip_token (); + + std::vector<std::unique_ptr<AST::UseTree>> use_trees; + + // TODO: think of better control structure + const_TokenPtr t = lexer.peek_token (); + while (t->get_id () != RIGHT_CURLY) + { + std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); + if (use_tree == nullptr) + { + break; + } + + use_trees.push_back (std::move (use_tree)); + + if (lexer.peek_token ()->get_id () != COMMA) + break; + + lexer.skip_token (); + t = lexer.peek_token (); + } + + // skip end curly delimiter + if (!skip_token (RIGHT_CURLY)) + { + // skip after somewhere? + return nullptr; + } + + return std::unique_ptr<AST::UseTreeList> ( + new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, + std::move (path), std::move (use_trees), + locus)); + } default: add_error (Error (t->get_locus (), "unexpected token %qs in use tree with valid path", @@ -3100,7 +3125,8 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) switch (token->get_id ()) { - case LIFETIME: { + case LIFETIME: + { auto lifetime = parse_lifetime (false); if (!lifetime) { @@ -3126,7 +3152,8 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) std::move (outer_attrs), token->get_locus ())); break; } - case IDENTIFIER: { + case IDENTIFIER: + { auto type_ident = token->get_str (); lexer.skip_token (); @@ -3161,7 +3188,8 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) std::move (outer_attrs))); break; } - case CONST: { + case CONST: + { lexer.skip_token (); auto name_token = expect_token (IDENTIFIER); @@ -3345,7 +3373,8 @@ Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) /* Parses lifetime generic parameters (objects). Will also consume any * trailing comma. No extra checks for end token. - * TODO: is this best solution? implements most of the same algorithm. */ + * TODO: is this best solution? implements most of the same algorithm. + * TODO: seems to be unused, remove? */ template <typename ManagedTokenSource> std::vector<AST::LifetimeParam> Parser<ManagedTokenSource>::parse_lifetime_params_objs () @@ -3363,7 +3392,7 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs () break; } - lifetime_params.push_back (std::move (lifetime_param)); + lifetime_params.push_back (std::move (lifetime_param.value ())); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -4356,7 +4385,8 @@ Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct with body // skip curly bracket @@ -4759,7 +4789,8 @@ Parser<ManagedTokenSource>::parse_enum_item () const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple enum item lexer.skip_token (); @@ -4780,7 +4811,8 @@ Parser<ManagedTokenSource>::parse_enum_item () std::move (item_name), std::move (vis), std::move (tuple_fields), std::move (outer_attrs), item_name_tok->get_locus ())); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct enum item lexer.skip_token (); @@ -4797,7 +4829,8 @@ Parser<ManagedTokenSource>::parse_enum_item () std::move (item_name), std::move (vis), std::move (struct_fields), std::move (outer_attrs), item_name_tok->get_locus ())); } - case EQUAL: { + case EQUAL: + { // discriminant enum item lexer.skip_token (); @@ -5450,7 +5483,8 @@ Parser<ManagedTokenSource>::parse_inherent_impl_item () case SUPER: case SELF: case CRATE: - case PUB: { + case PUB: + { // visibility, so not a macro invocation semi - must be constant, // function, or method AST::Visibility vis = parse_visibility (); @@ -5581,7 +5615,8 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method ( // param auto initial_param = parse_self_param (); - if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) return nullptr; /* FIXME: ensure that self param doesn't accidently consume tokens for a @@ -5780,7 +5815,8 @@ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method ( // param auto initial_param = parse_self_param (); - if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) return nullptr; // FIXME: ensure that self param doesn't accidently consume tokens for a @@ -5964,7 +6000,8 @@ Parser<ManagedTokenSource>::parse_external_item () { case IDENTIFIER: return parse_macro_invocation_semi (outer_attrs); - case STATIC_KW: { + case STATIC_KW: + { // parse extern static item lexer.skip_token (); @@ -6261,7 +6298,8 @@ Parser<ManagedTokenSource>::parse_generic_arg () switch (tok->get_id ()) { - case IDENTIFIER: { + case IDENTIFIER: + { // This is a bit of a weird situation: With an identifier token, we // could either have a valid type or a macro (FIXME: anything else?). So // we need one bit of lookahead to differentiate if this is really @@ -6309,9 +6347,10 @@ Parser<ManagedTokenSource>::parse_generic_arg () case FALSE_LITERAL: expr = parse_literal_expr (); break; - // FIXME: Because of this, error reporting is garbage for const generic - // parameter's default values - default: { + // FIXME: Because of this, error reporting is garbage for const generic + // parameter's default values + default: + { auto type = parse_type (); // FIXME: Find a better way to do this? if (type) @@ -6510,7 +6549,8 @@ Parser<ManagedTokenSource>::parse_type_path_segment () switch (t->get_id ()) { case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // parse generic args AST::GenericArgs generic_args = parse_path_generic_args (); @@ -6519,7 +6559,8 @@ Parser<ManagedTokenSource>::parse_type_path_segment () has_separating_scope_resolution, std::move (generic_args), locus)); } - case LEFT_PAREN: { + case LEFT_PAREN: + { // parse type path function AST::TypePathFunction type_path_function = parse_type_path_function (locus); @@ -7068,16 +7109,14 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, case SELF: case SELF_ALIAS: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { AST::PathInExpression path = parse_path_in_expression (); std::unique_ptr<AST::Expr> null_denotation; if (lexer.peek_token ()->get_id () == EXCLAM) { - // Bind a reference to avoid -Wredundant-move on post-P1825R0 - // compilers. Change to non-reference type and remove the moves - // below once C++20 is required to build gcc. - std::unique_ptr<AST::MacroInvocation> &&invoc + std::unique_ptr<AST::MacroInvocation> invoc = parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); @@ -7085,7 +7124,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, { invoc->add_semicolon (); // Macro invocation with semicolon. - return std::move (invoc); + return invoc; } TokenId after_macro = lexer.peek_token ()->get_id (); @@ -7093,14 +7132,14 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, if (restrictions.allow_close_after_expr_stmt && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY || after_macro == RIGHT_SQUARE)) - return std::move (invoc); + return invoc; if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type () == AST::CURLY && after_macro != DOT && after_macro != QUESTION_MARK) { rust_debug ("braced macro statement"); - return std::move (invoc); + return invoc; } null_denotation = std::move (invoc); @@ -7238,6 +7277,51 @@ Parser<ManagedTokenSource>::parse_block_expr ( std::move (label), locus, end_locus)); } +/* Parse an anonymous const expression. This can be a regular const expression + * or an underscore for deferred const inference */ +template <typename ManagedTokenSource> +tl::expected<AST::AnonConst, AnonConstError> +Parser<ManagedTokenSource>::parse_anon_const () +{ + auto current = lexer.peek_token (); + auto locus = current->get_locus (); + + // Special case deferred inference constants + if (maybe_skip_token (UNDERSCORE)) + return AST::AnonConst (locus); + + auto expr = parse_expr (); + + if (!expr) + return tl::make_unexpected (AnonConstError::InvalidSizeExpr); + + return AST::AnonConst (std::move (expr), locus); +} + +/* Parse a "const block", a block preceded by the `const` keyword whose + * statements can be const evaluated and used in constant contexts */ +template <typename ManagedTokenSource> +std::unique_ptr<AST::ConstBlock> +Parser<ManagedTokenSource>::parse_const_block_expr (AST::AttrVec outer_attrs, + location_t locus) +{ + auto block = parse_block_expr (); + + if (!block) + { + add_error (Error (locus, "failed to parse inner block in const block")); + skip_after_end_block (); + + return nullptr; + } + + auto block_locus = block->get_locus (); + + return std::make_unique<AST::ConstBlock> (AST::AnonConst (std::move (block), + block_locus), + locus, std::move (outer_attrs)); +} + /* Parses a "grouped" expression (expression in parentheses), used to control * precedence. */ template <typename ManagedTokenSource> @@ -7518,6 +7602,34 @@ Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs, locus)); } +// Parses a try expression. +template <typename ManagedTokenSource> +std::unique_ptr<AST::TryExpr> +Parser<ManagedTokenSource>::parse_try_expr (AST::AttrVec outer_attrs, + location_t pratt_parsed_loc) +{ + location_t locus = pratt_parsed_loc; + if (locus == UNKNOWN_LOCATION) + { + locus = lexer.peek_token ()->get_locus (); + skip_token (TRY); + } + + std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); + + if (!block_expr) + { + Error error (lexer.peek_token ()->get_locus (), + "failed to parse try block expression"); + add_error (std::move (error)); + + return nullptr; + } + + return std::unique_ptr<AST::TryExpr> ( + new AST::TryExpr (std::move (block_expr), std::move (outer_attrs), locus)); +} + /* Parses a break expression (including any label to break to AND any return * expression). */ template <typename ManagedTokenSource> @@ -7675,7 +7787,8 @@ Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // double selection - else // parse else block expr (required) std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); @@ -7696,7 +7809,8 @@ Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, std::move (else_body), std::move (outer_attrs), locus)); } - case IF: { + case IF: + { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token (1)->get_id () == LET) @@ -7857,7 +7971,8 @@ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // double selection - else // parse else block expr (required) std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); @@ -7879,7 +7994,8 @@ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, std::move (else_body), std::move (outer_attrs), locus)); } - case IF: { + case IF: + { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token (1)->get_id () == LET) @@ -8931,7 +9047,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) // slice type or array type - requires further disambiguation return parse_slice_or_array_type (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in type AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) @@ -8960,7 +9077,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) case LOGICAL_AND: // reference type return parse_reference_type (); - case LIFETIME: { + case LIFETIME: + { /* probably a lifetime bound, so probably type param bounds in * TraitObjectType */ std::vector<std::unique_ptr<AST::TypeParamBound>> bounds @@ -8976,7 +9094,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) case SELF_ALIAS: case CRATE: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // macro invocation or type path - requires further disambiguation. /* for parsing path component of each rule, perhaps parse it as a * typepath and attempt conversion to simplepath if a trailing '!' is @@ -9006,7 +9125,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) t = lexer.peek_token (); switch (t->get_id ()) { - case EXCLAM: { + case EXCLAM: + { // macro invocation // convert to simple path AST::SimplePath macro_path = path.as_simple_path (); @@ -9032,7 +9152,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) std::move (tok_tree)), {}, locus); } - case PLUS: { + case PLUS: + { // type param bounds std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; @@ -9117,14 +9238,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) t = lexer.peek_token (); if (t->get_id () != PLUS) { - // convert trait bound to value object - AST::TraitBound value_bound (*initial_bound); - - // DEBUG: removed as unique ptr, so should auto-delete - // delete initial_bound; - return std::unique_ptr<AST::ImplTraitTypeOneBound> ( - new AST::ImplTraitTypeOneBound (std::move (value_bound), + new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus)); } @@ -9152,7 +9267,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) new AST::ImplTraitType (std::move (bounds), locus)); } case DYN: - case QUESTION_MARK: { + case QUESTION_MARK: + { // either TraitObjectType or TraitObjectTypeOneBound bool has_dyn = false; if (t->get_id () == DYN) @@ -9405,7 +9521,8 @@ Parser<ManagedTokenSource>::parse_for_prefixed_type () case SELF: case SELF_ALIAS: case CRATE: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path, so trait type // parse type path to finish parsing trait bound @@ -9751,13 +9868,15 @@ Parser<ManagedTokenSource>::parse_slice_or_array_type () return std::unique_ptr<AST::SliceType> ( new AST::SliceType (std::move (inner_type), locus)); - case SEMICOLON: { + case SEMICOLON: + { // array type lexer.skip_token (); // parse required array size expression - std::unique_ptr<AST::Expr> size = parse_expr (); - if (size == nullptr) + auto size = parse_anon_const (); + + if (!size) { Error error (lexer.peek_token ()->get_locus (), "failed to parse size expression in array type"); @@ -9772,7 +9891,8 @@ Parser<ManagedTokenSource>::parse_slice_or_array_type () } return std::unique_ptr<AST::ArrayType> ( - new AST::ArrayType (std::move (inner_type), std::move (size), locus)); + new AST::ArrayType (std::move (inner_type), std::move (*size), + locus)); } default: // error @@ -9802,7 +9922,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () // slice type or array type - requires further disambiguation return parse_slice_or_array_type (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in type AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) @@ -9843,7 +9964,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () case SELF_ALIAS: case CRATE: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // macro invocation or type path - requires further disambiguation. /* for parsing path component of each rule, perhaps parse it as a * typepath and attempt conversion to simplepath if a trailing '!' is @@ -9871,7 +9993,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () t = lexer.peek_token (); switch (t->get_id ()) { - case EXCLAM: { + case EXCLAM: + { // macro invocation // convert to simple path AST::SimplePath macro_path = path.as_simple_path (); @@ -9955,14 +10078,12 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () return nullptr; } - // convert trait bound to value object - AST::TraitBound value_bound (*initial_bound); - return std::unique_ptr<AST::ImplTraitTypeOneBound> ( - new AST::ImplTraitTypeOneBound (std::move (value_bound), locus)); + new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus)); } case DYN: - case QUESTION_MARK: { + case QUESTION_MARK: + { // either TraitObjectTypeOneBound bool has_dyn = false; if (t->get_id () == DYN) @@ -10303,7 +10424,8 @@ Parser<ManagedTokenSource>::parse_range_pattern_bound () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path in expression AST::PathInExpression path = parse_path_in_expression (); if (path.is_error ()) @@ -10319,7 +10441,8 @@ Parser<ManagedTokenSource>::parse_range_pattern_bound () new AST::RangePatternBoundPath (std::move (path))); } case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in expression AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); @@ -10464,7 +10587,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () // slice pattern return parse_slice_pattern (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in expression or qualified range pattern bound AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); @@ -10500,7 +10624,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path in expression or range pattern bound AST::PathInExpression path = parse_path_in_expression (); @@ -10509,7 +10634,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () { case DOT_DOT_EQ: case DOT_DOT: - case ELLIPSIS: { + case ELLIPSIS: + { // qualified range pattern bound, so parse rest of range pattern AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); lexer.skip_token (); @@ -10527,7 +10653,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple struct lexer.skip_token (); @@ -10552,7 +10679,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () new AST::TupleStructPattern (std::move (path), std::move (items))); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct lexer.skip_token (); @@ -10722,7 +10850,8 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () return std::unique_ptr<AST::GroupedPattern> ( new AST::GroupedPattern (std::move (initial_pattern), paren_locus)); - case COMMA: { + case COMMA: + { // tuple pattern lexer.skip_token (); @@ -10835,27 +10964,47 @@ Parser<ManagedTokenSource>::parse_slice_pattern () { location_t square_locus = lexer.peek_token ()->get_locus (); std::vector<std::unique_ptr<AST::Pattern>> patterns; + tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns + = tl::nullopt; + + // lambda function to determine which vector to push new patterns into + auto get_pattern_ref + = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & { + return upper_patterns.has_value () ? upper_patterns.value () : patterns; + }; + skip_token (LEFT_SQUARE); if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) { skip_token (RIGHT_SQUARE); + std::unique_ptr<AST::SlicePatternItemsNoRest> items ( + new AST::SlicePatternItemsNoRest (std::move (patterns))); return std::unique_ptr<AST::SlicePattern> ( - new AST::SlicePattern (std::move (patterns), square_locus)); + new AST::SlicePattern (std::move (items), square_locus)); } // parse initial pattern (required) - std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); - if (initial_pattern == nullptr) + if (lexer.peek_token ()->get_id () == DOT_DOT) { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse initial pattern in slice pattern"); - add_error (std::move (error)); - - return nullptr; + lexer.skip_token (); + upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> (); } + else + { + // Not a rest pattern `..`, parse normally + std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); + if (initial_pattern == nullptr) + { + Error error (lexer.peek_token ()->get_locus (), + "failed to parse initial pattern in slice pattern"); + add_error (std::move (error)); - patterns.push_back (std::move (initial_pattern)); + return nullptr; + } + + patterns.push_back (std::move (initial_pattern)); + } const_TokenPtr t = lexer.peek_token (); while (t->get_id () == COMMA) @@ -10866,6 +11015,23 @@ Parser<ManagedTokenSource>::parse_slice_pattern () if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) break; + if (lexer.peek_token ()->get_id () == DOT_DOT) + { + if (upper_patterns.has_value ()) + { + // DOT_DOT has been parsed before + Error error (lexer.peek_token ()->get_locus (), "%s", + "`..` can only be used once per slice pattern"); + add_error (std::move (error)); + + return nullptr; + } + upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> (); + lexer.skip_token (); + t = lexer.peek_token (); + continue; + } + // parse pattern (required) std::unique_ptr<AST::Pattern> pattern = parse_pattern (); if (pattern == nullptr) @@ -10876,7 +11042,7 @@ Parser<ManagedTokenSource>::parse_slice_pattern () return nullptr; } - patterns.push_back (std::move (pattern)); + get_pattern_ref ().push_back (std::move (pattern)); t = lexer.peek_token (); } @@ -10886,8 +11052,21 @@ Parser<ManagedTokenSource>::parse_slice_pattern () return nullptr; } + if (upper_patterns.has_value ()) + { + // Slice pattern with rest + std::unique_ptr<AST::SlicePatternItemsHasRest> items ( + new AST::SlicePatternItemsHasRest ( + std::move (patterns), std::move (upper_patterns.value ()))); + return std::unique_ptr<AST::SlicePattern> ( + new AST::SlicePattern (std::move (items), square_locus)); + } + + // Rest-less slice pattern + std::unique_ptr<AST::SlicePatternItemsNoRest> items ( + new AST::SlicePatternItemsNoRest (std::move (patterns))); return std::unique_ptr<AST::SlicePattern> ( - new AST::SlicePattern (std::move (patterns), square_locus)); + new AST::SlicePattern (std::move (items), square_locus)); } /* Parses an identifier pattern (pattern that binds a value matched to a @@ -10979,7 +11158,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () { case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple struct lexer.skip_token (); @@ -11012,7 +11192,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () return std::unique_ptr<AST::TupleStructPattern> ( new AST::TupleStructPattern (std::move (path), std::move (items))); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct lexer.skip_token (); @@ -11033,7 +11214,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () } case DOT_DOT_EQ: case DOT_DOT: - case ELLIPSIS: { + case ELLIPSIS: + { // range AST::RangeKind kind = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); @@ -11050,7 +11232,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () std::move (upper_bound), kind, t->get_locus ())); } - case PATTERN_BIND: { + case PATTERN_BIND: + { // only allow on single-segment paths if (path.is_single_segment ()) { @@ -11188,7 +11371,8 @@ Parser<ManagedTokenSource>::parse_tuple_struct_items () case RIGHT_PAREN: return std::unique_ptr<AST::TupleStructItemsNoRange> ( new AST::TupleStructItemsNoRange (std::move (lower_patterns))); - case DOT_DOT: { + case DOT_DOT: + { // has an upper range that must be parsed separately lexer.skip_token (); @@ -11308,7 +11492,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case INT_LITERAL: { + case INT_LITERAL: + { // tuple index std::string index_str = t->get_str (); int index = atoi (index_str.c_str ()); @@ -11342,7 +11527,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( // branch on next token switch (lexer.peek_token (1)->get_id ()) { - case COLON: { + case COLON: + { // identifier-pattern Identifier ident{t}; lexer.skip_token (); @@ -11367,7 +11553,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( t->get_locus ())); } case COMMA: - case RIGHT_CURLY: { + case RIGHT_CURLY: + { // identifier only Identifier ident = {t}; lexer.skip_token (); @@ -11386,7 +11573,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( return nullptr; } case REF: - case MUT: { + case MUT: + { // only identifier bool has_ref = false; if (t->get_id () == REF) @@ -11458,7 +11646,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () t = lexer.peek_token (); switch (t->get_id ()) { - case LET: { + case LET: + { // let statement std::unique_ptr<AST::LetStmt> stmt ( parse_let_stmt (std::move (outer_attrs))); @@ -11476,42 +11665,48 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () case STATIC_KW: case AUTO: case TRAIT: - case IMPL: { + case IMPL: + { std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } - /* TODO: implement union keyword but not really because of - * context-dependence crappy hack way to parse a union written below to - * separate it from the good code. */ - // case UNION: - case UNSAFE: { // maybe - unsafe traits are a thing + /* TODO: implement union keyword but not really because of + * context-dependence crappy hack way to parse a union written below to + * separate it from the good code. */ + // case UNION: + case UNSAFE: + { // maybe - unsafe traits are a thing /* if any of these (should be all possible VisItem prefixes), parse a * VisItem - can't parse item because would require reparsing outer * attributes */ const_TokenPtr t2 = lexer.peek_token (1); switch (t2->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // unsafe block: parse as expression expr = parse_expr (std::move (outer_attrs), restrictions); break; } case AUTO: - case TRAIT: { + case TRAIT: + { // unsafe trait std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } case EXTERN_KW: - case FN_KW: { + case FN_KW: + { // unsafe function std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } - case IMPL: { + case IMPL: + { // unsafe trait impl std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); @@ -11556,7 +11751,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { AST::PathInExpression path = parse_path_in_expression (); std::unique_ptr<AST::Expr> null_denotation; @@ -11680,7 +11876,8 @@ Parser<ManagedTokenSource>::parse_struct_expr_field () std::move (outer_attrs), t->get_locus ())); } - case INT_LITERAL: { + case INT_LITERAL: + { // parse tuple index field int index = atoi (t->get_str ().c_str ()); lexer.skip_token (); @@ -11725,11 +11922,12 @@ Parser<ManagedTokenSource>::parse_struct_expr_field () } // "Unexpected token" panic mode - flags gcc error at unexpected token +// TODO: seems to be unused, remove? template <typename ManagedTokenSource> void Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t) { - Error error (t->get_locus (), "unexpected token %qs\n", + Error error (t->get_locus (), "unexpected token %qs", t->get_token_description ()); add_error (std::move (error)); } @@ -11920,7 +12118,7 @@ Parser<ManagedTokenSource>::skip_after_end_attribute () { const_TokenPtr t = lexer.peek_token (); - while (t->get_id () != RIGHT_SQUARE) + while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE) { lexer.skip_token (); t = lexer.peek_token (); @@ -12050,7 +12248,8 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, case SELF_ALIAS: case DOLLAR_SIGN: case CRATE: - case SUPER: { + case SUPER: + { // DEBUG rust_debug ("beginning null denotation identifier handling"); @@ -12061,7 +12260,8 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, return null_denotation_path (std::move (path), std::move (outer_attrs), restrictions); } - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // TODO: fix: this is for global paths, i.e. std::string::whatever Error error (tok->get_locus (), "found null denotation scope resolution operator, and " @@ -12103,7 +12303,8 @@ Parser<ManagedTokenSource>::null_denotation_path ( // macro return parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); - case LEFT_CURLY: { + case LEFT_CURLY: + { bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER && (lexer.peek_token (2)->get_id () == COMMA || (lexer.peek_token (2)->get_id () == COLON @@ -12179,7 +12380,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( { // FIXME: Handle in null_denotation_path? case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path // HACK: add outer attrs to path AST::QualifiedPathInExpression path @@ -12237,23 +12439,24 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( return parse_grouped_or_tuple_expr (std::move (outer_attrs), tok->get_locus ()); - /*case PLUS: { // unary plus operator - // invoke parse_expr recursively with appropriate priority, etc. for - below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); + /*case PLUS: { // unary plus operator + // invoke parse_expr recursively with appropriate priority, etc. for + below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); - if (expr == nullptr) - return nullptr; - // can only apply to integer and float expressions - if (expr->get_type() != integer_type_node || expr->get_type() != - float_type_node) { rust_error_at(tok->get_locus(), "operand of unary - plus must be int or float but it is %s", print_type(expr->get_type())); - return nullptr; - } + if (expr == nullptr) + return nullptr; + // can only apply to integer and float expressions + if (expr->get_type() != integer_type_node || expr->get_type() != + float_type_node) { rust_error_at(tok->get_locus(), "operand of unary + plus must be int or float but it is %s", print_type(expr->get_type())); + return nullptr; + } - return Tree(expr, tok->get_locus()); - }*/ - // Rust has no unary plus operator - case MINUS: { // unary minus + return Tree(expr, tok->get_locus()); + }*/ + // Rust has no unary plus operator + case MINUS: + { // unary minus ParseRestrictions entered_from_unary; entered_from_unary.entered_from_unary = true; if (!restrictions.can_be_struct_expr) @@ -12280,7 +12483,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE, std::move (outer_attrs), tok->get_locus ())); } - case EXCLAM: { // logical or bitwise not + case EXCLAM: + { // logical or bitwise not ParseRestrictions entered_from_unary; entered_from_unary.entered_from_unary = true; if (!restrictions.can_be_struct_expr) @@ -12305,7 +12509,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::NegationExpr (std::move (expr), NegationOperator::NOT, std::move (outer_attrs), tok->get_locus ())); } - case ASTERISK: { + case ASTERISK: + { /* pointer dereference only - HACK: as struct expressions should * always be value expressions, cannot be dereferenced */ ParseRestrictions entered_from_unary; @@ -12318,7 +12523,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs), tok->get_locus ())); } - case AMP: { + case AMP: + { // (single) "borrow" expression - shared (mutable) or immutable std::unique_ptr<AST::Expr> expr = nullptr; Mutability mutability = Mutability::Imm; @@ -12375,7 +12581,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false, std::move (outer_attrs), tok->get_locus ())); } - case LOGICAL_AND: { + case LOGICAL_AND: + { // (double) "borrow" expression - shared (mutable) or immutable std::unique_ptr<AST::Expr> expr = nullptr; Mutability mutability = Mutability::Imm; @@ -12414,6 +12621,9 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( case RETURN_KW: // FIXME: is this really a null denotation expression? return parse_return_expr (std::move (outer_attrs), tok->get_locus ()); + case TRY: + // FIXME: is this really a null denotation expression? + return parse_try_expr (std::move (outer_attrs), tok->get_locus ()); case BREAK: // FIXME: is this really a null denotation expression? return parse_break_expr (std::move (outer_attrs), tok->get_locus ()); @@ -12469,6 +12679,9 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( "use of %qs is not allowed on the right-side of an assignment", tok->get_token_description ())); return nullptr; + case CONST: + return parse_const_block_expr (std::move (outer_attrs), + tok->get_locus ()); default: if (!restrictions.expr_can_be_null) add_error (Error (tok->get_locus (), @@ -12491,8 +12704,9 @@ Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, // Token passed in has already been skipped, so peek gives "next" token switch (tok->get_id ()) { - // FIXME: allow for outer attributes to be applied - case QUESTION_MARK: { + // FIXME: allow for outer attributes to be applied + case QUESTION_MARK: + { location_t left_locus = left->get_locus (); // error propagation expression - unary postfix return std::unique_ptr<AST::ErrorPropagationExpr> ( @@ -12746,7 +12960,8 @@ Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, "function - this should probably be handled elsewhere")); return nullptr; - case DOT: { + case DOT: + { /* field expression or method call - relies on parentheses after next * identifier or await if token after is "await" (unary postfix) or * tuple index if token after is a decimal int literal */ @@ -14062,7 +14277,8 @@ Parser<ManagedTokenSource>::parse_struct_expr_struct_partial ( * algorithm should work too. As such, AST type not happening. */ case IDENTIFIER: case HASH: - case INT_LITERAL: { + case INT_LITERAL: + { // struct with struct expr fields // parse struct expr fields @@ -14359,7 +14575,8 @@ Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok, case OR: // no parameters, don't skip token break; - case PIPE: { + case PIPE: + { // actually may have parameters // don't skip token const_TokenPtr t = lexer.peek_token (); diff --git a/gcc/rust/parse/rust-parse.cc b/gcc/rust/parse/rust-parse.cc index 43d15aa..860fd11 100644 --- a/gcc/rust/parse/rust-parse.cc +++ b/gcc/rust/parse/rust-parse.cc @@ -42,8 +42,7 @@ extract_module_path (const AST::AttrVec &inner_attrs, { rust_error_at ( path_attr.get_locus (), - // Split the format string so that -Wformat-diag does not complain... - "path attributes must contain a filename: '%s'", "#![path = \"file\"]"); + "path attributes must contain a filename: %<#[path = \"file\"]%>"); return name; } @@ -67,8 +66,7 @@ extract_module_path (const AST::AttrVec &inner_attrs, { rust_error_at ( path_attr.get_locus (), - // Split the format string so that -Wformat-diag does not complain... - "path attributes must contain a filename: '%s'", "#[path = \"file\"]"); + "path attributes must contain a filename: %<#[path = \"file\"]%>"); return name; } @@ -80,6 +78,15 @@ extract_module_path (const AST::AttrVec &inner_attrs, // a character that is not an equal sign or whitespace auto filename_begin = path_value.find_first_not_of ("=\t "); + // If the path consists of only whitespace, then we have an error + if (filename_begin == std::string::npos) + { + rust_error_at ( + path_attr.get_locus (), + "path attributes must contain a filename: %<#[path = \"file\"]%>"); + return name; + } + auto path = path_value.substr (filename_begin); // On windows, the path might mix '/' and '\' separators. Replace the @@ -144,10 +151,9 @@ peculiar_fragment_match_compatible_fragment ( = contains (fragment_follow_set[last_spec.get_kind ()], spec.get_kind ()); if (!is_valid) - rust_error_at ( - match_locus, - "fragment specifier %qs is not allowed after %qs fragments", - spec.as_string ().c_str (), last_spec.as_string ().c_str ()); + rust_error_at (match_locus, + "fragment specifier %qs is not allowed after %qs fragments", + spec.as_string ().c_str (), last_spec.as_string ().c_str ()); return is_valid; } @@ -244,7 +250,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, // the error. switch (match.get_macro_match_type ()) { - case AST::MacroMatch::Tok: { + case AST::MacroMatch::Tok: + { auto tok = static_cast<const AST::Token *> (&match); if (contains (allowed_toks, tok->get_id ())) return true; @@ -254,7 +261,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, break; } break; - case AST::MacroMatch::Repetition: { + case AST::MacroMatch::Repetition: + { auto repetition = static_cast<const AST::MacroMatchRepetition *> (&match); auto &matches = repetition->get_matches (); @@ -263,7 +271,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, return peculiar_fragment_match_compatible (last_match, *first_frag); break; } - case AST::MacroMatch::Matcher: { + case AST::MacroMatch::Matcher: + { auto matcher = static_cast<const AST::MacroMatcher *> (&match); auto first_token = matcher->get_delim_type (); TokenId delim_id; @@ -289,7 +298,8 @@ peculiar_fragment_match_compatible (const AST::MacroMatchFragment &last_match, error_locus = matcher->get_match_locus (); break; } - case AST::MacroMatch::Fragment: { + case AST::MacroMatch::Fragment: + { auto last_spec = last_match.get_frag_spec (); auto fragment = static_cast<const AST::MacroMatchFragment *> (&match); if (last_spec.has_follow_set_fragment_restrictions ()) @@ -328,10 +338,11 @@ is_match_compatible (const AST::MacroMatch &last_match, switch (last_match.get_macro_match_type ()) { - // This is our main stop condition: When we are finally looking at the - // last match (or its actual last component), and it is a fragment, it - // may contain some follow up restrictions. - case AST::MacroMatch::Fragment: { + // This is our main stop condition: When we are finally looking at the + // last match (or its actual last component), and it is a fragment, it + // may contain some follow up restrictions. + case AST::MacroMatch::Fragment: + { auto fragment = static_cast<const AST::MacroMatchFragment *> (&last_match); if (fragment->get_frag_spec ().has_follow_set_restrictions ()) @@ -339,7 +350,8 @@ is_match_compatible (const AST::MacroMatch &last_match, else return true; } - case AST::MacroMatch::Repetition: { + case AST::MacroMatch::Repetition: + { // A repetition on the left hand side means we want to make sure the // last match of the repetition is compatible with the new match auto repetition diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 827d91d..8253885 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -17,6 +17,7 @@ along with GCC; see the file COPYING3. If not see #ifndef RUST_PARSE_H #define RUST_PARSE_H +#include "rust-ast.h" #include "rust-item.h" #include "rust-lex.h" #include "rust-ast-full.h" @@ -33,12 +34,19 @@ class ParseLifetimeParamError class ParseLifetimeError { }; + +enum class AnonConstError +{ + InvalidSizeExpr, +}; + enum class ParseLoopLabelError { NOT_LOOP_LABEL, MISSING_COLON, }; -enum ParseSelfError + +enum class ParseSelfError { SELF_PTR, PARSING, @@ -165,6 +173,12 @@ public: tl::optional<AST::LoopLabel> = tl::nullopt, location_t pratt_parsed_loc = UNKNOWN_LOCATION); + tl::expected<AST::AnonConst, AnonConstError> parse_anon_const (); + + std::unique_ptr<AST::ConstBlock> + parse_const_block_expr (AST::AttrVec outer_attrs = AST::AttrVec (), + location_t loc = UNKNOWN_LOCATION); + bool is_macro_rules_def (const_TokenPtr t); std::unique_ptr<AST::Item> parse_item (bool called_from_statement); std::unique_ptr<AST::Pattern> parse_pattern (); @@ -222,7 +236,7 @@ private: // Path-related AST::SimplePath parse_simple_path (); - AST::SimplePathSegment parse_simple_path_segment (); + AST::SimplePathSegment parse_simple_path_segment (int base_peek = 0); AST::TypePath parse_type_path (); std::unique_ptr<AST::TypePathSegment> parse_type_path_segment (); AST::PathIdentSegment parse_path_ident_segment (); @@ -644,6 +658,9 @@ private: std::unique_ptr<AST::ReturnExpr> parse_return_expr (AST::AttrVec outer_attrs = AST::AttrVec (), location_t pratt_parsed_loc = UNKNOWN_LOCATION); + std::unique_ptr<AST::TryExpr> + parse_try_expr (AST::AttrVec outer_attrs = AST::AttrVec (), + location_t pratt_parsed_loc = UNKNOWN_LOCATION); std::unique_ptr<AST::BreakExpr> parse_break_expr (AST::AttrVec outer_attrs = AST::AttrVec (), location_t pratt_parsed_loc = UNKNOWN_LOCATION); @@ -762,11 +779,15 @@ private: } ~InlineModuleStackScope () { parser.inline_module_stack.pop_back (); } }; + + // don't want to make things *only* AttributeParser uses public + // TODO: fold more of AttributeParser into Parser? + friend class ::Rust::AST::AttributeParser; }; -std::string -extract_module_path (const AST::AttrVec &inner_attrs, - const AST::AttrVec &outer_attrs, const std::string &name); +std::string extract_module_path (const AST::AttrVec &inner_attrs, + const AST::AttrVec &outer_attrs, + const std::string &name); /** * Check if a MacroMatch is allowed to follow the last parsed MacroMatch. @@ -776,12 +797,8 @@ extract_module_path (const AST::AttrVec &inner_attrs, * * @return true if the follow-up is valid, false otherwise */ -bool -is_match_compatible (const AST::MacroMatch &last_match, - const AST::MacroMatch ¤t_match); +bool is_match_compatible (const AST::MacroMatch &last_match, + const AST::MacroMatch ¤t_match); } // namespace Rust -// as now template, include implementations of all methods -#include "rust-parse-impl.h" - #endif // RUST_PARSE_H diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index b781ce33..3c7b425 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -116,7 +116,7 @@ ResolverBase::visit (AST::MetaItemLitExpr &) {} void -ResolverBase::visit (AST::MetaItemPathLit &) +ResolverBase::visit (AST::MetaItemPathExpr &) {} void @@ -232,6 +232,14 @@ ResolverBase::visit (AST::BlockExpr &) {} void +ResolverBase::visit (AST::AnonConst &) +{} + +void +ResolverBase::visit (AST::ConstBlock &) +{} + +void ResolverBase::visit (AST::ClosureExprInnerTyped &) {} @@ -276,6 +284,10 @@ ResolverBase::visit (AST::ReturnExpr &) {} void +ResolverBase::visit (AST::TryExpr &) +{} + +void ResolverBase::visit (AST::UnsafeBlockExpr &) {} @@ -572,6 +584,14 @@ ResolverBase::visit (AST::GroupedPattern &) {} void +ResolverBase::visit (AST::SlicePatternItemsNoRest &) +{} + +void +ResolverBase::visit (AST::SlicePatternItemsHasRest &) +{} + +void ResolverBase::visit (AST::SlicePattern &) {} @@ -663,5 +683,9 @@ void ResolverBase::visit (AST::FormatArgs &fmt) {} +void +ResolverBase::visit (AST::OffsetOf &offset_of) +{} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index 5bb9e4f..89c5c35 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -21,6 +21,8 @@ #include "rust-ast-visitor.h" #include "rust-ast.h" +#include "rust-builtin-ast-nodes.h" +#include "rust-expr.h" #include "rust-name-resolver.h" #include "rust-diagnostics.h" #include "rust-location.h" @@ -56,7 +58,7 @@ public: void visit (AST::AttrInputLiteral &); void visit (AST::AttrInputMacro &); void visit (AST::MetaItemLitExpr &); - void visit (AST::MetaItemPathLit &); + void visit (AST::MetaItemPathExpr &); void visit (AST::BorrowExpr &); void visit (AST::DereferenceExpr &); void visit (AST::ErrorPropagationExpr &); @@ -85,6 +87,8 @@ public: void visit (AST::FieldAccessExpr &); void visit (AST::ClosureExprInner &); void visit (AST::BlockExpr &); + void visit (AST::AnonConst &); + void visit (AST::ConstBlock &); void visit (AST::ClosureExprInnerTyped &); void visit (AST::ContinueExpr &); void visit (AST::BreakExpr &); @@ -96,6 +100,7 @@ public: void visit (AST::RangeToInclExpr &); void visit (AST::BoxExpr &); void visit (AST::ReturnExpr &); + void visit (AST::TryExpr &); void visit (AST::UnsafeBlockExpr &); void visit (AST::LoopExpr &); void visit (AST::WhileLoopExpr &); @@ -181,6 +186,8 @@ public: void visit (AST::TuplePatternItemsRanged &); void visit (AST::TuplePattern &); void visit (AST::GroupedPattern &); + void visit (AST::SlicePatternItemsNoRest &); + void visit (AST::SlicePatternItemsHasRest &); void visit (AST::SlicePattern &); void visit (AST::AltPattern &); @@ -207,6 +214,7 @@ public: void visit (AST::SelfParam ¶m); void visit (AST::FormatArgs &fmt); + void visit (AST::OffsetOf &offset_of); protected: ResolverBase () diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 5524e18..a410193 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -315,6 +315,18 @@ ResolveExpr::visit (AST::BlockExpr &expr) } void +ResolveExpr::visit (AST::AnonConst &expr) +{ + ResolveExpr::go (expr.get_inner_expr (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::ConstBlock &expr) +{ + ResolveExpr::go (expr.get_const_expr (), prefix, canonical_prefix); +} + +void translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, const CanonicalPath &canonical_prefix) { @@ -324,38 +336,46 @@ translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix, { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { auto in = operand.get_in (); ResolveExpr::go (*in.expr, prefix, canonical_prefix); break; } - case RegisterType::Out: { + case RegisterType::Out: + { auto out = operand.get_out (); ResolveExpr::go (*out.expr, prefix, canonical_prefix); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { auto in_out = operand.get_in_out (); ResolveExpr::go (*in_out.expr, prefix, canonical_prefix); break; } - case RegisterType::SplitInOut: { + case RegisterType::SplitInOut: + { auto split_in_out = operand.get_split_in_out (); ResolveExpr::go (*split_in_out.in_expr, prefix, canonical_prefix); ResolveExpr::go (*split_in_out.out_expr, prefix, canonical_prefix); break; } - case RegisterType::Const: { + case RegisterType::Const: + { auto anon_const = operand.get_const ().anon_const; - ResolveExpr::go (*anon_const.expr, prefix, canonical_prefix); + ResolveExpr::go (anon_const.get_inner_expr (), prefix, + canonical_prefix); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { auto sym = operand.get_sym (); ResolveExpr::go (*sym.expr, prefix, canonical_prefix); break; } - case RegisterType::Label: { + case RegisterType::Label: + { auto label = operand.get_label (); ResolveExpr::go (*label.expr, prefix, canonical_prefix); break; @@ -766,7 +786,7 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) resolver->push_closure_context (expr.get_node_id ()); - ResolveExpr::go (expr.get_definition_block (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_definition_expr (), prefix, canonical_prefix); resolver->pop_closure_context (); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index b296d66..aad1605 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -56,6 +56,8 @@ public: void visit (AST::IfLetExpr &expr) override; void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; + void visit (AST::AnonConst &expr) override; + void visit (AST::ConstBlock &expr) override; void visit (AST::InlineAsm &expr) override; void visit (AST::LlvmInlineAsm &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index 30f6d43..1d5ebed 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -453,7 +453,8 @@ ResolveItem::visit (AST::ConstantItem &constant) resolve_visibility (constant.get_visibility ()); ResolveType::go (constant.get_type ()); - ResolveExpr::go (constant.get_expr (), path, cpath); + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr (), path, cpath); } void @@ -608,10 +609,7 @@ ResolveItem::visit (AST::InherentImpl &impl_block) } else { - std::string seg_buf = "<impl " + self_cpath.get () + ">"; - CanonicalPath seg - = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); - cpath = canonical_prefix.append (seg); + cpath = canonical_prefix.append (impl_type_seg); } // done setup paths @@ -732,13 +730,7 @@ ResolveItem::visit (AST::TraitImpl &impl_block) } else { - std::string projection_str = canonical_projection.get (); - std::string seg_buf - = "<impl " + projection_str.substr (1, projection_str.size () - 2) - + ">"; - CanonicalPath seg - = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); - cpath = canonical_prefix.append (seg); + cpath = canonical_prefix.append (canonical_projection); } // DONE setup canonical-path @@ -838,29 +830,32 @@ ResolveItem::resolve_extern_item (AST::ExternalItem &item) ResolveExternItem::go (item, prefix, canonical_prefix); } -static void -flatten_glob (const AST::UseTreeGlob &glob, std::vector<Import> &imports); -static void -flatten_rebind (const AST::UseTreeRebind &glob, std::vector<Import> &imports); -static void -flatten_list (const AST::UseTreeList &glob, std::vector<Import> &imports); +static void flatten_glob (const AST::UseTreeGlob &glob, + std::vector<Import> &imports); +static void flatten_rebind (const AST::UseTreeRebind &glob, + std::vector<Import> &imports); +static void flatten_list (const AST::UseTreeList &glob, + std::vector<Import> &imports); static void flatten (const AST::UseTree *tree, std::vector<Import> &imports) { switch (tree->get_kind ()) { - case AST::UseTree::Glob: { + case AST::UseTree::Glob: + { auto glob = static_cast<const AST::UseTreeGlob *> (tree); flatten_glob (*glob, imports); break; } - case AST::UseTree::Rebind: { + case AST::UseTree::Rebind: + { auto rebind = static_cast<const AST::UseTreeRebind *> (tree); flatten_rebind (*rebind, imports); break; } - case AST::UseTree::List: { + case AST::UseTree::List: + { auto list = static_cast<const AST::UseTreeList *> (tree); flatten_list (*list, imports); break; diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h index 776dd53..d31f910 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.h +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -153,8 +153,7 @@ private: #if CHECKING_P namespace selftest { -extern void -rust_simple_path_resolve_test (void); +extern void rust_simple_path_resolve_test (void); } // namespace selftest #endif // CHECKING_P diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc index ee84be8..3b80f9f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -62,6 +62,11 @@ PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type, void PatternDeclaration::visit (AST::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + pattern.get_subpattern ().accept_vis (*this); + } + Mutability mut = pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm; add_new_binding (pattern.get_ident (), pattern.get_node_id (), BindingTypeInfo (mut, pattern.get_is_ref (), @@ -94,13 +99,15 @@ PatternDeclaration::visit (AST::TupleStructPattern &pattern) AST::TupleStructItems &items = pattern.get_items (); switch (items.get_item_type ()) { - case AST::TupleStructItems::RANGE: { + case AST::TupleStructItems::RANGE: + { // TODO rust_unreachable (); } break; - case AST::TupleStructItems::NO_RANGE: { + case AST::TupleStructItems::NO_RANGE: + { auto &items_no_range = static_cast<AST::TupleStructItemsNoRange &> (items); @@ -123,7 +130,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) { switch (field->get_item_type ()) { - case AST::StructPatternField::ItemType::TUPLE_PAT: { + case AST::StructPatternField::ItemType::TUPLE_PAT: + { AST::StructPatternFieldTuplePat &tuple = static_cast<AST::StructPatternFieldTuplePat &> (*field); @@ -131,7 +139,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT_PAT: { + case AST::StructPatternField::ItemType::IDENT_PAT: + { AST::StructPatternFieldIdentPat &ident = static_cast<AST::StructPatternFieldIdentPat &> (*field); @@ -139,7 +148,8 @@ PatternDeclaration::visit (AST::StructPattern &pattern) } break; - case AST::StructPatternField::ItemType::IDENT: { + case AST::StructPatternField::ItemType::IDENT: + { auto &ident = static_cast<AST::StructPatternFieldIdent &> (*field); Mutability mut @@ -160,7 +170,8 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) auto &items = pattern.get_items (); switch (items.get_pattern_type ()) { - case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: + { auto &ref = static_cast<AST::TuplePatternItemsMultiple &> ( pattern.get_items ()); @@ -169,7 +180,8 @@ PatternDeclaration::visit (AST::TuplePattern &pattern) } break; - case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + case AST::TuplePatternItems::TuplePatternItemType::RANGED: + { auto &ref = static_cast<AST::TuplePatternItemsRanged &> (pattern.get_items ()); @@ -348,14 +360,16 @@ resolve_range_pattern_bound (AST::RangePatternBound &bound) // Nothing to resolve for a literal. break; - case AST::RangePatternBound::RangePatternBoundType::PATH: { + case AST::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast<AST::RangePatternBoundPath &> (bound); ResolvePath::go (ref.get_path ()); } break; - case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast<AST::RangePatternBoundQualPath &> (bound); ResolvePath::go (ref.get_qualified_path ()); @@ -374,9 +388,30 @@ PatternDeclaration::visit (AST::RangePattern &pattern) void PatternDeclaration::visit (AST::SlicePattern &pattern) { - for (auto &p : pattern.get_items ()) + auto &items = pattern.get_items (); + switch (items.get_pattern_type ()) { - p->accept_vis (*this); + case AST::SlicePatternItems::SlicePatternItemType::NO_REST: + { + auto &ref + = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ()); + + for (auto &p : ref.get_patterns ()) + p->accept_vis (*this); + } + break; + + case AST::SlicePatternItems::SlicePatternItemType::HAS_REST: + { + auto &ref + = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ()); + + for (auto &p : ref.get_lower_patterns ()) + p->accept_vis (*this); + for (auto &p : ref.get_upper_patterns ()) + p->accept_vis (*this); + } + break; } } diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h index d413a7c..d714511 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -67,7 +67,8 @@ public: }); ResolveType::go (constant.get_type ()); - ResolveExpr::go (constant.get_expr (), prefix, canonical_prefix); + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr (), prefix, canonical_prefix); } void visit (AST::LetStmt &stmt) override diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 8fd69c3..a040228 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -140,7 +140,7 @@ ResolveType::visit (AST::ImplTraitType &type) void ResolveType::visit (AST::ImplTraitTypeOneBound &type) { - ResolveTypeBound::go (type.get_trait_bound ()); + ResolveTypeBound::go (*type.get_trait_bound ().get ()); } // resolve relative type-paths @@ -210,7 +210,8 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) switch (segment->get_type ()) { - case AST::TypePathSegment::SegmentType::GENERIC: { + case AST::TypePathSegment::SegmentType::GENERIC: + { AST::TypePathSegmentGeneric *s = static_cast<AST::TypePathSegmentGeneric *> (segment.get ()); if (s->has_generic_args ()) @@ -509,7 +510,8 @@ ResolveTypeToCanonicalPath::visit (AST::TypePath &path) auto &final_seg = path.get_segments ().back (); switch (final_seg->get_type ()) { - case AST::TypePathSegment::SegmentType::GENERIC: { + case AST::TypePathSegment::SegmentType::GENERIC: + { AST::TypePathSegmentGeneric *s = static_cast<AST::TypePathSegmentGeneric *> (final_seg.get ()); @@ -651,7 +653,8 @@ ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type) switch (additional_bound->get_bound_type ()) { - case AST::TypeParamBound::TRAIT: { + case AST::TypeParamBound::TRAIT: + { auto bound_path = CanonicalPath::create_empty (); auto &bound_type_path diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 3e3c992..2208f70 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -24,8 +24,7 @@ #include "rust-ast-resolve-expr.h" #include "rust-ast-resolve-struct-expr-field.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Resolver { diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 480034c..f1c0e5c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -25,6 +25,21 @@ namespace Rust { namespace Resolver2_0 { void +DefaultResolver::visit (AST::Crate &crate) +{ + auto inner_fn = [this, &crate] () { AST::DefaultASTVisitor::visit (crate); }; + + auto &mappings = Analysis::Mappings::get (); + + auto crate_num = mappings.lookup_crate_num (crate.get_node_id ()); + rust_assert (crate_num.has_value ()); + auto crate_name = mappings.get_crate_name (*crate_num); + rust_assert (crate_name.has_value ()); + + ctx.canonical_ctx.scope_crate (crate.get_node_id (), *crate_name, inner_fn); +} + +void DefaultResolver::visit (AST::BlockExpr &expr) { // extracting the lambda from the `scoped` call otherwise the code looks like @@ -38,19 +53,32 @@ DefaultResolver::visit (AST::BlockExpr &expr) void DefaultResolver::visit (AST::Module &module) { - auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; + auto item_fn_1 + = [this, &module] () { AST::DefaultASTVisitor::visit (module); }; + + auto item_fn_2 = [this, &module, &item_fn_1] () { + ctx.canonical_ctx.scope (module.get_node_id (), module.get_name (), + std::move (item_fn_1)); + }; - ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn, + ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn_2, module.get_name ()); } void DefaultResolver::visit (AST::Function &function) { - auto def_fn + auto def_fn_1 = [this, &function] () { AST::DefaultASTVisitor::visit (function); }; - ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn); + auto def_fn_2 = [this, &function, &def_fn_1] () { + ctx.canonical_ctx.scope (function.get_node_id (), + function.get_function_name (), + std::move (def_fn_1)); + }; + + ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn_2, + function.get_function_name ()); } void @@ -61,73 +89,252 @@ DefaultResolver::visit (AST::ForLoopExpr &expr) } void -DefaultResolver::visit (AST::Trait &trait) +DefaultResolver::visit_if_let_patterns (AST::IfLetExpr &expr) +{ + for (auto &pattern : expr.get_patterns ()) + visit (pattern); +} + +void +DefaultResolver::visit (AST::IfLetExpr &expr) { - auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); }; + auto inner_vis = [this, &expr] () { + visit_if_let_patterns (expr); + visit (expr.get_if_block ()); + }; + + visit_outer_attrs (expr); + + visit (expr.get_value_expr ()); + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_vis); +} + +void +DefaultResolver::visit (AST::IfLetExprConseqElse &expr) +{ + DefaultResolver::visit (static_cast<AST::IfLetExpr &> (expr)); + visit (expr.get_else_block ()); +} - ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn, +void +DefaultResolver::visit (AST::Trait &trait) +{ + visit_outer_attrs (trait); + visit (trait.get_visibility ()); + visit_inner_attrs (trait); + + auto inner_fn_1 = [this, &trait] () { + for (auto &item : trait.get_trait_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &trait, &inner_fn_1] () { + visit (trait.get_implicit_self ()); + for (auto &generic : trait.get_generic_params ()) + visit (generic); + if (trait.has_where_clause ()) + visit (trait.get_where_clause ()); + for (auto &bound : trait.get_type_param_bounds ()) + visit (bound); + + ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &trait, &inner_fn_2] () { + ctx.canonical_ctx.scope (trait.get_node_id (), trait.get_identifier (), + std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, trait.get_node_id (), inner_fn_3, trait.get_identifier () /* FIXME: Is that valid?*/); } void DefaultResolver::visit (AST::InherentImpl &impl) { - auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + visit_outer_attrs (impl); + visit (impl.get_visibility ()); + visit_inner_attrs (impl); + + auto inner_fn_1 = [this, &impl] () { + for (auto &item : impl.get_impl_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &impl, &inner_fn_1] () { + maybe_insert_big_self (impl); + for (auto &generic : impl.get_generic_params ()) + visit (generic); + if (impl.has_where_clause ()) + visit (impl.get_where_clause ()); + visit_impl_type (impl.get_type ()); + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &impl, &inner_fn_2] () { + ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3); } void DefaultResolver::visit (AST::TraitImpl &impl) { - auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + visit_outer_attrs (impl); + visit (impl.get_visibility ()); + visit_inner_attrs (impl); + + auto inner_fn_1 = [this, &impl] () { + for (auto &item : impl.get_impl_items ()) + visit (item); + }; + + auto inner_fn_2 = [this, &impl, &inner_fn_1] () { + maybe_insert_big_self (impl); + for (auto &generic : impl.get_generic_params ()) + visit (generic); + if (impl.has_where_clause ()) + visit (impl.get_where_clause ()); + visit_impl_type (impl.get_type ()); + visit (impl.get_trait_path ()); + + ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn_1); + }; + + auto inner_fn_3 = [this, &impl, &inner_fn_2] () { + ctx.canonical_ctx.scope_impl (impl, std::move (inner_fn_2)); + }; + + ctx.scoped (Rib::Kind::Generics, impl.get_node_id (), inner_fn_3); } void DefaultResolver::visit (AST::StructStruct &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_struct_name ()); + inner_fn_2, type.get_struct_name ()); } void DefaultResolver::visit (AST::TupleStruct &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_struct_name (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_struct_name ()); + inner_fn_2, type.get_struct_name ()); +} + +void +DefaultResolver::visit (AST::EnumItem &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemTuple &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemStruct &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); +} + +void +DefaultResolver::visit (AST::EnumItemDiscriminant &item) +{ + auto inner_fn = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + inner_fn); } void DefaultResolver::visit (AST::Enum &type) { - auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - variant_fn, type.get_identifier ()); + inner_fn_2, type.get_identifier ()); } void DefaultResolver::visit (AST::Union &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_identifier (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_identifier ()); + inner_fn_2, type.get_identifier ()); } void DefaultResolver::visit (AST::TypeAlias &type) { - auto inner_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + auto inner_fn_1 = [this, &type] () { AST::DefaultASTVisitor::visit (type); }; + + auto inner_fn_2 = [this, &type, &inner_fn_1] () { + ctx.canonical_ctx.scope (type.get_node_id (), type.get_new_type_name (), + std::move (inner_fn_1)); + }; ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (), - inner_fn, type.get_new_type_name ()); + inner_fn_2, type.get_new_type_name ()); +} + +void +DefaultResolver::visit_closure_params (AST::ClosureExpr &expr) +{ + for (auto ¶m : expr.get_params ()) + visit (param); +} + +void +DefaultResolver::visit (AST::ClosureExpr &expr) +{ + auto expr_fn = [this, &expr] () { + visit_closure_params (expr); + visit (expr.get_definition_expr ()); + }; + + visit_outer_attrs (expr); + + ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), expr_fn); } void @@ -136,7 +343,7 @@ DefaultResolver::visit (AST::ClosureExprInner &expr) if (expr.is_marked_for_strip ()) return; - AST::DefaultASTVisitor::visit (expr); + visit (static_cast<AST::ClosureExpr &> (expr)); } void @@ -145,7 +352,8 @@ DefaultResolver::visit (AST::ClosureExprInnerTyped &expr) if (expr.is_marked_for_strip ()) return; - AST::DefaultASTVisitor::visit (expr); + visit (static_cast<AST::ClosureExpr &> (expr)); + visit (expr.get_return_type ()); } void @@ -160,23 +368,29 @@ DefaultResolver::visit (AST::MatchExpr &expr) void DefaultResolver::visit (AST::ConstantItem &item) { - if (item.has_expr ()) - { - auto expr_vis - = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + auto expr_vis_1 = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; - // FIXME: Why do we need a Rib here? - ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); - } + auto expr_vis_2 = [this, &item, &expr_vis_1] () { + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + std::move (expr_vis_1)); + }; + + // FIXME: Why do we need a Rib here? + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); } void DefaultResolver::visit (AST::StaticItem &item) { - auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + auto expr_vis_1 = [this, &item] () { AST::DefaultASTVisitor::visit (item); }; + + auto expr_vis_2 = [this, &item, &expr_vis_1] () { + ctx.canonical_ctx.scope (item.get_node_id (), item.get_identifier (), + std::move (expr_vis_1)); + }; // FIXME: Why do we need a Rib here? - ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); } void @@ -187,5 +401,46 @@ DefaultResolver::visit (AST::TypeParam ¶m) ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis); } +void +DefaultResolver::visit_extern_crate (AST::ExternCrate &extern_crate, + AST::Crate &crate, CrateNum num) +{ + visit (crate); +} + +void +DefaultResolver::visit (AST::ExternCrate &crate) +{ + auto &mappings = Analysis::Mappings::get (); + auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ()); + + if (!num_opt) + { + rust_error_at (crate.get_locus (), "unknown crate %qs", + crate.get_referenced_crate ().c_str ()); + return; + } + + CrateNum num = *num_opt; + + AST::Crate &referenced_crate = mappings.get_ast_crate (num); + + auto sub_visitor_1 + = [&, this] () { visit_extern_crate (crate, referenced_crate, num); }; + + auto sub_visitor_2 = [&] () { + ctx.canonical_ctx.scope_crate (referenced_crate.get_node_id (), + crate.get_referenced_crate (), + std::move (sub_visitor_1)); + }; + + if (crate.has_as_clause ()) + ctx.scoped (Rib::Kind::Module, referenced_crate.get_node_id (), + sub_visitor_2, crate.get_as_clause ()); + else + ctx.scoped (Rib::Kind::Module, referenced_crate.get_node_id (), + sub_visitor_2, crate.get_referenced_crate ()); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index 2a987ef..cf0df68 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -39,6 +39,7 @@ public: virtual ~DefaultResolver () {} + void visit (AST::Crate &) override; // First, our lexical scope expressions - these visit their sub nodes, always // these nodes create new scopes and ribs - they are often used to declare new // variables, such as a for loop's iterator, or a function's arguments @@ -46,20 +47,35 @@ public: void visit (AST::Module &) override; void visit (AST::Function &) override; void visit (AST::ForLoopExpr &expr) override; + virtual void visit_if_let_patterns (AST::IfLetExpr &expr); + void visit (AST::IfLetExpr &expr) override; + void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::Trait &) override; + // used to handle Self insertion in TopLevel + virtual void maybe_insert_big_self (AST::Impl &) {} + virtual void visit_impl_type (AST::Type &type) { visit (type); } void visit (AST::InherentImpl &) override; void visit (AST::TraitImpl &) override; void visit (AST::TypeParam &) override; + virtual void visit_extern_crate (AST::ExternCrate &, AST::Crate &, CrateNum); + void visit (AST::ExternCrate &) override; + // type dec nodes, which visit their fields or variants by default void visit (AST::StructStruct &) override; void visit (AST::TupleStruct &) override; + void visit (AST::EnumItem &) override; + void visit (AST::EnumItemTuple &) override; + void visit (AST::EnumItemStruct &) override; + void visit (AST::EnumItemDiscriminant &) override; void visit (AST::Enum &) override; void visit (AST::Union &) override; void visit (AST::TypeAlias &) override; // Visitors that visit their expression node(s) + virtual void visit_closure_params (AST::ClosureExpr &); + virtual void visit (AST::ClosureExpr &); void visit (AST::ClosureExprInner &) override; void visit (AST::ClosureExprInnerTyped &) override; void visit (AST::MatchExpr &) override; diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 3390f09..4fd1dd2 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -17,8 +17,11 @@ // <http://www.gnu.org/licenses/>. #include "rust-early-name-resolver-2.0.h" -#include "rust-ast-full.h" +#include "optional.h" +#include "options.h" #include "rust-diagnostics.h" +#include "rust-hir-map.h" +#include "rust-item.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-attributes.h" #include "rust-finalize-imports-2.0.h" @@ -62,8 +65,9 @@ Early::go (AST::Crate &crate) // We now proceed with resolving macros, which can be nested in almost any // items textual_scope.push (); - for (auto &item : crate.items) - item->accept_vis (*this); + + visit (crate); + textual_scope.pop (); } @@ -74,8 +78,9 @@ Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) if (!resolved.has_value ()) return false; - auto result - = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ()); + auto result = Analysis::Mappings::get ().lookup_glob_container ( + resolved->get_node_id ()); + if (!result) return false; @@ -249,7 +254,12 @@ Early::visit (AST::Module &module) void Early::visit (AST::MacroInvocation &invoc) { - auto path = invoc.get_invoc_data ().get_path (); + auto &path = invoc.get_invoc_data ().get_path (); + + // We special case the `offset_of!()` macro if the flag is here, otherwise + // we accept whatever `offset_of!()` definition we resolved to. + auto resolve_offset_of + = flag_assume_builtin_offset_of && (path.as_string () == "offset_of"); if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin) for (auto &pending_invoc : invoc.get_pending_eager_invocations ()) @@ -272,14 +282,16 @@ Early::visit (AST::MacroInvocation &invoc) // we won't have changed `definition` from `nullopt` if there are more // than one segments in our path if (!definition.has_value ()) - definition = ctx.resolve_path (path.get_segments (), Namespace::Macros); + definition = ctx.resolve_path (path, Namespace::Macros); - // if the definition still does not have a value, then it's an error + // if the definition still does not have a value, then it's an error - unless + // we should automatically resolve offset_of!() calls if (!definition.has_value ()) { - collect_error (Error (invoc.get_locus (), ErrorCode::E0433, - "could not resolve macro invocation %qs", - path.as_string ().c_str ())); + if (!resolve_offset_of) + collect_error (Error (invoc.get_locus (), ErrorCode::E0433, + "could not resolve macro invocation %qs", + path.as_string ().c_str ())); return; } @@ -314,8 +326,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) auto traits = attr.get_traits_to_derive (); for (auto &trait : traits) { - auto definition = ctx.resolve_path (trait.get ().get_segments (), - Namespace::Macros); + auto definition + = ctx.resolve_path (trait.get (), Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -337,8 +349,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) ->lookup_builtin (name) .is_error ()) // Do not resolve builtins { - auto definition = ctx.resolve_path (attr.get_path ().get_segments (), - Namespace::Macros); + auto definition + = ctx.resolve_path (attr.get_path (), Namespace::Macros); if (!definition.has_value ()) { // FIXME: Change to proper error message @@ -350,7 +362,8 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs) auto pm_def = mappings.lookup_attribute_proc_macro_def ( definition->get_node_id ()); - rust_assert (pm_def.has_value ()); + if (!pm_def.has_value ()) + return; mappings.insert_attribute_proc_macro_invocation (attr.get_path (), pm_def.value ()); @@ -392,12 +405,12 @@ void Early::finalize_glob_import (NameResolutionContext &ctx, const Early::ImportPair &mapping) { - auto module = Analysis::Mappings::get ().lookup_ast_module ( - mapping.data.module ().get_node_id ()); - rust_assert (module); + auto container = Analysis::Mappings::get ().lookup_glob_container ( + mapping.data.container ().get_node_id ()); + + rust_assert (container); - GlobbingVisitor glob_visitor (ctx); - glob_visitor.go (module.value ()); + GlobbingVisitor (ctx).go (container.value ()); } void @@ -419,7 +432,8 @@ Early::finalize_rebind_import (const Early::ImportPair &mapping) declared_name = rebind.get_identifier ().as_string (); locus = rebind.get_identifier ().get_locus (); break; - case AST::UseTreeRebind::NewBindType::NONE: { + case AST::UseTreeRebind::NewBindType::NONE: + { const auto &segments = path.get_segments (); // We don't want to insert `self` with `use module::self` if (path.get_final_segment ().is_lower_self_seg ()) diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index e78bec0..960de0e 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -83,15 +83,15 @@ public: return ImportData (Kind::Rebind, std::move (definitions)); } - static ImportData Glob (Rib::Definition module) + static ImportData Glob (Rib::Definition container) { - return ImportData (Kind::Glob, module); + return ImportData (Kind::Glob, container); } - Rib::Definition module () const + Rib::Definition container () const { rust_assert (kind == Kind::Glob); - return glob_module; + return glob_container; } std::vector<std::pair<Rib::Definition, Namespace>> definitions () const @@ -107,8 +107,8 @@ public: : kind (kind), resolved_definitions (std::move (definitions)) {} - ImportData (Kind kind, Rib::Definition module) - : kind (kind), glob_module (module) + ImportData (Kind kind, Rib::Definition container) + : kind (kind), glob_container (container) {} // TODO: Should this be a union? @@ -117,7 +117,7 @@ public: std::vector<std::pair<Rib::Definition, Namespace>> resolved_definitions; // For Glob - Rib::Definition glob_module; + Rib::Definition glob_container; }; struct ImportPair diff --git a/gcc/rust/resolve/rust-early-name-resolver.cc b/gcc/rust/resolve/rust-early-name-resolver.cc index fc9a26c..7b365ef 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.cc +++ b/gcc/rust/resolve/rust-early-name-resolver.cc @@ -205,7 +205,7 @@ EarlyNameResolver::visit (AST::MetaItemLitExpr &) {} void -EarlyNameResolver::visit (AST::MetaItemPathLit &) +EarlyNameResolver::visit (AST::MetaItemPathExpr &) {} void diff --git a/gcc/rust/resolve/rust-early-name-resolver.h b/gcc/rust/resolve/rust-early-name-resolver.h index 26fc84d..d3c5225 100644 --- a/gcc/rust/resolve/rust-early-name-resolver.h +++ b/gcc/rust/resolve/rust-early-name-resolver.h @@ -142,7 +142,7 @@ private: virtual void visit (AST::AttrInputLiteral &attr_input); virtual void visit (AST::AttrInputMacro &attr_input); virtual void visit (AST::MetaItemLitExpr &meta_item); - virtual void visit (AST::MetaItemPathLit &meta_item); + virtual void visit (AST::MetaItemPathExpr &meta_item); virtual void visit (AST::StructExprStruct &expr); virtual void visit (AST::StructExprFieldIdentifier &field); virtual void visit (AST::StructExprStructBase &expr); diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc index b0e8651..317acb0 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.cc +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc @@ -21,19 +21,44 @@ #include "rust-hir-map.h" #include "rust-name-resolution-context.h" #include "rust-rib.h" +#include "rust-system.h" #include "rust-toplevel-name-resolver-2.0.h" namespace Rust { namespace Resolver2_0 { void -GlobbingVisitor::go (AST::Module *module) +GlobbingVisitor::go (AST::Item *container) { - for (auto &i : module->get_items ()) + switch (container->get_item_kind ()) + { + case AST::Item::Kind::Module: + visit_module_container (static_cast<AST::Module &> (*container)); + break; + case AST::Item::Kind::Enum: + visit_enum_container (static_cast<AST::Enum &> (*container)); + break; + default: + rust_unreachable (); + } +} + +void +GlobbingVisitor::visit_module_container (AST::Module &module) +{ + for (auto &i : module.get_items ()) visit (i); } void +GlobbingVisitor::visit_enum_container (AST::Enum &item) +{ + for (auto &variant : item.get_variants ()) + ctx.insert_globbed (variant->get_identifier (), variant->get_node_id (), + Namespace::Types); +} + +void GlobbingVisitor::visit (AST::Module &module) { if (module.get_visibility ().is_public ()) diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h index d587a5e..4ae1d6d 100644 --- a/gcc/rust/resolve/rust-finalize-imports-2.0.h +++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h @@ -18,6 +18,7 @@ #include "rust-ast.h" #include "rust-expr.h" +#include "rust-item.h" #include "rust-name-resolution-context.h" #include "rust-toplevel-name-resolver-2.0.h" #include "rust-early-name-resolver-2.0.h" @@ -32,7 +33,11 @@ class GlobbingVisitor : public AST::DefaultASTVisitor public: GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {} - void go (AST::Module *module); + void go (AST::Item *container); + + void visit_module_container (AST::Module &module); + void visit_enum_container (AST::Enum &item); + void visit (AST::Module &module) override; void visit (AST::MacroRulesDefinition ¯o) override; void visit (AST::Function &function) override; diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index 81468e5..75dd873 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -543,6 +543,13 @@ private: Node root; }; +enum class ResolutionMode +{ + Normal, + FromRoot, + FromExtern, // extern prelude +}; + template <Namespace N> class ForeverStack { public: @@ -672,14 +679,11 @@ public: */ template <typename S> tl::optional<Rib::Definition> resolve_path ( - const std::vector<S> &segments, bool has_opening_scope_resolution, + const std::vector<S> &segments, ResolutionMode mode, std::function<void (const S &, NodeId)> insert_segment_resolution, std::vector<Error> &collect_errors); // FIXME: Documentation - tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; - - // FIXME: Documentation tl::optional<Rib &> to_rib (NodeId rib_id); tl::optional<const Rib &> to_rib (NodeId rib_id) const; @@ -739,6 +743,9 @@ private: tl::optional<Node &> parent; // `None` only if the node is a root }; + // private overload which allows specifying a starting point + tl::optional<Rib::Definition> get (Node &start, const Identifier &name); + /* Should we keep going upon seeing a Rib? */ enum class KeepGoing { diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 069111ee..1ed87b3 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -291,12 +291,16 @@ ForeverStack<N>::update_cursor (Node &new_cursor) template <Namespace N> tl::optional<Rib::Definition> -ForeverStack<N>::get (const Identifier &name) +ForeverStack<N>::get (Node &start, const Identifier &name) { tl::optional<Rib::Definition> resolved_definition = tl::nullopt; // TODO: Can we improve the API? have `reverse_iter` return an optional? - reverse_iter ([&resolved_definition, &name] (Node ¤t) { + reverse_iter (start, [&resolved_definition, &name] (Node ¤t) { + // we can't reference associated types/functions like this + if (current.rib.kind == Rib::Kind::TraitOrImpl) + return KeepGoing::Yes; + auto candidate = current.rib.get (name.as_string ()); return candidate.map_or ( @@ -320,6 +324,13 @@ ForeverStack<N>::get (const Identifier &name) template <Namespace N> tl::optional<Rib::Definition> +ForeverStack<N>::get (const Identifier &name) +{ + return get (cursor (), name); +} + +template <Namespace N> +tl::optional<Rib::Definition> ForeverStack<N>::get_lang_prelude (const Identifier &name) { return lang_prelude.rib.get (name.as_string ()); @@ -542,6 +553,14 @@ ForeverStack<N>::resolve_segments ( bool searched_prelude = false; while (true) { + if (is_start (iterator, segments) + && current_node->rib.kind == Rib::Kind::TraitOrImpl) + { + // we can't reference associated types/functions like this + current_node = ¤t_node->parent.value (); + continue; + } + // may set the value of child for (auto &kv : current_node->children) { @@ -625,88 +644,158 @@ template <Namespace N> template <typename S> tl::optional<Rib::Definition> ForeverStack<N>::resolve_path ( - const std::vector<S> &segments, bool has_opening_scope_resolution, + const std::vector<S> &segments, ResolutionMode mode, std::function<void (const S &, NodeId)> insert_segment_resolution, std::vector<Error> &collect_errors) { - // TODO: What to do if segments.empty() ? + rust_assert (!segments.empty ()); - // handle paths with opening scopes - std::function<void (void)> cleanup_current = [] () {}; - if (has_opening_scope_resolution) + std::reference_wrapper<Node> starting_point = cursor (); + switch (mode) { - Node *last_current = &cursor_reference.get (); - if (get_rust_edition () == Edition::E2015) - cursor_reference = root; - else - cursor_reference = extern_prelude; - cleanup_current - = [this, last_current] () { cursor_reference = *last_current; }; + case ResolutionMode::Normal: + break; // default + case ResolutionMode::FromRoot: + starting_point = root; + break; + case ResolutionMode::FromExtern: + starting_point = extern_prelude; + break; + default: + rust_unreachable (); } // if there's only one segment, we just use `get` if (segments.size () == 1) { - auto &seg = segments.front (); - if (auto lang_item = unwrap_segment_get_lang_item (seg)) + auto &outer_seg = segments.front (); + if (auto lang_item = unwrap_segment_get_lang_item (outer_seg)) { NodeId seg_id = Analysis::Mappings::get ().get_lang_item_node ( lang_item.value ()); - insert_segment_resolution (seg, seg_id); - cleanup_current (); + insert_segment_resolution (outer_seg, seg_id); // TODO: does NonShadowable matter? return Rib::Definition::NonShadowable (seg_id); } + auto &seg = unwrap_type_segment (outer_seg); + tl::optional<Rib::Definition> res - = get (unwrap_type_segment (segments.back ()).as_string ()); + = get (starting_point.get (), seg.as_string ()); if (!res) - res = get_lang_prelude ( - unwrap_type_segment (segments.back ()).as_string ()); + res = get_lang_prelude (seg.as_string ()); + + if (N == Namespace::Types && !res) + { + if (seg.is_crate_path_seg ()) + { + insert_segment_resolution (outer_seg, root.id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (root.id); + } + else if (seg.is_lower_self_seg ()) + { + NodeId id = find_closest_module (starting_point.get ()).id; + insert_segment_resolution (outer_seg, id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else if (seg.is_super_path_seg ()) + { + Node &closest_module + = find_closest_module (starting_point.get ()); + if (closest_module.is_root ()) + { + rust_error_at (seg.get_locus (), ErrorCode::E0433, + "too many leading %<super%> keywords"); + return tl::nullopt; + } + + NodeId id + = find_closest_module (closest_module.parent.value ()).id; + insert_segment_resolution (outer_seg, id); + // TODO: does NonShadowable matter? + return Rib::Definition::NonShadowable (id); + } + else + { + // HACK: check for a module after we check the language prelude + for (auto &kv : + find_closest_module (starting_point.get ()).children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg.as_string (); + }, + false)) + { + insert_segment_resolution (outer_seg, kv.second.id); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + } if (res && !res->is_ambiguous ()) - insert_segment_resolution (segments.back (), res->get_node_id ()); - cleanup_current (); + insert_segment_resolution (outer_seg, res->get_node_id ()); return res; } - std::reference_wrapper<Node> starting_point = cursor (); + return find_starting_point (segments, starting_point, + insert_segment_resolution, collect_errors) + .and_then ( + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector<S>::const_iterator iterator) { + return resolve_segments (starting_point.get (), segments, iterator, + insert_segment_resolution, collect_errors); + }) + .and_then ([this, &segments, &insert_segment_resolution] ( + Node &final_node) -> tl::optional<Rib::Definition> { + // leave resolution within impl blocks to type checker + if (final_node.rib.kind == Rib::Kind::TraitOrImpl) + return tl::nullopt; + + auto &seg = unwrap_type_segment (segments.back ()); + std::string seg_name = seg.as_string (); + + // assuming this can't be a lang item segment + tl::optional<Rib::Definition> res + = resolve_final_segment (final_node, seg_name, + seg.is_lower_self_seg ()); + // Ok we didn't find it in the rib, Lets try the prelude... + if (!res) + res = get_lang_prelude (seg_name); - auto res - = find_starting_point (segments, starting_point, insert_segment_resolution, - collect_errors) - .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution, - &collect_errors] (typename std::vector<S>::const_iterator iterator) { - return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution, collect_errors); - }) - .and_then ([this, &segments, &insert_segment_resolution] ( - Node &final_node) -> tl::optional<Rib::Definition> { - // leave resolution within impl blocks to type checker - if (final_node.rib.kind == Rib::Kind::TraitOrImpl) - return tl::nullopt; - - auto &seg = unwrap_type_segment (segments.back ()); - std::string seg_name = seg.as_string (); - - // assuming this can't be a lang item segment - tl::optional<Rib::Definition> res - = resolve_final_segment (final_node, seg_name, - seg.is_lower_self_seg ()); - // Ok we didn't find it in the rib, Lets try the prelude... - if (!res) - res = get_lang_prelude (seg_name); - - if (res && !res->is_ambiguous ()) - insert_segment_resolution (segments.back (), res->get_node_id ()); - - return res; - }); - cleanup_current (); - return res; + if (N == Namespace::Types && !res) + { + // HACK: check for a module after we check the language prelude + for (auto &kv : final_node.children) + { + auto &link = kv.first; + + if (link.path.map_or ( + [&seg_name] (Identifier path) { + auto &path_str = path.as_string (); + return path_str == seg_name; + }, + false)) + { + insert_segment_resolution (segments.back (), kv.second.id); + return Rib::Definition::NonShadowable (kv.second.id); + } + } + } + + if (res && !res->is_ambiguous ()) + insert_segment_resolution (segments.back (), res->get_node_id ()); + + return res; + }); } template <Namespace N> @@ -771,67 +860,6 @@ ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point, } template <Namespace N> -tl::optional<Resolver::CanonicalPath> -ForeverStack<N>::to_canonical_path (NodeId id) const -{ - // find the id in the current forever stack, starting from the root, - // performing either a BFS or DFS once the Node containing the ID is found, go - // back up to the root (parent().parent().parent()...) accumulate link - // segments reverse them that's your canonical path - - return dfs (root, id).map ([this, id] (ConstDfsResult tuple) { - auto containing_node = tuple.first; - auto name = tuple.second; - - auto segments = std::vector<Resolver::CanonicalPath> (); - - reverse_iter (containing_node, [&segments] (const Node ¤t) { - if (current.is_root ()) - return KeepGoing::No; - - auto children = current.parent.value ().children; - const Link *outer_link = nullptr; - - for (auto &kv : children) - { - auto &link = kv.first; - auto &child = kv.second; - - if (current.id == child.id) - { - outer_link = &link; - break; - } - } - - rust_assert (outer_link); - - outer_link->path.map ([&segments, outer_link] (Identifier path) { - segments.emplace (segments.begin (), - Resolver::CanonicalPath::new_seg (outer_link->id, - path.as_string ())); - }); - - return KeepGoing::Yes; - }); - - auto &mappings = Analysis::Mappings::get (); - CrateNum crate_num = mappings.lookup_crate_num (root.id).value (); - auto path = Resolver::CanonicalPath::new_seg ( - root.id, mappings.get_crate_name (crate_num).value ()); - path.set_crate_num (crate_num); - - for (const auto &segment : segments) - path = path.append (segment); - - // Finally, append the name - path = path.append (Resolver::CanonicalPath::new_seg (id, name)); - - return path; - }); -} - -template <Namespace N> tl::optional<Rib &> ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find) { diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index a15e17f..e39ca15 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -19,6 +19,7 @@ #include "optional.h" #include "rust-ast-full.h" #include "rust-diagnostics.h" +#include "rust-expr.h" #include "rust-hir-map.h" #include "rust-late-name-resolver-2.0.h" #include "rust-default-resolver.h" @@ -33,7 +34,9 @@ namespace Rust { namespace Resolver2_0 { -Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {} +Late::Late (NameResolutionContext &ctx) + : DefaultResolver (ctx), funny_error (false), block_big_self (false) +{} static NodeId next_node_id () @@ -114,8 +117,7 @@ Late::go (AST::Crate &crate) { setup_builtin_types (); - for (auto &item : crate.items) - item->accept_vis (*this); + visit (crate); } void @@ -140,24 +142,21 @@ Late::visit (AST::ForLoopExpr &expr) ctx.bindings.exit (); visit (expr.get_iterator_expr ()); - visit (expr.get_loop_label ()); + + if (expr.has_loop_label ()) + visit (expr.get_loop_label ()); + visit (expr.get_loop_block ()); } void -Late::visit (AST::IfLetExpr &expr) +Late::visit_if_let_patterns (AST::IfLetExpr &expr) { - visit_outer_attrs (expr); + ctx.bindings.enter (BindingSource::IfLet); - ctx.bindings.enter (BindingSource::Let); - - for (auto &pattern : expr.get_patterns ()) - visit (pattern); + DefaultResolver::visit_if_let_patterns (expr); ctx.bindings.exit (); - - visit (expr.get_value_expr ()); - visit (expr.get_if_block ()); } void @@ -214,45 +213,80 @@ Late::visit (AST::LetStmt &let) } void -Late::visit (AST::IdentifierPattern &identifier) +Late::visit (AST::WhileLetLoopExpr &while_let) +{ + DefaultASTVisitor::visit_outer_attrs (while_let); + + if (while_let.has_loop_label ()) + visit (while_let.get_loop_label ()); + + // visit expression before pattern + // this makes variable shadowing work properly + visit (while_let.get_scrutinee_expr ()); + + ctx.bindings.enter (BindingSource::WhileLet); + + for (auto &pattern : while_let.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + visit (while_let.get_loop_block ()); +} + +static void +visit_identifier_as_pattern (NameResolutionContext &ctx, + const Identifier &ident, location_t locus, + NodeId node_id, bool is_ref, bool is_mut) { // do we insert in labels or in values // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ())) + if (ctx.bindings.peek ().is_and_bound (ident)) { if (ctx.bindings.peek ().get_source () == BindingSource::Param) rust_error_at ( - identifier.get_locus (), ErrorCode::E0415, + locus, ErrorCode::E0415, "identifier %qs is bound more than once in the same parameter list", - identifier.as_string ().c_str ()); + ident.as_string ().c_str ()); else rust_error_at ( - identifier.get_locus (), ErrorCode::E0416, + locus, ErrorCode::E0416, "identifier %qs is bound more than once in the same pattern", - identifier.as_string ().c_str ()); + ident.as_string ().c_str ()); return; } - ctx.bindings.peek ().insert_ident (identifier.get_ident ()); + ctx.bindings.peek ().insert_ident (ident.as_string (), locus, is_ref, is_mut); - if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ())) + if (ctx.bindings.peek ().is_or_bound (ident)) { - // FIXME: map usage instead - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + auto res = ctx.values.get (ident); + rust_assert (res.has_value () && !res->is_ambiguous ()); + ctx.map_usage (Usage (node_id), Definition (res->get_node_id ())); } else { // We do want to ignore duplicated data because some situations rely on // it. - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + std::ignore = ctx.values.insert_shadowable (ident, node_id); } } void +Late::visit (AST::IdentifierPattern &identifier) +{ + DefaultResolver::visit (identifier); + + visit_identifier_as_pattern (ctx, identifier.get_ident (), + identifier.get_locus (), + identifier.get_node_id (), + identifier.get_is_ref (), + identifier.get_is_mut ()); +} + +void Late::visit (AST::AltPattern &pattern) { ctx.bindings.peek ().push (Binding::Kind::Or); @@ -279,9 +313,9 @@ Late::visit_function_params (AST::Function &function) void Late::visit (AST::StructPatternFieldIdent &field) { - // We do want to ignore duplicated data because some situations rely on it. - std::ignore = ctx.values.insert_shadowable (field.get_identifier (), - field.get_node_id ()); + visit_identifier_as_pattern (ctx, field.get_identifier (), field.get_locus (), + field.get_node_id (), field.is_ref (), + field.is_mut ()); } void @@ -375,7 +409,8 @@ Late::visit (AST::IdentifierExpr &expr) } else if (funny_error) { - diagnostics::text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer; + diagnostics::text_finalizer (global_dc) + = Resolver::funny_ice_text_finalizer; emit_diagnostic (diagnostics::kind::ice_nobt, expr.get_locus (), -1, "are you trying to break %s? how dare you?", expr.as_string ().c_str ()); @@ -477,6 +512,16 @@ Late::visit (AST::PathInExpression &expr) } void +Late::visit_impl_type (AST::Type &type) +{ + // TODO: does this have to handle reentrancy? + rust_assert (!block_big_self); + block_big_self = true; + visit (type); + block_big_self = false; +} + +void Late::visit (AST::TypePath &type) { // should we add type path resolution in `ForeverStack` directly? Since it's @@ -486,6 +531,16 @@ Late::visit (AST::TypePath &type) DefaultResolver::visit (type); + // prevent "impl Self {}" and similar + if (type.get_segments ().size () == 1 + && !type.get_segments ().front ()->is_lang_item () + && type.get_segments ().front ()->is_big_self_seg () && block_big_self) + { + rust_error_at (type.get_locus (), + "%<Self%> is not valid in the self type of an impl block"); + return; + } + // this *should* mostly work // TODO: make sure typepath-like path resolution (?) is working auto resolved = ctx.resolve_path (type, Namespace::Types); @@ -493,15 +548,16 @@ Late::visit (AST::TypePath &type) if (!resolved.has_value ()) { if (!ctx.lookup (type.get_segments ().front ()->get_node_id ())) - rust_error_at (type.get_locus (), "could not resolve type path %qs", - type.as_string ().c_str ()); + rust_error_at (type.get_locus (), ErrorCode::E0412, + "could not resolve type path %qs", + type.make_debug_string ().c_str ()); return; } if (resolved->is_ambiguous ()) { rust_error_at (type.get_locus (), ErrorCode::E0659, "%qs is ambiguous", - type.as_string ().c_str ()); + type.make_debug_string ().c_str ()); return; } @@ -518,6 +574,62 @@ Late::visit (AST::TypePath &type) } void +Late::visit (AST::Visibility &vis) +{ + if (!vis.has_path ()) + return; + + AST::SimplePath &path = vis.get_path (); + + rust_assert (path.get_segments ().size ()); + auto &first_seg = path.get_segments ()[0]; + + auto mode = ResolutionMode::Normal; + + if (path.has_opening_scope_resolution ()) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + else if (!first_seg.is_crate_path_seg () && !first_seg.is_super_path_seg () + && !first_seg.is_lower_self_seg ()) + { + if (get_rust_edition () == Edition::E2015) + { + mode = ResolutionMode::FromRoot; + } + else + { + rust_error_at (path.get_locus (), + "relative paths are not supported in visibilities in " + "2018 edition or later"); + return; + } + } + + auto res = ctx.resolve_path (path.get_segments (), mode, Namespace::Types); + + if (!res.has_value ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0433, + "could not resolve path %qs", path.as_string ().c_str ()); + return; + } + + // TODO: is this possible? + if (res->is_ambiguous ()) + { + rust_error_at (path.get_locus (), ErrorCode::E0659, "%qs is ambiguous", + path.as_string ().c_str ()); + return; + } + + ctx.map_usage (Usage (path.get_node_id ()), Definition (res->get_node_id ())); +} + +void Late::visit (AST::Trait &trait) { // kind of weird how this is done @@ -531,13 +643,6 @@ Late::visit (AST::Trait &trait) } void -Late::visit (AST::StructStruct &s) -{ - auto s_vis = [this, &s] () { AST::DefaultASTVisitor::visit (s); }; - ctx.scoped (Rib::Kind::Item, s.get_node_id (), s_vis); -} - -void Late::visit (AST::StructExprStruct &s) { visit_outer_attrs (s); @@ -613,51 +718,27 @@ Late::visit (AST::GenericArg &arg) DefaultResolver::visit (arg); } -template <class Closure> -static void -add_captures (Closure &closure, NameResolutionContext &ctx) -{ - auto vals = ctx.values.peek ().get_values (); - for (auto &val : vals) - { - ctx.mappings.add_capture (closure.get_node_id (), - val.second.get_node_id ()); - } -} - void -Late::visit (AST::ClosureExprInner &closure) +Late::visit_closure_params (AST::ClosureExpr &closure) { - add_captures (closure, ctx); - - visit_outer_attrs (closure); - ctx.bindings.enter (BindingSource::Param); - for (auto ¶m : closure.get_params ()) - visit (param); + DefaultResolver::visit_closure_params (closure); ctx.bindings.exit (); - - visit (closure.get_definition_expr ()); } void -Late::visit (AST::ClosureExprInnerTyped &closure) +Late::visit (AST::ClosureExpr &expr) { - add_captures (closure, ctx); - - visit_outer_attrs (closure); - - ctx.bindings.enter (BindingSource::Param); - - for (auto ¶m : closure.get_params ()) - visit (param); - - ctx.bindings.exit (); + // add captures + auto vals = ctx.values.peek ().get_values (); + for (auto &val : vals) + { + ctx.mappings.add_capture (expr.get_node_id (), val.second.get_node_id ()); + } - visit (closure.get_return_type ()); - visit (closure.get_definition_block ()); + DefaultResolver::visit (expr); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 171d9bf..95540e3 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -42,6 +42,7 @@ public: // some more label declarations void visit (AST::LetStmt &) override; + void visit (AST::WhileLetLoopExpr &) override; // TODO: Do we need this? // void visit (AST::Method &) override; void visit (AST::IdentifierPattern &) override; @@ -50,7 +51,7 @@ public: void visit (AST::SelfParam &) override; void visit (AST::MatchArm &) override; void visit (AST::ForLoopExpr &) override; - void visit (AST::IfLetExpr &) override; + void visit_if_let_patterns (AST::IfLetExpr &) override; // resolutions void visit (AST::IdentifierExpr &) override; @@ -59,16 +60,17 @@ public: void visit (AST::ContinueExpr &) override; void visit (AST::LoopLabel &) override; void visit (AST::PathInExpression &) override; + void visit_impl_type (AST::Type &) override; void visit (AST::TypePath &) override; + void visit (AST::Visibility &) override; void visit (AST::Trait &) override; void visit (AST::StructExprStruct &) override; void visit (AST::StructExprStructBase &) override; void visit (AST::StructExprStructFields &) override; - void visit (AST::StructStruct &) override; void visit (AST::GenericArgs &) override; void visit (AST::GenericArg &); - void visit (AST::ClosureExprInner &) override; - void visit (AST::ClosureExprInnerTyped &) override; + void visit_closure_params (AST::ClosureExpr &) override; + void visit (AST::ClosureExpr &) override; private: void resolve_label (AST::Lifetime &lifetime); @@ -77,6 +79,9 @@ private: void setup_builtin_types (); bool funny_error; + + /* used to prevent "impl Self {}", "impl (Self, i32) {}", etc */ + bool block_big_self; }; // TODO: Add missing mappings and data structures diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index f098e48..1b84f1d 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -33,7 +33,8 @@ BindingLayer::bind_test (Identifier ident, Binding::Kind kind) { for (auto &bind : bindings) { - if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + if (bind.idents.find (ident.as_string ()) != bind.idents.cend () + && bind.kind == kind) { return true; } @@ -60,20 +61,66 @@ BindingLayer::is_or_bound (Identifier ident) } void -BindingLayer::insert_ident (Identifier ident) +BindingLayer::insert_ident (std::string ident, location_t locus, bool is_ref, + bool is_mut) { - bindings.back ().set.insert (ident); + bindings.back ().idents.emplace ( + std::move (ident), std::make_pair (locus, IdentifierMode (is_ref, is_mut))); } void BindingLayer::merge () { - auto last_binding = bindings.back (); + auto last_binding = std::move (bindings.back ()); bindings.pop_back (); - for (auto &value : last_binding.set) + + if (bindings.back ().has_expected_bindings) + { + for (auto &value : bindings.back ().idents) + { + auto ident = value.first; + if (last_binding.idents.find (ident) == last_binding.idents.end ()) + { + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0408, + "variable %qs is not bound in all patterns", + ident.c_str ()); + } + } + } + + for (auto &value : last_binding.idents) { - bindings.back ().set.insert (value); + auto res = bindings.back ().idents.emplace (value); + if (res.second) + { + if (bindings.back ().has_expected_bindings) + { + auto &ident = value.first; + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0408, + "variable %qs is not bound in all patterns", + ident.c_str ()); + } + } + else + { + auto this_mode = value.second.second; + auto other_mode = res.first->second.second; + if (this_mode != other_mode) + { + auto &ident = value.first; + location_t locus = value.second.first; + rust_error_at (locus, ErrorCode::E0409, + "variable %qs is bound inconsistently across " + "pattern alternatives", + ident.c_str ()); + } + } } + + if (bindings.back ().kind == Binding::Kind::Or) + bindings.back ().has_expected_bindings = true; } BindingSource @@ -82,8 +129,63 @@ BindingLayer::get_source () const return source; } +Resolver::CanonicalPath +CanonicalPathRecordCrateRoot::as_path (const NameResolutionContext &) +{ + auto ret = Resolver::CanonicalPath::new_seg (node_id, seg); + ret.set_crate_num (crate_num); + return ret; +} + +Resolver::CanonicalPath +CanonicalPathRecordNormal::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append (Resolver::CanonicalPath::new_seg (node_id, seg)); +} + +Resolver::CanonicalPath +CanonicalPathRecordLookup::as_path (const NameResolutionContext &ctx) +{ + if (!cache) + { + auto res = ctx.lookup (lookup_id).and_then ( + [&ctx] (NodeId id) { return ctx.canonical_ctx.get_record_opt (id); }); + + if (!res) + { + // HACK: use a dummy value + // this should bring us roughly to parity with nr1.0 + // since nr1.0 doesn't seem to handle canonical paths for generics + // quite right anyways + return Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, "XXX"); + } + + cache = res.value (); + } + return cache->as_path (ctx); +} + +Resolver::CanonicalPath +CanonicalPathRecordImpl::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append ( + Resolver::CanonicalPath::inherent_impl_seg (impl_id, + type_record.as_path (ctx))); +} + +Resolver::CanonicalPath +CanonicalPathRecordTraitImpl::as_path (const NameResolutionContext &ctx) +{ + auto parent_path = get_parent ().as_path (ctx); + return parent_path.append ( + Resolver::CanonicalPath::trait_impl_projection_seg ( + impl_id, trait_path_record.as_path (ctx), type_record.as_path (ctx))); +} + NameResolutionContext::NameResolutionContext () - : mappings (Analysis::Mappings::get ()) + : mappings (Analysis::Mappings::get ()), canonical_ctx (*this) {} tl::expected<NodeId, DuplicateNameError> diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 19ba750..558b3ca 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -24,6 +24,7 @@ #include "rust-hir-map.h" #include "rust-rib.h" #include "rust-stacked-contexts.h" +#include "rust-item.h" namespace Rust { namespace Resolver2_0 { @@ -157,6 +158,22 @@ public: NodeId id; }; +struct IdentifierMode +{ + bool is_ref; + bool is_mut; + + IdentifierMode (bool is_ref, bool is_mut) : is_ref (is_ref), is_mut (is_mut) + {} + + bool operator== (const IdentifierMode &other) + { + return other.is_ref == is_ref && other.is_mut == is_mut; + } + + bool operator!= (const IdentifierMode &other) { return !(*this == other); } +}; + struct Binding { enum class Kind @@ -165,9 +182,12 @@ struct Binding Or, } kind; - std::unordered_set<Identifier> set; + // used to check the correctness of or-bindings + bool has_expected_bindings; - Binding (Binding::Kind kind) : kind (kind) {} + std::unordered_map<std::string, std::pair<location_t, IdentifierMode>> idents; + + Binding (Binding::Kind kind) : kind (kind), has_expected_bindings (false) {} }; /** @@ -177,6 +197,8 @@ enum class BindingSource { Match, Let, + IfLet, + WhileLet, For, /* Closure param or function param */ Param @@ -206,13 +228,256 @@ public: */ bool is_or_bound (Identifier ident); - void insert_ident (Identifier ident); + void insert_ident (std::string ident, location_t locus, bool is_ref, + bool is_mut); void merge (); BindingSource get_source () const; }; +class NameResolutionContext; +/* + * Used to handle canonical paths + * Similar to ForeverStack, but namespace independent and more specialized + */ +class CanonicalPathRecord +{ +public: + virtual Resolver::CanonicalPath as_path (const NameResolutionContext &) = 0; + + virtual bool is_root () const = 0; + + virtual ~CanonicalPathRecord () = default; +}; + +class CanonicalPathRecordWithParent : public CanonicalPathRecord +{ +public: + CanonicalPathRecordWithParent (CanonicalPathRecord &parent) : parent (&parent) + {} + + CanonicalPathRecord &get_parent () { return *parent; } + + bool is_root () const override final { return false; } + +private: + CanonicalPathRecord *parent; +}; + +class CanonicalPathRecordCrateRoot : public CanonicalPathRecord +{ +public: + CanonicalPathRecordCrateRoot (NodeId node_id, std::string seg) + : node_id (node_id), seg (std::move (seg)) + { + rust_assert (Analysis::Mappings::get ().node_is_crate (node_id)); + crate_num = Analysis::Mappings::get ().lookup_crate_num (node_id).value (); + } + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + + bool is_root () const override final { return true; } + +private: + NodeId node_id; + CrateNum crate_num; + std::string seg; +}; + +class CanonicalPathRecordNormal : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordNormal (CanonicalPathRecord &parent, NodeId node_id, + std::string seg) + : CanonicalPathRecordWithParent (parent), node_id (node_id), + seg (std::move (seg)) + { + rust_assert (!Analysis::Mappings::get ().node_is_crate (node_id)); + } + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId node_id; + std::string seg; +}; + +class CanonicalPathRecordLookup : public CanonicalPathRecord +{ +public: + CanonicalPathRecordLookup (NodeId lookup_id) + : lookup_id (lookup_id), cache (nullptr) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + + bool is_root () const override final { return true; } + +private: + NodeId lookup_id; + CanonicalPathRecord *cache; +}; + +class CanonicalPathRecordImpl : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordImpl (CanonicalPathRecord &parent, NodeId impl_id, + NodeId type_id) + : CanonicalPathRecordWithParent (parent), impl_id (impl_id), + type_record (type_id) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId impl_id; + CanonicalPathRecordLookup type_record; +}; + +class CanonicalPathRecordTraitImpl : public CanonicalPathRecordWithParent +{ +public: + CanonicalPathRecordTraitImpl (CanonicalPathRecord &parent, NodeId impl_id, + NodeId type_id, NodeId trait_path_id) + : CanonicalPathRecordWithParent (parent), impl_id (impl_id), + type_record (type_id), trait_path_record (trait_path_id) + {} + + Resolver::CanonicalPath as_path (const NameResolutionContext &) override; + +private: + NodeId impl_id; + CanonicalPathRecordLookup type_record; + CanonicalPathRecordLookup trait_path_record; +}; + +class CanonicalPathCtx +{ +public: + CanonicalPathCtx (const NameResolutionContext &ctx) + : current_record (nullptr), nr_ctx (&ctx) + {} + + Resolver::CanonicalPath get_path (NodeId id) const + { + return get_record (id).as_path (*nr_ctx); + } + + CanonicalPathRecord &get_record (NodeId id) const + { + auto it = records.find (id); + rust_assert (it != records.end ()); + return *it->second; + } + + tl::optional<CanonicalPathRecord *> get_record_opt (NodeId id) const + { + auto it = records.find (id); + if (it == records.end ()) + return tl::nullopt; + else + return it->second.get (); + } + + void insert_record (NodeId id, const Identifier &ident) + { + insert_record (id, ident.as_string ()); + } + + void insert_record (NodeId id, std::string seg) + { + rust_assert (current_record != nullptr); + + auto it = records.find (id); + if (it == records.end ()) + { + auto record = new CanonicalPathRecordNormal (*current_record, id, + std::move (seg)); + bool ok + = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record)) + .second; + rust_assert (ok); + } + } + + template <typename F> void scope (NodeId id, const Identifier &ident, F &&f) + { + scope (id, ident.as_string (), std::forward<F> (f)); + } + + template <typename F> void scope (NodeId id, std::string seg, F &&f) + { + rust_assert (current_record != nullptr); + + scope_inner (id, std::forward<F> (f), [this, id, &seg] () { + return new CanonicalPathRecordNormal (*current_record, id, + std::move (seg)); + }); + } + + template <typename F> void scope_impl (AST::InherentImpl &impl, F &&f) + { + rust_assert (current_record != nullptr); + + NodeId id = impl.get_node_id (); + scope_inner (id, std::forward<F> (f), [this, id, &impl] () { + return new CanonicalPathRecordImpl (*current_record, id, + impl.get_type ().get_node_id ()); + }); + } + + template <typename F> void scope_impl (AST::TraitImpl &impl, F &&f) + { + rust_assert (current_record != nullptr); + + NodeId id = impl.get_node_id (); + scope_inner (id, std::forward<F> (f), [this, id, &impl] () { + return new CanonicalPathRecordTraitImpl ( + *current_record, id, impl.get_type ().get_node_id (), + impl.get_trait_path ().get_node_id ()); + }); + } + + template <typename F> + void scope_crate (NodeId node_id, std::string crate_name, F &&f) + { + scope_inner (node_id, std::forward<F> (f), [node_id, &crate_name] () { + return new CanonicalPathRecordCrateRoot (node_id, std::move (crate_name)); + }); + } + +private: + template <typename FCreate, typename FCallback> + void scope_inner (NodeId id, FCallback &&f_callback, FCreate &&f_create) + { + auto it = records.find (id); + if (it == records.end ()) + { + CanonicalPathRecord *record = std::forward<FCreate> (f_create) (); + it = records.emplace (id, std::unique_ptr<CanonicalPathRecord> (record)) + .first; + } + + rust_assert (it->second->is_root () + || &static_cast<CanonicalPathRecordWithParent &> (*it->second) + .get_parent () + == current_record); + + CanonicalPathRecord *stash = it->second.get (); + std::swap (stash, current_record); + + std::forward<FCallback> (f_callback) (); + + std::swap (stash, current_record); + } + + std::unordered_map<NodeId, std::unique_ptr<CanonicalPathRecord>> records; + CanonicalPathRecord *current_record; + + const NameResolutionContext *nr_ctx; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -271,16 +536,22 @@ public: Analysis::Mappings &mappings; StackedContexts<BindingLayer> bindings; + CanonicalPathCtx canonical_ctx; + // TODO: Rename // TODO: Use newtype pattern for Usage and Definition void map_usage (Usage usage, Definition definition); tl::optional<NodeId> lookup (NodeId usage) const; + Resolver::CanonicalPath to_canonical_path (NodeId id) const + { + return canonical_ctx.get_path (id); + } + template <typename S> tl::optional<Rib::Definition> - resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector<S> &segments, ResolutionMode mode, std::vector<Error> &collect_errors, Namespace ns) { std::function<void (const S &, NodeId)> insert_segment_resolution @@ -292,17 +563,17 @@ public: switch (ns) { case Namespace::Values: - return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return values.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Types: - return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return types.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Macros: - return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return macros.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); case Namespace::Labels: - return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution, collect_errors); + return labels.resolve_path (segments, mode, insert_segment_resolution, + collect_errors); default: rust_unreachable (); } @@ -310,8 +581,7 @@ public: template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, + resolve_path (const std::vector<S> &segments, ResolutionMode mode, tl::optional<std::vector<Error> &> collect_errors, Namespace ns_first, Args... ns_args) { @@ -320,8 +590,7 @@ public: for (auto ns : namespaces) { std::vector<Error> collect_errors_inner; - if (auto ret = resolve_path (segments, has_opening_scope_resolution, - collect_errors_inner, ns)) + if (auto ret = resolve_path (segments, mode, collect_errors_inner, ns)) return ret; if (!collect_errors_inner.empty ()) { @@ -343,52 +612,68 @@ public: return tl::nullopt; } - template <typename... Args> + template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const AST::SimplePath &path, + resolve_path (const std::vector<S> &path_segments, + bool has_opening_scope_resolution, tl::optional<std::vector<Error> &> collect_errors, Namespace ns_first, Args... ns_args) { - return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), collect_errors, - ns_first, ns_args...); + auto mode = ResolutionMode::Normal; + if (has_opening_scope_resolution) + { + if (get_rust_edition () == Edition::E2015) + mode = ResolutionMode::FromRoot; + else + mode = ResolutionMode::FromExtern; + } + return resolve_path (path_segments, mode, collect_errors, ns_first, + ns_args...); } - template <typename... Args> + template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const AST::PathInExpression &path, - tl::optional<std::vector<Error> &> collect_errors, - Namespace ns_first, Args... ns_args) + resolve_path (const std::vector<S> &path_segments, + bool has_opening_scope_resolution, Namespace ns_first, + Args... ns_args) { - return resolve_path (path.get_segments (), path.opening_scope_resolution (), - collect_errors, ns_first, ns_args...); + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } - template <typename... Args> + template <typename S, typename... Args> tl::optional<Rib::Definition> - resolve_path (const AST::TypePath &path, - tl::optional<std::vector<Error> &> collect_errors, + resolve_path (const std::vector<S> &path_segments, ResolutionMode mode, Namespace ns_first, Args... ns_args) { + return resolve_path (path_segments, mode, tl::nullopt, ns_first, + ns_args...); + } + + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path, + Args &&...args) + { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), - collect_errors, ns_first, ns_args...); + path.has_opening_scope_resolution (), + std::forward<Args> (args)...); } - template <typename P, typename... Args> - tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first, - Args... ns_args) + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, + Args &&...args) { - return resolve_path (path, tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), path.opening_scope_resolution (), + std::forward<Args> (args)...); } - template <typename P, typename... Args> - tl::optional<Rib::Definition> - resolve_path (const P &path_segments, bool has_opening_scope_resolution, - Namespace ns_first, Args... ns_args) + template <typename... Args> + tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, + Args &&...args) { - return resolve_path (path_segments, has_opening_scope_resolution, - tl::nullopt, ns_first, ns_args...); + return resolve_path (path.get_segments (), + path.has_opening_scope_resolution_op (), + std::forward<Args> (args)...); } private: diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h index c498328..140c991 100644 --- a/gcc/rust/resolve/rust-rib.h +++ b/gcc/rust/resolve/rust-rib.h @@ -188,6 +188,8 @@ public: * restriction that you cannot `use` items from the Prelude */ Prelude, + /* Generic rib, used to store generics */ + Generics, } kind; static std::string kind_to_string (Rib::Kind kind) @@ -214,9 +216,13 @@ public: return "Forward type param ban"; case Rib::Kind::ConstParamType: return "Const Param Type"; - default: - rust_unreachable (); + case Kind::Prelude: + return "Prelude"; + case Kind::Generics: + return "Generics"; } + + rust_unreachable (); } Rib (Kind kind); diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index 2f036fe..0930f96 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -95,41 +95,17 @@ TopLevel::go (AST::Crate &crate) // times in a row in a fixed-point fashion, so it would make the code // responsible for this ugly and perfom a lot of error checking. - for (auto &item : crate.items) - item->accept_vis (*this); + visit (crate); } void TopLevel::visit (AST::Module &module) { - insert_or_error_out (module.get_name (), module, Namespace::Types); - - // Parse the module's items if they haven't been expanded and the file - // should be parsed (i.e isn't hidden behind an untrue or impossible cfg - // directive - // TODO: make sure this is right - // TODO: avoid loading items if cfg attributes are present? - // might not be needed if this runs after early resolution? - // This was copied from the old early resolver method - // 'accumulate_escaped_macros' - if (module.get_kind () == AST::Module::UNLOADED) - { - module.load_items (); - - // If the module was previously unloaded, then we don't want to visit it - // this time around as the CfgStrip hasn't run on its inner items yet. - // Skip it for now, mark the visitor as dirty and try again - - dirty = true; - - return; - } - DefaultResolver::visit (module); - if (Analysis::Mappings::get ().lookup_ast_module (module.get_node_id ()) + if (Analysis::Mappings::get ().lookup_glob_container (module.get_node_id ()) == tl::nullopt) - Analysis::Mappings::get ().insert_ast_module (&module); + Analysis::Mappings::get ().insert_glob_container (&module); } void @@ -141,33 +117,10 @@ TopLevel::visit (AST::Trait &trait) } void -TopLevel::visit (AST::InherentImpl &impl) -{ - auto inner_fn = [this, &impl] () { - insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), - impl.get_type (), Namespace::Types); - - // We do want to visit with the default visitor instead of default resolver - // because we don't want to insert the scope twice. - AST::DefaultASTVisitor::visit (impl); - }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); -} - -void -TopLevel::visit (AST::TraitImpl &impl) +TopLevel::maybe_insert_big_self (AST::Impl &impl) { - auto inner_fn = [this, &impl] () { - insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), - impl.get_type (), Namespace::Types); - - // We do want to visit using the default visitor instead of default resolver - // because we don't want to insert the scope twice. - AST::DefaultASTVisitor::visit (impl); - }; - - ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn); + insert_or_error_out (Identifier ("Self", impl.get_type ().get_locus ()), + impl.get_type (), Namespace::Types); } void @@ -197,19 +150,10 @@ insert_macros (std::vector<PROC_MACRO> ¯os, NameResolutionContext &ctx) } void -TopLevel::visit (AST::ExternCrate &crate) +TopLevel::visit_extern_crate (AST::ExternCrate &extern_crate, AST::Crate &crate, + CrateNum num) { auto &mappings = Analysis::Mappings::get (); - auto num_opt = mappings.lookup_crate_name (crate.get_referenced_crate ()); - - if (!num_opt) - { - rust_error_at (crate.get_locus (), "unknown crate %qs", - crate.get_referenced_crate ().c_str ()); - return; - } - - CrateNum num = *num_opt; auto attribute_macros = mappings.lookup_attribute_proc_macros (num); @@ -217,34 +161,27 @@ TopLevel::visit (AST::ExternCrate &crate) auto derive_macros = mappings.lookup_derive_proc_macros (num); - auto sub_visitor = [&] () { - // TODO: Find a way to keep this part clean without the double dispatch. - if (derive_macros.has_value ()) - { - insert_macros (derive_macros.value (), ctx); - for (auto ¯o : derive_macros.value ()) - mappings.insert_derive_proc_macro_def (macro); - } - if (attribute_macros.has_value ()) - { - insert_macros (attribute_macros.value (), ctx); - for (auto ¯o : attribute_macros.value ()) - mappings.insert_attribute_proc_macro_def (macro); - } - if (bang_macros.has_value ()) - { - insert_macros (bang_macros.value (), ctx); - for (auto ¯o : bang_macros.value ()) - mappings.insert_bang_proc_macro_def (macro); - } - }; + // TODO: Find a way to keep this part clean without the double dispatch. + if (derive_macros.has_value ()) + { + insert_macros (derive_macros.value (), ctx); + for (auto ¯o : derive_macros.value ()) + mappings.insert_derive_proc_macro_def (macro); + } + if (attribute_macros.has_value ()) + { + insert_macros (attribute_macros.value (), ctx); + for (auto ¯o : attribute_macros.value ()) + mappings.insert_attribute_proc_macro_def (macro); + } + if (bang_macros.has_value ()) + { + insert_macros (bang_macros.value (), ctx); + for (auto ¯o : bang_macros.value ()) + mappings.insert_bang_proc_macro_def (macro); + } - if (crate.has_as_clause ()) - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor, - crate.get_as_clause ()); - else - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor, - crate.get_referenced_crate ()); + visit (crate); } static bool @@ -321,14 +258,7 @@ TopLevel::visit (AST::ExternalStaticItem &static_item) void TopLevel::visit (AST::StructStruct &struct_item) { - auto generic_vis = [this, &struct_item] () { - for (auto &g : struct_item.get_generic_params ()) - { - g->accept_vis (*this); - } - }; - - ctx.scoped (Rib::Kind::Item, struct_item.get_node_id (), generic_vis); + DefaultResolver::visit (struct_item); insert_or_error_out (struct_item.get_struct_name (), struct_item, Namespace::Types); @@ -374,24 +304,32 @@ void TopLevel::visit (AST::EnumItem &variant) { insert_enum_variant_or_error_out (variant.get_identifier (), variant); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemTuple &variant) { insert_enum_variant_or_error_out (variant.get_identifier (), variant); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemStruct &variant) { insert_enum_variant_or_error_out (variant.get_identifier (), variant); + + DefaultResolver::visit (variant); } void TopLevel::visit (AST::EnumItemDiscriminant &variant) { insert_or_error_out (variant.get_identifier (), variant, Namespace::Types); + + DefaultResolver::visit (variant); } void @@ -401,6 +339,13 @@ TopLevel::visit (AST::Enum &enum_item) Namespace::Types); DefaultResolver::visit (enum_item); + + // Since enums can be containers for imports, we need to insert them like we + // do for modules + if (Analysis::Mappings::get ().lookup_glob_container ( + enum_item.get_node_id ()) + == tl::nullopt) + Analysis::Mappings::get ().insert_glob_container (&enum_item); } void @@ -430,21 +375,18 @@ TopLevel::visit (AST::TypeAlias &type_item) DefaultResolver::visit (type_item); } -static void -flatten_rebind ( +static void flatten_rebind ( const AST::UseTreeRebind &glob, std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> &rebind_paths); -static void -flatten_list ( +static void flatten_list ( const AST::UseTreeList &glob, std::vector<AST::SimplePath> &paths, std::vector<AST::SimplePath> &glob_paths, std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> &rebind_paths, NameResolutionContext &ctx); -static void -flatten_glob (const AST::UseTreeGlob &glob, - std::vector<AST::SimplePath> &glob_paths, - NameResolutionContext &ctx); +static void flatten_glob (const AST::UseTreeGlob &glob, + std::vector<AST::SimplePath> &glob_paths, + NameResolutionContext &ctx); static void flatten ( @@ -455,17 +397,20 @@ flatten ( { switch (tree->get_kind ()) { - case AST::UseTree::Rebind: { + case AST::UseTree::Rebind: + { auto rebind = static_cast<const AST::UseTreeRebind *> (tree); flatten_rebind (*rebind, rebind_paths); break; } - case AST::UseTree::List: { + case AST::UseTree::List: + { auto list = static_cast<const AST::UseTreeList *> (tree); flatten_list (*list, paths, glob_paths, rebind_paths, ctx); break; } - case AST::UseTree::Glob: { + case AST::UseTree::Glob: + { auto glob = static_cast<const AST::UseTreeGlob *> (tree); flatten_glob (*glob, glob_paths, ctx); break; diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h index 3ff37ed..8d3da92 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -160,8 +160,7 @@ private: void visit (AST::Module &module) override; void visit (AST::Trait &trait) override; - void visit (AST::InherentImpl &impl) override; - void visit (AST::TraitImpl &impl) override; + void maybe_insert_big_self (AST::Impl &impl) override; void visit (AST::TraitItemType &trait_item) override; void visit (AST::MacroRulesDefinition ¯o) override; void visit (AST::Function &function) override; @@ -177,7 +176,7 @@ private: void visit (AST::Union &union_item) override; void visit (AST::ConstantItem &const_item) override; void visit (AST::TypeAlias &type_item) override; - void visit (AST::ExternCrate &crate) override; + void visit_extern_crate (AST::ExternCrate &, AST::Crate &, CrateNum) override; void visit (AST::TypeParam &type_param) override; void visit (AST::ConstGenericParam &const_param) override; diff --git a/gcc/rust/rust-attribs.cc b/gcc/rust/rust-attribs.cc index 74cb2af..a98c1fa 100644 --- a/gcc/rust/rust-attribs.cc +++ b/gcc/rust/rust-attribs.cc @@ -38,35 +38,27 @@ along with GCC; see the file COPYING3. If not see * future. */ -extern const attribute_spec grs_langhook_common_attribute_table[]; +extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table; +extern const struct scoped_attribute_specs grs_langhook_common_attribute_table; /* Internal attribute handlers for built-in functions. */ -static tree -handle_noreturn_attribute (tree *, tree, tree, int, bool *); -static tree -handle_leaf_attribute (tree *, tree, tree, int, bool *); -static tree -handle_const_attribute (tree *, tree, tree, int, bool *); -static tree -handle_malloc_attribute (tree *, tree, tree, int, bool *); -static tree -handle_pure_attribute (tree *, tree, tree, int, bool *); -static tree -handle_novops_attribute (tree *, tree, tree, int, bool *); -static tree -handle_nonnull_attribute (tree *, tree, tree, int, bool *); -static tree -handle_nothrow_attribute (tree *, tree, tree, int, bool *); -static tree -handle_type_generic_attribute (tree *, tree, tree, int, bool *); -static tree -handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); -static tree -handle_returns_twice_attribute (tree *, tree, tree, int, bool *); -static tree -handle_fnspec_attribute (tree *, tree, tree, int, bool *); -static tree -handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree handle_leaf_attribute (tree *, tree, tree, int, bool *); +static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *); +static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); +static tree handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); + +/* Rust attribute handlers for user defined attributes. */ +static tree handle_cold_attribute (tree *, tree, tree, int, bool *); +static tree handle_hot_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -74,6 +66,10 @@ handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *); name, function, type, variable \ } +// clang-format off +// Disabling clang-format because it insists in having several ATTR_EXCL() on a +// single line. + static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = { // ATTR_EXCL ("alloc_size", true, true, true), ATTR_EXCL ("const", true, true, true), @@ -89,11 +85,22 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] ATTR_EXCL (NULL, false, false, false), }; +extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = { + + ATTR_EXCL ("cold", true, true, true), + ATTR_EXCL ("hot", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { // ATTR_EXCL ("alloc_size", true, true, true), ATTR_EXCL ("const", true, true, true), ATTR_EXCL ("noreturn", true, true, true), - ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false)}; + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + +// clang-format on /* Helper to define an attribute. */ #define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \ @@ -105,7 +112,7 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = { /* Table of machine-independent attributes. For internal use (marking of built-ins) only. */ -const attribute_spec grs_langhook_common_attribute_table[] = { +static const attribute_spec grs_langhook_common_attributes[] = { ATTR_SPEC ("noreturn", 0, 0, true, false, false, false, handle_noreturn_attribute, attr_noreturn_exclusions), ATTR_SPEC ("leaf", 0, 0, true, false, false, false, handle_leaf_attribute, @@ -132,9 +139,21 @@ const attribute_spec grs_langhook_common_attribute_table[] = { NULL), ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false, handle_omp_declare_simd_attribute, NULL), - ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL), }; +const scoped_attribute_specs grs_langhook_common_attribute_table + = {"gnu", {grs_langhook_common_attributes}}; + +static const attribute_spec grs_langhook_gnu_attributes[] = { + ATTR_SPEC ("cold", 0, 0, true, false, false, false, handle_cold_attribute, + attr_cold_hot_exclusions), + ATTR_SPEC ("hot", 0, 0, true, false, false, false, handle_hot_attribute, + attr_cold_hot_exclusions), +}; + +const scoped_attribute_specs grs_langhook_gnu_attribute_table + = {"gnu", {grs_langhook_gnu_attributes}}; + /* Built-in attribute handlers. These functions take the arguments: (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */ @@ -204,7 +223,7 @@ handle_const_attribute (tree *node, tree, tree, int, bool *) /* Handle a "malloc" attribute; arguments as in struct attribute_spec.handler. */ -tree +static tree handle_malloc_attribute (tree *node, tree, tree, int, bool *) { gcc_assert (TREE_CODE (*node) == FUNCTION_DECL @@ -217,9 +236,14 @@ handle_malloc_attribute (tree *node, tree, tree, int, bool *) struct attribute_spec.handler. */ static tree -handle_pure_attribute (tree *node, tree, tree, int, bool *) +handle_pure_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + DECL_PURE_P (*node) = 1; return NULL_TREE; } @@ -228,9 +252,14 @@ handle_pure_attribute (tree *node, tree, tree, int, bool *) struct attribute_spec.handler. */ static tree -handle_novops_attribute (tree *node, tree, tree, int, bool *) +handle_novops_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + DECL_IS_NOVOPS (*node) = 1; return NULL_TREE; } @@ -301,9 +330,14 @@ handle_nonnull_attribute (tree *node, tree, tree args, int, bool *) struct attribute_spec.handler. */ static tree -handle_nothrow_attribute (tree *node, tree, tree, int, bool *) +handle_nothrow_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + TREE_NOTHROW (*node) = 1; return NULL_TREE; } @@ -339,9 +373,14 @@ handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *) struct attribute_spec.handler. */ static tree -handle_returns_twice_attribute (tree *node, tree, tree, int, bool *) +handle_returns_twice_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } DECL_IS_RETURNS_TWICE (*node) = 1; @@ -351,7 +390,7 @@ handle_returns_twice_attribute (tree *node, tree, tree, int, bool *) /* Handle a "fn spec" attribute; arguments as in struct attribute_spec.handler. */ -tree +static tree handle_fnspec_attribute (tree *, tree, tree args, int, bool *) { gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST @@ -362,9 +401,46 @@ handle_fnspec_attribute (tree *, tree, tree args, int, bool *) /* Handle an "omp declare simd" attribute; arguments as in struct attribute_spec.handler. */ -tree -handle_omp_declare_simd_attribute (tree *node, tree, tree, int, bool *) +static tree +handle_omp_declare_simd_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) { - gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Language specific attribute handlers. + These functions take the arguments: + (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */ + +/* Handle a "cold" and attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_cold_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +static tree +handle_hot_attribute (tree *node, tree name, tree, int, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + return NULL_TREE; } diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index 414799e..95ca7a9 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -27,6 +27,8 @@ #include "rust-linemap.h" #include "rust-diagnostics.h" #include "util/rust-operators.h" +#include "util/rust-ggc.h" +#include "util/optional.h" #include "tree.h" #include "rust-gcc.h" @@ -42,69 +44,60 @@ class Bvariable; namespace Backend { -void -init (); +namespace GGC { + +using Rust::GGC::Ident; + +} // namespace GGC + +void init (); // Name/type/location. Used for function parameters, struct fields, // interface methods. struct typed_identifier { - std::string name; + GGC::Ident name; tree type; location_t location; - typed_identifier () : name (), type (NULL_TREE), location (UNKNOWN_LOCATION) - {} - - typed_identifier (const std::string &a_name, tree a_type, - location_t a_location) + typed_identifier (GGC::Ident a_name, tree a_type, location_t a_location) : name (a_name), type (a_type), location (a_location) {} }; // debug void debug (tree); -void -debug (Bvariable *); +void debug (Bvariable *); -tree -get_identifier_node (const std::string &str); +tree get_identifier_node (const std::string &str); // Types. // Get the wchar type -tree -wchar_type (); +tree wchar_type (); // Get the Host pointer size in bits -int -get_pointer_size (); +int get_pointer_size (); // Get the raw str type const char* -tree -raw_str_type (); +tree raw_str_type (); // Get an unnamed integer type with the given signedness and number // of bits. -tree -integer_type (bool is_unsigned, int bits); +tree integer_type (bool is_unsigned, int bits); // Get an unnamed floating point type with the given number of bits // (32 or 64). -tree -float_type (int bits); +tree float_type (int bits); // Get a pointer type. -tree -pointer_type (tree to_type); +tree pointer_type (tree to_type); // Get a reference type. -tree -reference_type (tree to_type); +tree reference_type (tree to_type); // make type immutable -tree -immutable_type (tree base); +tree immutable_type (tree base); // Get a function type. The receiver, parameter, and results are // generated from the types in the Function_type. The Function_type @@ -115,41 +108,36 @@ immutable_type (tree base); // one result, RESULT_STRUCT is a struct type to hold the results, // and RESULTS may be ignored; if there are zero or one results, // RESULT_STRUCT is NULL. -tree -function_type (const typed_identifier &receiver, - const std::vector<typed_identifier> ¶meters, - const std::vector<typed_identifier> &results, tree result_struct, - location_t location); - -tree -function_type_variadic (const typed_identifier &receiver, - const std::vector<typed_identifier> ¶meters, - const std::vector<typed_identifier> &results, - tree result_struct, location_t location); - -tree -function_ptr_type (tree result, const std::vector<tree> &praameters, - location_t location); +tree function_type (const typed_identifier &receiver, + const std::vector<typed_identifier> ¶meters, + const std::vector<typed_identifier> &results, + tree result_struct, location_t location); + +tree function_type_variadic (const typed_identifier &receiver, + const std::vector<typed_identifier> ¶meters, + const std::vector<typed_identifier> &results, + tree result_struct, location_t location); + +tree function_ptr_type (tree result, const std::vector<tree> &praameters, + location_t location); // Get a struct type. -tree -struct_type (const std::vector<typed_identifier> &fields, bool layout = true); +tree struct_type (const std::vector<typed_identifier> &fields, + bool layout = true); // Get a union type. -tree -union_type (const std::vector<typed_identifier> &fields, bool layout = true); +tree union_type (const std::vector<typed_identifier> &fields, + bool layout = true); // Get an array type. -tree -array_type (tree element_type, tree length); +tree array_type (tree element_type, tree length); // Return a named version of a type. The location is the location // of the type definition. This will not be called for a type // created via placeholder_pointer_type, placeholder_struct_type, or // placeholder_array_type.. (It may be called for a pointer, // struct, or array type in a case like "type P *byte; type Q P".) -tree -named_type (const std::string &name, tree, location_t); +tree named_type (GGC::Ident name, tree, location_t); // Return the size of a type. int64_t type_size (tree); @@ -164,8 +152,7 @@ int64_t type_field_alignment (tree); // Return the offset of field INDEX in a struct type. INDEX is the // entry in the FIELDS std::vector parameter of struct_type or // set_placeholder_struct_type. -int64_t -type_field_offset (tree, size_t index); +int64_t type_field_offset (tree, size_t index); // Expressions. @@ -175,155 +162,135 @@ type_field_offset (tree, size_t index); tree zero_expression (tree); // Create a reference to a variable. -tree -var_expression (Bvariable *var, location_t); +tree var_expression (Bvariable *var, location_t); // Return an expression for the floating point value VAL in BTYPE. -tree -float_constant_expression (tree btype, mpfr_t val); +tree float_constant_expression (tree btype, mpfr_t val); // Return an expression for the string value VAL. -tree -string_constant_expression (const std::string &val); +tree string_constant_expression (const std::string &val); // Get a char literal -tree -char_constant_expression (char c); +tree char_constant_expression (char c); // Get a char literal -tree -wchar_constant_expression (wchar_t c); +tree wchar_constant_expression (wchar_t c); + +// Get a size literal +tree size_constant_expression (size_t val); // Return an expression for the boolean value VAL. -tree -boolean_constant_expression (bool val); +tree boolean_constant_expression (bool val); // Return an expression that converts EXPR to TYPE. -tree -convert_expression (tree type, tree expr, location_t); +tree convert_expression (tree type, tree expr, location_t); // Return an expression for the field at INDEX in BSTRUCT. -tree -struct_field_expression (tree bstruct, size_t index, location_t); +tree struct_field_expression (tree bstruct, size_t index, location_t); // Create an expression that executes BSTAT before BEXPR. -tree -compound_expression (tree bstat, tree bexpr, location_t); +tree compound_expression (tree bstat, tree bexpr, location_t); // Return an expression that executes THEN_EXPR if CONDITION is true, or // ELSE_EXPR otherwise and returns the result as type BTYPE, within the // specified function FUNCTION. ELSE_EXPR may be NULL. BTYPE may be NULL. -tree -conditional_expression (tree function, tree btype, tree condition, - tree then_expr, tree else_expr, location_t); +tree conditional_expression (tree function, tree btype, tree condition, + tree then_expr, tree else_expr, location_t); // Return an expression for the negation operation OP EXPR. // Supported values of OP are enumerated in NegationOperator. -tree -negation_expression (NegationOperator op, tree expr, location_t); +tree negation_expression (NegationOperator op, tree expr, location_t); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ArithmeticOrLogicalOperator. -tree -arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left, - tree right, location_t loc); +tree arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, + tree left, tree right, location_t loc); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ArithmeticOrLogicalOperator. // This function adds overflow checking and returns a list of statements to // add to the current function context. The `receiver` variable refers to the // variable which will contain the result of that operation. -tree -arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, - tree left, tree right, location_t loc, - Bvariable *receiver); +tree arithmetic_or_logical_expression_checked (ArithmeticOrLogicalOperator op, + tree left, tree right, + location_t loc, + Bvariable *receiver); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in ComparisonOperator. -tree -comparison_expression (ComparisonOperator op, tree left, tree right, - location_t loc); +tree comparison_expression (ComparisonOperator op, tree left, tree right, + location_t loc); // Return an expression for the operation LEFT OP RIGHT. // Supported values of OP are enumerated in LazyBooleanOperator. -tree -lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right, - location_t); +tree lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right, + location_t); // Return an expression that constructs BTYPE with VALS. BTYPE must be the // backend representation a of struct. VALS must be in the same order as the // corresponding fields in BTYPE. -tree -constructor_expression (tree btype, bool is_variant, - const std::vector<tree> &vals, int, location_t); +tree constructor_expression (tree btype, bool is_variant, + const std::vector<tree> &vals, int, location_t); // Return an expression that constructs an array of BTYPE with INDEXES and // VALS. INDEXES and VALS must have the same amount of elements. Each index // in INDEXES must be in the same order as the corresponding value in VALS. -tree -array_constructor_expression (tree btype, - const std::vector<unsigned long> &indexes, - const std::vector<tree> &vals, location_t); +tree array_constructor_expression (tree btype, + const std::vector<unsigned long> &indexes, + const std::vector<tree> &vals, location_t); -tree -array_initializer (tree, tree, tree, tree, tree, tree *, location_t); +tree array_initializer (tree, tree, tree, tree, tree, tree *, location_t); // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid // fixed-length array, not a slice. -tree -array_index_expression (tree array, tree index, location_t); +tree array_index_expression (tree array, tree index, location_t); + +// Return an expresison for SLICE[INDEX] as an l-value. SLICE is represented +// with a DST. +tree slice_index_expression (tree slice, tree index, location_t); // Create an expression for a call to FN with ARGS, taking place within // caller CALLER. -tree -call_expression (tree fn, const std::vector<tree> &args, tree static_chain, - location_t); +tree call_expression (tree fn, const std::vector<tree> &args, tree static_chain, + location_t); // Statements. // Create a variable initialization statement in the specified // function. This initializes a local variable at the point in the // program flow where it is declared. -tree -init_statement (tree, Bvariable *var, tree init); +tree init_statement (tree, Bvariable *var, tree init); // Create an assignment statement within the specified function. -tree -assignment_statement (tree lhs, tree rhs, location_t); +tree assignment_statement (tree lhs, tree rhs, location_t); // Create return statement for an decl for a value (can be NULL_TREE) at a // location -tree -return_statement (tree fndecl, tree val, location_t); +tree return_statement (tree fndecl, tree val, location_t); // Create an if statement within a function. ELSE_BLOCK may be NULL. -tree -if_statement (tree, tree condition, tree then_block, tree else_block, - location_t); +tree if_statement (tree, tree condition, tree then_block, tree else_block, + location_t); // infinite loop expressions -tree -loop_expression (tree body, location_t); +tree loop_expression (tree body, location_t); // exit expressions -tree -exit_expression (tree condition, location_t); +tree exit_expression (tree condition, location_t); // Create a single statement from two statements. tree compound_statement (tree, tree); // Create a single statement from a list of statements. -tree -statement_list (const std::vector<tree> &); +tree statement_list (const std::vector<tree> &); // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if // an exception occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and // if not NULL, it will always be executed. This is used for handling defers // in Go functions. In C++, the resulting code is of this form: // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; } -tree -exception_handler_statement (tree bstat, tree except_stmt, tree finally_stmt, - location_t); +tree exception_handler_statement (tree bstat, tree except_stmt, + tree finally_stmt, location_t); // Blocks. @@ -337,16 +304,14 @@ exception_handler_statement (tree bstat, tree except_stmt, tree finally_stmt, // the initial curly brace. END_LOCATION is the location of the end // of the block, more or less the location of the final curly brace. // The statements will be added after the block is created. -tree -block (tree function, tree enclosing, const std::vector<Bvariable *> &vars, - location_t start_location, location_t end_location); +tree block (tree function, tree enclosing, const std::vector<Bvariable *> &vars, + location_t start_location, location_t end_location); // Add the statements to a block. The block is created first. Then // the statements are created. Then the statements are added to the // block. This will called exactly once per block. The vector may // be empty if there are no statements. -void -block_add_statements (tree, const std::vector<tree> &); +void block_add_statements (tree, const std::vector<tree> &); // Variables. @@ -360,10 +325,9 @@ block_add_statements (tree, const std::vector<tree> &); // be put into a unique section if possible; this is intended to // permit the linker to garbage collect the variable if it is not // referenced. LOCATION is where the variable was defined. -Bvariable * -global_variable (const std::string &name, const std::string &asm_name, - tree btype, bool is_external, bool is_hidden, - bool in_unique_section, location_t location); +Bvariable *global_variable (GGC::Ident name, GGC::Ident asm_name, tree btype, + bool is_external, bool is_hidden, + bool in_unique_section, location_t location); // A global variable will 1) be initialized to zero, or 2) be // initialized to a constant value, or 3) be initialized in the init @@ -371,8 +335,7 @@ global_variable (const std::string &name, const std::string &asm_name, // global_variable_set_init to set the initial value. If this is // not called, the backend should initialize a global variable to 0. // The init function may then assign a value to it. -void -global_variable_set_init (Bvariable *, tree); +void global_variable_set_init (Bvariable *, tree); // Create a local variable. The frontend will create the local // variables first, and then create the block which contains them. @@ -386,21 +349,18 @@ global_variable_set_init (Bvariable *, tree); // the function, as otherwise the variable would be on the heap). // LOCATION is where the variable is defined. For each local variable // the frontend will call init_statement to set the initial value. -Bvariable * -local_variable (tree function, const std::string &name, tree type, - Bvariable *decl_var, location_t location); +Bvariable *local_variable (tree function, GGC::Ident name, tree type, + Bvariable *decl_var, location_t location); // Create a function parameter. This is an incoming parameter, not // a result parameter (result parameters are treated as local // variables). The arguments are as for local_variable. -Bvariable * -parameter_variable (tree function, const std::string &name, tree type, - location_t location); +Bvariable *parameter_variable (tree function, GGC::Ident name, tree type, + location_t location); // Create a static chain parameter. This is the closure parameter. -Bvariable * -static_chain_variable (tree function, const std::string &name, tree type, - location_t location); +Bvariable *static_chain_variable (tree function, GGC::Ident name, tree type, + location_t location); // Create a temporary variable. A temporary variable has no name, // just a type. We pass in FUNCTION and BLOCK in case they are @@ -413,18 +373,16 @@ static_chain_variable (tree function, const std::string &name, tree type, // variable, and may not be very useful. This function should // return a variable which can be referenced later and should set // *PSTATEMENT to a statement which initializes the variable. -Bvariable * -temporary_variable (tree fndecl, tree bind_tree, tree type, tree init, - bool address_is_taken, location_t location, - tree *pstatement); +Bvariable *temporary_variable (tree fndecl, tree bind_tree, tree type, + tree init, bool address_is_taken, + location_t location, tree *pstatement); // Labels. -// Create a new label. NAME will be empty if this is a label +// Create a new label. NAME will be tl::nullopt if this is a label // created by the frontend for a loop construct. The location is // where the label is defined. -tree -label (tree, const std::string &name, location_t); +tree label (tree, tl::optional<GGC::Ident> name, location_t); // Create a statement which defines a label. This statement will be // put into the codestream at the point where the label should be @@ -439,6 +397,12 @@ tree goto_statement (tree, location_t); // recover. tree label_address (tree, location_t); +// Lookup a field from a type given its name. +// Build the `component` tree with `Backend::get_identifier_node`. +// +// Forked from the C frontend. +tree lookup_field (const_tree, tree); + // Functions. // Bit flags to pass to the function method. @@ -460,43 +424,38 @@ static const unsigned int function_does_not_return = 1 << 2; static const unsigned int function_in_unique_section = 1 << 3; // Declare or define a function of FNTYPE. -// NAME is the Go name of the function. ASM_NAME, if not the empty -// string, is the name that should be used in the symbol table; this +// NAME is the Go name of the function. ASM_NAME, if not tl::nullopt, +// is the name that should be used in the symbol table; this // will be non-empty if a magic extern comment is used. FLAGS is // bit flags described above. -tree -function (tree fntype, const std::string &name, const std::string &asm_name, - unsigned int flags, location_t); +tree function (tree fntype, GGC::Ident name, tl::optional<GGC::Ident> asm_name, + unsigned int flags, location_t); // Create a statement that runs all deferred calls for FUNCTION. This should // be a statement that looks like this in C++: // finish: // try { DEFER_RETURN; } catch { CHECK_DEFER; goto finish; } -tree -function_defer_statement (tree function, tree undefer, tree check_defer, - location_t); +tree function_defer_statement (tree function, tree undefer, tree check_defer, + location_t); // Record PARAM_VARS as the variables to use for the parameters of FUNCTION. // This will only be called for a function definition. Returns true on // success, false on failure. -bool -function_set_parameters (tree function, - const std::vector<Bvariable *> ¶m_vars); +bool function_set_parameters (tree function, + const std::vector<Bvariable *> ¶m_vars); // Utility. // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, // FUNCTION_DECLS, and VARIABLE_DECLS declared globally. -void -write_global_definitions (const std::vector<tree> &type_decls, - const std::vector<tree> &constant_decls, - const std::vector<tree> &function_decls, - const std::vector<Bvariable *> &variable_decls); +void write_global_definitions (const std::vector<tree> &type_decls, + const std::vector<tree> &constant_decls, + const std::vector<tree> &function_decls, + const std::vector<Bvariable *> &variable_decls); // TODO: make static -tree -fill_in_fields (tree, const std::vector<typed_identifier> &, bool); +tree fill_in_fields (tree, const std::vector<typed_identifier> &, bool); tree fill_in_array (tree, tree, tree); diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc index 702da71..5965bb4 100644 --- a/gcc/rust/rust-diagnostics.cc +++ b/gcc/rust/rust-diagnostics.cc @@ -48,27 +48,33 @@ expand_format (const char *fmt) c++; switch (*c) { - case '\0': { + case '\0': + { // malformed format string rust_unreachable (); } - case '%': { + case '%': + { ss << "%"; break; } - case 'm': { + case 'm': + { ss << mformat_value (); break; } - case '<': { + case '<': + { ss << rust_open_quote (); break; } - case '>': { + case '>': + { ss << rust_close_quote (); break; } - case 'q': { + case 'q': + { ss << rust_open_quote (); c++; if (*c == 'm') @@ -82,7 +88,8 @@ expand_format (const char *fmt) ss << rust_close_quote (); break; } - default: { + default: + { ss << "%" << *c; } } @@ -104,8 +111,8 @@ expand_format (const char *fmt) // calling function must need to have attribute gnu_printf as well, even // though there is already an attribute declaration for it. -static std::string -expand_message (const char *fmt, va_list ap) RUST_ATTRIBUTE_GCC_DIAG (1, 0); +static std::string expand_message (const char *fmt, va_list ap) + RUST_ATTRIBUTE_GCC_DIAG (1, 0); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsuggest-attribute=format" @@ -420,24 +427,24 @@ namespace Rust { */ // simple location -static Error -va_constructor (Error::Kind kind, location_t locus, const char *fmt, - va_list args) RUST_ATTRIBUTE_GCC_DIAG (3, 0); +static Error va_constructor (Error::Kind kind, location_t locus, + const char *fmt, va_list args) + RUST_ATTRIBUTE_GCC_DIAG (3, 0); // simple location + error code -static Error -va_constructor (Error::Kind kind, location_t locus, const ErrorCode code, - const char *fmt, va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); +static Error va_constructor (Error::Kind kind, location_t locus, + const ErrorCode code, const char *fmt, + va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); // rich location -static Error -va_constructor (Error::Kind kind, rich_location *r_locus, const char *fmt, - va_list args) RUST_ATTRIBUTE_GCC_DIAG (3, 0); +static Error va_constructor (Error::Kind kind, rich_location *r_locus, + const char *fmt, va_list args) + RUST_ATTRIBUTE_GCC_DIAG (3, 0); // rich location + error code -static Error -va_constructor (Error::Kind kind, rich_location *r_locus, const ErrorCode code, - const char *fmt, va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); +static Error va_constructor (Error::Kind kind, rich_location *r_locus, + const ErrorCode code, const char *fmt, + va_list args) RUST_ATTRIBUTE_GCC_DIAG (4, 0); // simple location static Error diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h index a13dc6a2..09d5e24 100644 --- a/gcc/rust/rust-diagnostics.h +++ b/gcc/rust/rust-diagnostics.h @@ -31,7 +31,7 @@ #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) #define RUST_ATTRIBUTE_GCC_DIAG(m, n) \ __attribute__ ((__format__ (__gcc_tdiag__, m, n))) \ - __attribute__ ((__nonnull__ (m))) + __attribute__ ((__nonnull__ (m))) #else #define RUST_ATTRIBUTE_GCC_DIAG(m, n) #endif @@ -119,10 +119,8 @@ rust_error_at(rich_location *richloc, const ErrorCode, const char *fmt, ...) // These interfaces provide a way for the front end to ask for // the open/close quote characters it should use when formatting // diagnostics (warnings, errors). -extern const char * -rust_open_quote (); -extern const char * -rust_close_quote (); +extern const char *rust_open_quote (); +extern const char *rust_close_quote (); // These interfaces are used by utilities above to pass warnings and // errors (once format specifiers have been expanded) to the back end, @@ -185,7 +183,7 @@ struct Error Error (Kind kind, location_t locus, std::string message) : kind (kind), locus (locus), message (std::move (message)) { - message.shrink_to_fit (); + this->message.shrink_to_fit (); } // simple location + error code Error (Kind kind, location_t locus, ErrorCode code, std::string message) @@ -193,13 +191,13 @@ struct Error message (std::move (message)) { is_errorcode = true; - message.shrink_to_fit (); + this->message.shrink_to_fit (); } // rich location Error (Kind kind, rich_location *richlocus, std::string message) : kind (kind), richlocus (richlocus), message (std::move (message)) { - message.shrink_to_fit (); + this->message.shrink_to_fit (); } // rich location + error code Error (Kind kind, rich_location *richlocus, ErrorCode code, @@ -208,7 +206,7 @@ struct Error message (std::move (message)) { is_errorcode = true; - message.shrink_to_fit (); + this->message.shrink_to_fit (); } // simple location Error (location_t locus, std::string message) @@ -306,8 +304,7 @@ struct Error #define rust_sorry_at(location, ...) sorry_at (location, __VA_ARGS__) -void -rust_debug_loc (const location_t location, const char *fmt, - ...) ATTRIBUTE_PRINTF_2; +void rust_debug_loc (const location_t location, const char *fmt, + ...) ATTRIBUTE_PRINTF_2; #endif // !defined(RUST_DIAGNOSTICS_H) diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index e5319d3..398dea1 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -91,12 +91,6 @@ Bvariable::error_variable () // A helper function to create a GCC identifier from a C++ string. -static inline tree -get_identifier_from_string (const std::string &str) -{ - return get_identifier_with_length (str.data (), str.length ()); -} - namespace Backend { // Define the built-in functions that are exposed to GCCRust. @@ -609,7 +603,7 @@ fill_in_fields (tree fill, const std::vector<typed_identifier> &fields, tree *pp = &field_trees; for (const auto &p : fields) { - tree name_tree = get_identifier_from_string (p.name); + tree name_tree = p.name.as_tree (); tree type_tree = p.type; if (error_operand_p (type_tree)) return error_mark_node; @@ -675,7 +669,7 @@ fill_in_array (tree fill, tree element_type, tree length_tree) // Return a named version of a type. tree -named_type (const std::string &name, tree type, location_t location) +named_type (GGC::Ident name, tree type, location_t location) { if (error_operand_p (type)) return error_mark_node; @@ -688,15 +682,14 @@ named_type (const std::string &name, tree type, location_t location) || TREE_CODE (type) == COMPLEX_TYPE || TREE_CODE (type) == BOOLEAN_TYPE)) { - tree decl = build_decl (BUILTINS_LOCATION, TYPE_DECL, - get_identifier_from_string (name), type); + tree decl + = build_decl (BUILTINS_LOCATION, TYPE_DECL, name.as_tree (), type); TYPE_NAME (type) = decl; return type; } tree copy = build_variant_type_copy (type); - tree decl - = build_decl (location, TYPE_DECL, get_identifier_from_string (name), copy); + tree decl = build_decl (location, TYPE_DECL, name.as_tree (), copy); DECL_ORIGINAL_TYPE (decl) = type; TYPE_NAME (copy) = decl; return copy; @@ -825,6 +818,12 @@ char_constant_expression (char c) return build_int_cst (char_type_node, c); } +tree +size_constant_expression (size_t val) +{ + return size_int (val); +} + // Make a constant boolean expression. tree @@ -1505,6 +1504,34 @@ array_index_expression (tree array_tree, tree index_tree, location_t location) return ret; } +// Return an expression representing SLICE[INDEX] + +tree +slice_index_expression (tree slice_tree, tree index_tree, location_t location) +{ + if (error_operand_p (slice_tree) || error_operand_p (index_tree)) + return error_mark_node; + + // A slice is created in TyTyResolvecompile::create_slice_type_record + // For example: + // &[i32] is turned directly into a struct { i32* data, usize len }; + // [i32] is also turned into struct { i32* data, usize len } + + // it should have RS_DST_FLAG set to 1 + rust_assert (RS_DST_FLAG_P (TREE_TYPE (slice_tree))); + + tree data_field = struct_field_expression (slice_tree, 0, location); + tree data_field_deref = build_fold_indirect_ref_loc (location, data_field); + + tree element_type = TREE_TYPE (data_field_deref); + tree data_pointer = TREE_OPERAND (data_field_deref, 0); + rust_assert (POINTER_TYPE_P (TREE_TYPE (data_pointer))); + tree data_offset_expr + = Rust::pointer_offset_expression (data_pointer, index_tree, location); + + return build1_loc (location, INDIRECT_REF, element_type, data_offset_expr); +} + // Create an expression for a call to FN_EXPR with FN_ARGS. tree call_expression (tree fn, const std::vector<tree> &fn_args, tree chain_expr, @@ -1876,7 +1903,8 @@ non_zero_size_type (tree type) } return rust_non_zero_struct; - case ARRAY_TYPE: { + case ARRAY_TYPE: + { tree element_type = non_zero_size_type (TREE_TYPE (type)); return build_array_type_nelts (element_type, 1); } @@ -1923,9 +1951,9 @@ convert_tree (tree type_tree, tree expr_tree, location_t location) // Make a global variable. Bvariable * -global_variable (const std::string &var_name, const std::string &asm_name, - tree type_tree, bool is_external, bool is_hidden, - bool in_unique_section, location_t location) +global_variable (GGC::Ident var_name, GGC::Ident asm_name, tree type_tree, + bool is_external, bool is_hidden, bool in_unique_section, + location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); @@ -1935,8 +1963,7 @@ global_variable (const std::string &var_name, const std::string &asm_name, if ((is_external || !is_hidden) && int_size_in_bytes (type_tree) == 0) type_tree = non_zero_size_type (type_tree); - tree decl = build_decl (location, VAR_DECL, - get_identifier_from_string (var_name), type_tree); + tree decl = build_decl (location, VAR_DECL, var_name.as_tree (), type_tree); if (is_external) DECL_EXTERNAL (decl) = 1; else @@ -1944,11 +1971,11 @@ global_variable (const std::string &var_name, const std::string &asm_name, if (!is_hidden) { TREE_PUBLIC (decl) = 1; - SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name)); + SET_DECL_ASSEMBLER_NAME (decl, asm_name.as_tree ()); } else { - SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name)); + SET_DECL_ASSEMBLER_NAME (decl, asm_name.as_tree ()); } TREE_USED (decl) = 1; @@ -1988,13 +2015,12 @@ global_variable_set_init (Bvariable *var, tree expr_tree) // Make a local variable. Bvariable * -local_variable (tree function, const std::string &name, tree type_tree, +local_variable (tree function, GGC::Ident name, tree type_tree, Bvariable *decl_var, location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); - tree decl = build_decl (location, VAR_DECL, get_identifier_from_string (name), - type_tree); + tree decl = build_decl (location, VAR_DECL, name.as_tree (), type_tree); DECL_CONTEXT (decl) = function; if (decl_var != NULL) @@ -2009,13 +2035,12 @@ local_variable (tree function, const std::string &name, tree type_tree, // Make a function parameter variable. Bvariable * -parameter_variable (tree function, const std::string &name, tree type_tree, +parameter_variable (tree function, GGC::Ident name, tree type_tree, location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); - tree decl = build_decl (location, PARM_DECL, - get_identifier_from_string (name), type_tree); + tree decl = build_decl (location, PARM_DECL, name.as_tree (), type_tree); DECL_CONTEXT (decl) = function; DECL_ARG_TYPE (decl) = type_tree; @@ -2026,13 +2051,12 @@ parameter_variable (tree function, const std::string &name, tree type_tree, // Make a static chain variable. Bvariable * -static_chain_variable (tree fndecl, const std::string &name, tree type_tree, +static_chain_variable (tree fndecl, GGC::Ident name, tree type_tree, location_t location) { if (error_operand_p (type_tree)) return Bvariable::error_variable (); - tree decl = build_decl (location, PARM_DECL, - get_identifier_from_string (name), type_tree); + tree decl = build_decl (location, PARM_DECL, name.as_tree (), type_tree); DECL_CONTEXT (decl) = fndecl; DECL_ARG_TYPE (decl) = type_tree; TREE_USED (decl) = 1; @@ -2123,10 +2147,10 @@ temporary_variable (tree fndecl, tree bind_tree, tree type_tree, tree init_tree, // Make a label. tree -label (tree func_tree, const std::string &name, location_t location) +label (tree func_tree, tl::optional<GGC::Ident> name, location_t location) { tree decl; - if (name.empty ()) + if (!name.has_value ()) { if (DECL_STRUCT_FUNCTION (func_tree) == NULL) push_struct_function (func_tree); @@ -2139,7 +2163,7 @@ label (tree func_tree, const std::string &name, location_t location) } else { - tree id = get_identifier_from_string (name); + tree id = name->as_tree (); decl = build_decl (location, LABEL_DECL, id, void_type_node); DECL_CONTEXT (decl) = func_tree; } @@ -2178,7 +2202,7 @@ label_address (tree label, location_t location) // Declare or define a new function. tree -function (tree functype, const std::string &name, const std::string &asm_name, +function (tree functype, GGC::Ident name, tl::optional<GGC::Ident> asm_name, unsigned int flags, location_t location) { if (error_operand_p (functype)) @@ -2186,13 +2210,13 @@ function (tree functype, const std::string &name, const std::string &asm_name, gcc_assert (FUNCTION_POINTER_TYPE_P (functype)); functype = TREE_TYPE (functype); - tree id = get_identifier_from_string (name); + tree id = name.as_tree (); if (error_operand_p (id)) return error_mark_node; tree decl = build_decl (location, FUNCTION_DECL, id, functype); - if (!asm_name.empty ()) - SET_DECL_ASSEMBLER_NAME (decl, get_identifier_from_string (asm_name)); + if (asm_name.has_value ()) + SET_DECL_ASSEMBLER_NAME (decl, asm_name->as_tree ()); if ((flags & function_is_declaration) != 0) DECL_EXTERNAL (decl) = 1; @@ -2235,7 +2259,7 @@ function_defer_statement (tree function, tree undefer_tree, tree defer_tree, push_cfun (DECL_STRUCT_FUNCTION (function)); tree stmt_list = NULL; - tree label = Backend::label (function, "", location); + tree label = Backend::label (function, tl::nullopt, location); tree label_def = label_definition_statement (label); append_to_statement_list (label_def, &stmt_list); @@ -2342,4 +2366,30 @@ write_global_definitions (const std::vector<tree> &type_decls, delete[] defs; } +tree +lookup_field (const_tree type, tree component) +{ + tree field; + + for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (DECL_NAME (field) == NULL_TREE + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))) + { + tree anon = lookup_field (TREE_TYPE (field), component); + + if (anon) + return tree_cons (NULL_TREE, field, anon); + } + + if (DECL_NAME (field) == component) + break; + } + + if (field == NULL_TREE) + return NULL_TREE; + + return tree_cons (NULL_TREE, field, NULL_TREE); +} + } // namespace Backend diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc index f3a155d..93ce041 100644 --- a/gcc/rust/rust-lang.cc +++ b/gcc/rust/rust-lang.cc @@ -51,10 +51,10 @@ // FIXME: test saving intellisense #include "options.h" -// version check to stop compiling if c++ isn't c++11 or higher -#if __cplusplus < 201103 +// version check to stop compiling if c++ isn't c++14 or higher +#if __cplusplus < 201402 #error \ - "GCC Rust frontend requires C++11 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." + "GCC Rust frontend requires C++14 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." #endif // TODO: is this best way to do it? Is it allowed? (should be) @@ -373,7 +373,13 @@ rust_localize_identifier (const char *ident) return identifier_to_locale (ident); } -extern const attribute_spec grs_langhook_common_attribute_table[]; +extern const struct scoped_attribute_specs grs_langhook_gnu_attribute_table; +extern const struct scoped_attribute_specs grs_langhook_common_attribute_table; + +const scoped_attribute_specs *const grs_langhook_attribute_table[] = { + &grs_langhook_gnu_attribute_table, + &grs_langhook_common_attribute_table, +}; /* The language hooks data structure. This is the main interface between the GCC * front-end and the GCC middle-end/back-end. A list of language hooks could be @@ -394,8 +400,7 @@ extern const attribute_spec grs_langhook_common_attribute_table[]; #undef LANG_HOOKS_WRITE_GLOBALS #undef LANG_HOOKS_GIMPLIFY_EXPR #undef LANG_HOOKS_EH_PERSONALITY - -#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE +#undef LANG_HOOKS_ATTRIBUTE_TABLE #define LANG_HOOKS_NAME "GNU Rust" #define LANG_HOOKS_INIT grs_langhook_init @@ -417,7 +422,7 @@ extern const attribute_spec grs_langhook_common_attribute_table[]; #define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr #define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality -#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE grs_langhook_common_attribute_table +#define LANG_HOOKS_ATTRIBUTE_TABLE grs_langhook_attribute_table #if CHECKING_P diff --git a/gcc/rust/rust-object-export.h b/gcc/rust/rust-object-export.h index fe055c3..784fef3 100644 --- a/gcc/rust/rust-object-export.h +++ b/gcc/rust/rust-object-export.h @@ -21,13 +21,10 @@ #include "rust-system.h" -extern unsigned int -rust_field_alignment (tree t); - -extern const char * -rust_read_export_data (int fd, off_t offset, char **pbuf, size_t *plen, - int *perr); -extern void -rust_write_export_data (const char *bytes, unsigned int size); +extern unsigned int rust_field_alignment (tree t); + +extern const char *rust_read_export_data (int fd, off_t offset, char **pbuf, + size_t *plen, int *perr); +extern void rust_write_export_data (const char *bytes, unsigned int size); #endif // RUST_OBJECT_EXPORT_H diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index 48acbf34..17f9c06 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -20,7 +20,9 @@ #include "rust-collect-lang-items.h" #include "rust-desugar-for-loops.h" #include "rust-desugar-question-mark.h" +#include "rust-desugar-apit.h" #include "rust-diagnostics.h" +#include "rust-expression-yeast.h" #include "rust-hir-pattern-analysis.h" #include "rust-immutable-name-resolution-context.h" #include "rust-unsafe-checker.h" @@ -61,11 +63,9 @@ #include "tm.h" #include "rust-target.h" -extern bool -saw_errors (void); +extern bool saw_errors (void); -extern Linemap * -rust_get_linemap (); +extern Linemap *rust_get_linemap (); namespace Rust { @@ -150,9 +150,9 @@ validate_crate_name (const std::string &crate_name, Error &error) { if (!(is_alphabetic (c.value) || is_numeric (c.value) || c.value == '_')) { - error = Error (UNDEF_LOCATION, - "invalid character %qs in crate name: %qs", - c.as_string ().c_str (), crate_name.c_str ()); + error + = Error (UNDEF_LOCATION, "invalid character %qs in crate name: %qs", + c.as_string ().c_str (), crate_name.c_str ()); return false; } } @@ -203,14 +203,16 @@ Session::handle_option ( switch (code) { case OPT_I: - case OPT_L: { + case OPT_L: + { // TODO: add search path const std::string p = std::string (arg); add_search_path (p); } break; - case OPT_frust_extern_: { + case OPT_frust_extern_: + { std::string input (arg); ret = handle_extern_option (input); } @@ -251,7 +253,8 @@ Session::handle_option ( Compile::Mangler::set_mangling (flag_rust_mangling); break; - case OPT_frust_cfg_: { + case OPT_frust_cfg_: + { auto string_arg = std::string (arg); ret = handle_cfg_option (string_arg); break; @@ -617,9 +620,6 @@ Session::compile_crate (const char *filename) expansion (parsed_crate, name_resolution_ctx); - AST::DesugarForLoops ().go (parsed_crate); - AST::DesugarQuestionMark ().go (parsed_crate); - rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) { @@ -682,6 +682,7 @@ Session::compile_crate (const char *filename) Resolver2_0::ImmutableNameResolutionContext::init (name_resolution_ctx); // type resolve + Compile::Context *ctx = Compile::Context::get (); Resolver::TypeResolution::Resolve (hir); Resolver::TypeCheckContext::get ()->get_variance_analysis_ctx ().solve (); @@ -729,16 +730,15 @@ Session::compile_crate (const char *filename) return; // do compile to gcc generic - Compile::Context ctx; - Compile::CompileCrate::Compile (hir, &ctx); + Compile::CompileCrate::Compile (hir, ctx); // we can't do static analysis if there are errors to worry about if (!saw_errors ()) { // lints Analysis::ScanDeadcode::Scan (hir); - Analysis::UnusedVariables::Lint (ctx); - Analysis::ReadonlyCheck::Lint (ctx); + Analysis::UnusedVariables::Lint (*ctx); + Analysis::ReadonlyCheck::Lint (*ctx); // metadata bool specified_emit_metadata @@ -759,7 +759,7 @@ Session::compile_crate (const char *filename) } // pass to GCC middle-end - ctx.write_to_backend (); + ctx->write_to_backend (); } void @@ -983,6 +983,20 @@ Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx) rust_error_at (range, "reached recursion limit"); } + // handle AST desugaring + if (!saw_errors ()) + { + AST::ExpressionYeast ().go (crate); + + AST::DesugarApit ().go (crate); + + // HACK: we may need a final TopLevel pass + // however, this should not count towards the recursion limit + // and we don't need a full Early pass + if (flag_name_resolution_2_0) + Resolver2_0::TopLevel (ctx).go (crate); + } + // error reporting - check unused macros, get missing fragment specifiers // build test harness @@ -1108,8 +1122,7 @@ Session::load_extern_crate (const std::string &crate_name, location_t locus) if (stream == NULL // No stream and && proc_macros.empty ()) // no proc macros { - rust_error_at (locus, "failed to locate crate %qs", - import_name.c_str ()); + rust_error_at (locus, "failed to locate crate %qs", import_name.c_str ()); return UNKNOWN_NODEID; } @@ -1177,16 +1190,13 @@ Session::load_extern_crate (const std::string &crate_name, location_t locus) mappings.insert_bang_proc_macros (crate_num, bang_macros); mappings.insert_derive_proc_macros (crate_num, derive_macros); - // name resolve it - Resolver::NameResolution::Resolve (parsed_crate); - - // perform hir lowering - std::unique_ptr<HIR::Crate> lowered - = HIR::ASTLowering::Resolve (parsed_crate); - HIR::Crate &hir = mappings.insert_hir_crate (std::move (lowered)); - - // perform type resolution - Resolver::TypeResolution::Resolve (hir); + // if flag_name_resolution_2_0 is enabled + // then we perform resolution later + if (!flag_name_resolution_2_0) + { + // name resolve it + Resolver::NameResolution::Resolve (parsed_crate); + } // always restore the crate_num mappings.set_current_crate (saved_crate_num); diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h index 83ba121..9af103c 100644 --- a/gcc/rust/rust-session-manager.h +++ b/gcc/rust/rust-session-manager.h @@ -441,8 +441,7 @@ private: #if CHECKING_P namespace selftest { -extern void -rust_crate_name_validation_test (void); +extern void rust_crate_name_validation_test (void); } #endif // CHECKING_P diff --git a/gcc/rust/rust-system.h b/gcc/rust/rust-system.h index 986428b..a455123 100644 --- a/gcc/rust/rust-system.h +++ b/gcc/rust/rust-system.h @@ -88,10 +88,8 @@ constexpr static const char *file_separator = "/"; */ #define rust_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__)) -extern void -rust_preserve_from_gc (tree t); +extern void rust_preserve_from_gc (tree t); -extern const char * -rust_localize_identifier (const char *ident); +extern const char *rust_localize_identifier (const char *ident); #endif // !defined(RUST_SYSTEM_H) diff --git a/gcc/rust/rust-target.h b/gcc/rust/rust-target.h index dbc2baf..e61ea51 100644 --- a/gcc/rust/rust-target.h +++ b/gcc/rust/rust-target.h @@ -26,8 +26,7 @@ #include "rust-target.def" /* Used by target to add target-related info. */ -extern void -rust_add_target_info (const char *, const char *); +extern void rust_add_target_info (const char *, const char *); /* Each target can provide their own. */ extern struct gcc_targetrustm targetrustm; diff --git a/gcc/rust/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc index 6aa20a8..10a59bd 100644 --- a/gcc/rust/typecheck/rust-autoderef.cc +++ b/gcc/rust/typecheck/rust-autoderef.cc @@ -26,8 +26,7 @@ namespace Rust { namespace Resolver { -static bool -resolve_operator_overload_fn ( +static bool resolve_operator_overload_fn ( LangItem::Kind lang_item_type, TyTy::BaseType *ty, TyTy::FnType **resolved_fn, Adjustment::AdjustmentType *requires_ref_adjustment); @@ -248,7 +247,6 @@ resolve_operator_overload_fn ( const TyTy::ADTType *adt = static_cast<const TyTy::ADTType *> (lhs); auto s = fn->get_self_type ()->get_root (); - rust_assert (s->can_eq (adt, false)); rust_assert (s->get_kind () == TyTy::TypeKind::ADT); const TyTy::ADTType *self_adt = static_cast<const TyTy::ADTType *> (s); diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc index 90bdef1..f06d9ed 100644 --- a/gcc/rust/typecheck/rust-casts.cc +++ b/gcc/rust/typecheck/rust-casts.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "rust-casts.h" +#include "rust-tyty-util.h" namespace Rust { namespace Resolver { @@ -28,15 +29,20 @@ TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from, TypeCoercionRules::CoercionResult TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from, - TyTy::TyWithLocation to) + TyTy::TyWithLocation to, bool emit_error) { TypeCastRules cast_rules (locus, from, to); - return cast_rules.check (); + return cast_rules.check (emit_error); } TypeCoercionRules::CoercionResult -TypeCastRules::check () +TypeCastRules::check (bool emit_error) { + // try the simple cast rules + auto simple_cast = cast_rules (); + if (!simple_cast.is_error ()) + return simple_cast; + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582 auto possible_coercion = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus, @@ -51,13 +57,9 @@ TypeCastRules::check () true /*is_cast_site*/); } - // try the simple cast rules - auto simple_cast = cast_rules (); - if (!simple_cast.is_error ()) - return simple_cast; + if (emit_error) + TypeCastRules::emit_cast_error (locus, from, to); - // failed to cast - emit_cast_error (); return TypeCoercionRules::CoercionResult::get_error (); } @@ -73,7 +75,8 @@ TypeCastRules::cast_rules () to.get_ty ()->debug_str ().c_str ()); switch (from_type->get_kind ()) { - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *from_infer = static_cast<TyTy::InferType *> (from_type); switch (from_infer->get_infer_kind ()) @@ -85,7 +88,8 @@ TypeCastRules::cast_rules () case TyTy::InferType::InferTypeKind::INTEGRAL: switch (to.get_ty ()->get_kind ()) { - case TyTy::TypeKind::CHAR: { + case TyTy::TypeKind::CHAR: + { // only u8 and char bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT; @@ -108,7 +112,8 @@ TypeCastRules::cast_rules () return TypeCoercionRules::CoercionResult{ {}, to.get_ty ()->clone ()}; - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *to_infer = static_cast<TyTy::InferType *> (to.get_ty ()); @@ -140,7 +145,8 @@ TypeCastRules::cast_rules () return TypeCoercionRules::CoercionResult{ {}, to.get_ty ()->clone ()}; - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *to_infer = static_cast<TyTy::InferType *> (to.get_ty ()); @@ -187,7 +193,8 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::INT: switch (to.get_ty ()->get_kind ()) { - case TyTy::TypeKind::CHAR: { + case TyTy::TypeKind::CHAR: + { // only u8 and char bool was_uint = from.get_ty ()->get_kind () == TyTy::TypeKind::UINT; bool was_u8 = was_uint @@ -200,7 +207,8 @@ TypeCastRules::cast_rules () } break; - case TyTy::TypeKind::FLOAT: { + case TyTy::TypeKind::FLOAT: + { // can only do this for number types not char bool from_char = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR; @@ -210,7 +218,8 @@ TypeCastRules::cast_rules () } break; - case TyTy::TypeKind::POINTER: { + case TyTy::TypeKind::POINTER: + { // char can't be casted as a ptr bool from_char = from.get_ty ()->get_kind () == TyTy::TypeKind::CHAR; @@ -244,7 +253,8 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::FLOAT: return TypeCoercionRules::CoercionResult{{}, to.get_ty ()->clone ()}; - case TyTy::TypeKind::INFER: { + case TyTy::TypeKind::INFER: + { TyTy::InferType *to_infer = static_cast<TyTy::InferType *> (to.get_ty ()); @@ -273,7 +283,8 @@ TypeCastRules::cast_rules () case TyTy::TypeKind::USIZE: case TyTy::TypeKind::ISIZE: case TyTy::TypeKind::UINT: - case TyTy::TypeKind::INT: { + case TyTy::TypeKind::INT: + { // refs should not cast to numeric type bool from_ptr = from.get_ty ()->get_kind () == TyTy::TypeKind::POINTER; @@ -320,7 +331,27 @@ TypeCastRules::check_ptr_ptr_cast () } else if (from_is_ref && to_is_ref) { - // mutability must be coercedable + const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> (); + const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> (); + + if (from_ref.is_dyn_object () != to_ref.is_dyn_object ()) + { + // this needs to be handled by coercion logic + return TypeCoercionRules::CoercionResult::get_error (); + } + + // are the underlying types safely simple castable? + const auto to_underly = to_ref.get_base (); + const auto from_underly = from_ref.get_base (); + auto res = resolve (locus, TyTy::TyWithLocation (from_underly), + TyTy::TyWithLocation (to_underly), false); + if (res.is_error ()) + { + // this needs to be handled by coercion logic + return TypeCoercionRules::CoercionResult::get_error (); + } + + // mutability must be coerceable TyTy::ReferenceType &f = static_cast<TyTy::ReferenceType &> (*from.get_ty ()); TyTy::ReferenceType &t @@ -337,7 +368,8 @@ TypeCastRules::check_ptr_ptr_cast () } void -TypeCastRules::emit_cast_error () const +TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from, + TyTy::TyWithLocation to) { rich_location r (line_table, locus); r.add_range (from.get_locus ()); diff --git a/gcc/rust/typecheck/rust-casts.h b/gcc/rust/typecheck/rust-casts.h index 0d6ed68..10bb006 100644 --- a/gcc/rust/typecheck/rust-casts.h +++ b/gcc/rust/typecheck/rust-casts.h @@ -30,15 +30,17 @@ class TypeCastRules public: static TypeCoercionRules::CoercionResult resolve (location_t locus, TyTy::TyWithLocation from, - TyTy::TyWithLocation to); + TyTy::TyWithLocation to, + bool emit_error = true); + + static void emit_cast_error (location_t locus, TyTy::TyWithLocation from, + TyTy::TyWithLocation to); protected: - TypeCoercionRules::CoercionResult check (); + TypeCoercionRules::CoercionResult check (bool emit_error); TypeCoercionRules::CoercionResult cast_rules (); TypeCoercionRules::CoercionResult check_ptr_ptr_cast (); - void emit_cast_error () const; - protected: TypeCastRules (location_t locus, TyTy::TyWithLocation from, TyTy::TyWithLocation to); diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index 5905992..fd12839 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -125,13 +125,15 @@ TypeCoercionRules::do_coercion (TyTy::BaseType *receiver) // pointers switch (expected->get_kind ()) { - case TyTy::TypeKind::POINTER: { + case TyTy::TypeKind::POINTER: + { TyTy::PointerType *ptr = static_cast<TyTy::PointerType *> (expected); try_result = coerce_unsafe_ptr (receiver, ptr, ptr->mutability ()); return !try_result.is_error (); } - case TyTy::TypeKind::REF: { + case TyTy::TypeKind::REF: + { TyTy::ReferenceType *ptr = static_cast<TyTy::ReferenceType *> (expected); try_result @@ -147,7 +149,8 @@ TypeCoercionRules::do_coercion (TyTy::BaseType *receiver) // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L210 switch (receiver->get_kind ()) { - default: { + default: + { rust_debug ( "do_coercion default unify and infer expected: %s receiver %s", receiver->debug_str ().c_str (), expected->debug_str ().c_str ()); @@ -182,7 +185,8 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, TyTy::BaseType *element = nullptr; switch (receiver->get_kind ()) { - case TyTy::TypeKind::REF: { + case TyTy::TypeKind::REF: + { TyTy::ReferenceType *ref = static_cast<TyTy::ReferenceType *> (receiver); from_mutbl = ref->mutability (); @@ -190,16 +194,19 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, } break; - case TyTy::TypeKind::POINTER: { + case TyTy::TypeKind::POINTER: + { TyTy::PointerType *ref = static_cast<TyTy::PointerType *> (receiver); from_mutbl = ref->mutability (); element = ref->get_base (); } break; - default: { - // FIXME this can probably turn into a unify_and - if (receiver->can_eq (expected, false)) + default: + { + if (types_compatable (TyTy::TyWithLocation (receiver), + TyTy::TyWithLocation (expected), UNKNOWN_LOCATION, + false)) return CoercionResult{{}, expected->clone ()}; return CoercionResult::get_error (); @@ -264,17 +271,16 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, Mutability from_mutbl = Mutability::Imm; switch (receiver->get_kind ()) { - case TyTy::TypeKind::REF: { + case TyTy::TypeKind::REF: + { TyTy::ReferenceType *from = static_cast<TyTy::ReferenceType *> (receiver); from_mutbl = from->mutability (); } break; - default: { - // FIXME - // we might be able to replace this with a can_eq because we default - // back to a final unity anyway + default: + { rust_debug ("coerce_borrowed_pointer -- unify"); TyTy::BaseType *result = unify_site_and (receiver->get_ref (), @@ -393,7 +399,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, if (expect_dyn && need_unsize) { - bool bounds_compatible = b->bounds_compatible (*a, locus, true); + bool bounds_compatible = b->bounds_compatible (*a, locus, false); if (!bounds_compatible) { unsafe_error = true; diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.cc b/gcc/rust/typecheck/rust-hir-dot-operator.cc index c1165e9..7b7944c 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.cc +++ b/gcc/rust/typecheck/rust-hir-dot-operator.cc @@ -102,26 +102,16 @@ MethodResolver::try_hook (const TyTy::BaseType &r) } } -bool -MethodResolver::select (TyTy::BaseType &receiver) +std::vector<MethodResolver::impl_item_candidate> +MethodResolver::assemble_inherent_impl_candidates ( + const TyTy::BaseType &receiver) { - rust_debug ("MethodResolver::select reciever=[%s] path=[%s]", - receiver.debug_str ().c_str (), - segment_name.as_string ().c_str ()); - - struct impl_item_candidate - { - HIR::Function *item; - HIR::ImplBlock *impl_block; - TyTy::FnType *ty; - }; - + std::vector<impl_item_candidate> inherent_impl_fns; const TyTy::BaseType *raw = receiver.destructure (); bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER; bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF; - // assemble inherent impl items - std::vector<impl_item_candidate> inherent_impl_fns; + // Assemble inherent impl items (non-trait impl blocks) mappings.iterate_impl_items ( [&] (HirId id, HIR::ImplItem *item, HIR::ImplBlock *impl) mutable -> bool { bool is_trait_impl = impl->has_trait_ref (); @@ -190,16 +180,19 @@ MethodResolver::select (TyTy::BaseType &receiver) return true; }); - struct trait_item_candidate - { - const HIR::TraitItemFunc *item; - const HIR::Trait *trait; - TyTy::FnType *ty; - const TraitReference *reference; - const TraitItemReference *item_ref; - }; + return inherent_impl_fns; +} + +void +MethodResolver::assemble_trait_impl_candidates ( + const TyTy::BaseType &receiver, + std::vector<impl_item_candidate> &impl_candidates, + std::vector<trait_item_candidate> &trait_candidates) +{ + const TyTy::BaseType *raw = receiver.destructure (); + bool receiver_is_raw_ptr = raw->get_kind () == TyTy::TypeKind::POINTER; + bool receiver_is_ref = raw->get_kind () == TyTy::TypeKind::REF; - std::vector<trait_item_candidate> trait_fns; mappings.iterate_impl_blocks ([&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { bool is_trait_impl = impl->has_trait_ref (); @@ -266,7 +259,7 @@ MethodResolver::select (TyTy::BaseType &receiver) continue; } - inherent_impl_fns.push_back ({func, impl, fnty}); + impl_candidates.push_back ({func, impl, fnty}); return true; } @@ -293,26 +286,15 @@ MethodResolver::select (TyTy::BaseType &receiver) TyTy::FnType *fnty = static_cast<TyTy::FnType *> (ty); trait_item_candidate candidate{func, trait, fnty, trait_ref, item_ref}; - trait_fns.push_back (candidate); + trait_candidates.push_back (candidate); return true; }); +} - // lookup specified bounds for an associated item - struct precdicate_candidate - { - TyTy::TypeBoundPredicateItem lookup; - TyTy::FnType *fntype; - }; - - // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694 - - rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, " - "predicate_items found {%lu}", - (unsigned long) inherent_impl_fns.size (), - (unsigned long) trait_fns.size (), - (unsigned long) predicate_items.size ()); - +bool +MethodResolver::try_select_predicate_candidates (TyTy::BaseType &receiver) +{ bool found_possible_candidate = false; for (const auto &predicate : predicate_items) { @@ -346,60 +328,33 @@ MethodResolver::select (TyTy::BaseType &receiver) found_possible_candidate = true; } } - if (found_possible_candidate) - { - return true; - } + return found_possible_candidate; +} - for (auto &impl_item : inherent_impl_fns) +bool +MethodResolver::try_select_inherent_impl_candidates ( + TyTy::BaseType &receiver, const std::vector<impl_item_candidate> &candidates, + bool trait_impl_blocks_only) +{ + bool found_possible_candidate = false; + for (auto &impl_item : candidates) { bool is_trait_impl_block = impl_item.impl_block->has_trait_ref (); - if (is_trait_impl_block) + if (trait_impl_blocks_only && !is_trait_impl_block) continue; - - TyTy::FnType *fn = impl_item.ty; - rust_assert (fn->is_method ()); - - TyTy::BaseType *fn_self = fn->get_self_type (); - rust_debug ("dot-operator impl_item fn_self={%s} can_eq receiver={%s}", - fn_self->debug_str ().c_str (), - receiver.debug_str ().c_str ()); - - auto res - = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION, - false /*allow-autoderef*/); - bool ok = !res.is_error (); - if (ok) - { - std::vector<Adjustment> adjs = append_adjustments (res.adjustments); - PathProbeCandidate::ImplItemCandidate c{impl_item.item, - impl_item.impl_block}; - auto try_result = MethodCandidate{ - PathProbeCandidate (PathProbeCandidate::CandidateType::IMPL_FUNC, - fn, impl_item.item->get_locus (), c), - adjs}; - result.insert (std::move (try_result)); - found_possible_candidate = true; - } - } - if (found_possible_candidate) - { - return true; - } - - for (auto &impl_item : inherent_impl_fns) - { - bool is_trait_impl_block = impl_item.impl_block->has_trait_ref (); - if (!is_trait_impl_block) + if (!trait_impl_blocks_only && is_trait_impl_block) continue; TyTy::FnType *fn = impl_item.ty; rust_assert (fn->is_method ()); TyTy::BaseType *fn_self = fn->get_self_type (); - rust_debug ( - "dot-operator trait_impl_item fn_self={%s} can_eq receiver={%s}", - fn_self->debug_str ().c_str (), receiver.debug_str ().c_str ()); + + const char *debug_prefix + = trait_impl_blocks_only ? "trait_impl_item" : "impl_item"; + rust_debug ("dot-operator %s fn_self={%s} can_eq receiver={%s}", + debug_prefix, fn_self->debug_str ().c_str (), + receiver.debug_str ().c_str ()); auto res = TypeCoercionRules::TryCoerce (&receiver, fn_self, UNDEF_LOCATION, @@ -418,12 +373,15 @@ MethodResolver::select (TyTy::BaseType &receiver) found_possible_candidate = true; } } - if (found_possible_candidate) - { - return true; - } + return found_possible_candidate; +} - for (auto trait_item : trait_fns) +bool +MethodResolver::try_select_trait_impl_candidates ( + TyTy::BaseType &receiver, const std::vector<trait_item_candidate> &candidates) +{ + bool found_possible_candidate = false; + for (auto trait_item : candidates) { TyTy::FnType *fn = trait_item.ty; rust_assert (fn->is_method ()); @@ -451,10 +409,53 @@ MethodResolver::select (TyTy::BaseType &receiver) found_possible_candidate = true; } } - return found_possible_candidate; } +bool +MethodResolver::select (TyTy::BaseType &receiver) +{ + rust_debug ("MethodResolver::select reciever=[%s] path=[%s]", + receiver.debug_str ().c_str (), + segment_name.as_string ().c_str ()); + + // Assemble candidates + std::vector<impl_item_candidate> inherent_impl_fns + = assemble_inherent_impl_candidates (receiver); + std::vector<impl_item_candidate> trait_impl_fns; + std::vector<trait_item_candidate> trait_fns; + assemble_trait_impl_candidates (receiver, trait_impl_fns, trait_fns); + + // Combine inherent and trait impl functions + inherent_impl_fns.insert (inherent_impl_fns.end (), trait_impl_fns.begin (), + trait_impl_fns.end ()); + + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/method/probe.rs#L580-L694 + + rust_debug ("inherent_impl_fns found {%lu}, trait_fns found {%lu}, " + "predicate_items found {%lu}", + (unsigned long) inherent_impl_fns.size (), + (unsigned long) trait_fns.size (), + (unsigned long) predicate_items.size ()); + + // Try selection in the priority order defined by Rust's method resolution: + + // 1. Try predicate candidates first (highest priority) + if (try_select_predicate_candidates (receiver)) + return true; + + // 2. Try inherent impl functions (non-trait impl blocks) + if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns, false)) + return true; + + // 3. Try inherent impl functions from trait impl blocks + if (try_select_inherent_impl_candidates (receiver, inherent_impl_fns, true)) + return true; + + // 4. Try trait functions (lowest priority) + return try_select_trait_impl_candidates (receiver, trait_fns); +} + std::vector<MethodResolver::predicate_candidate> MethodResolver::get_predicate_items ( const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver, diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h index ab95a5a..cc40472 100644 --- a/gcc/rust/typecheck/rust-hir-dot-operator.h +++ b/gcc/rust/typecheck/rust-hir-dot-operator.h @@ -65,6 +65,22 @@ public: const HIR::PathIdentSegment &segment_name, const TyTy::BaseType &receiver, const std::vector<TyTy::TypeBoundPredicate> &specified_bounds); + struct impl_item_candidate + { + HIR::Function *item; + HIR::ImplBlock *impl_block; + TyTy::FnType *ty; + }; + + struct trait_item_candidate + { + const HIR::TraitItemFunc *item; + const HIR::Trait *trait; + TyTy::FnType *ty; + const TraitReference *reference; + const TraitItemReference *item_ref; + }; + protected: MethodResolver (bool autoderef_flag, const HIR::PathIdentSegment &segment_name); @@ -77,6 +93,25 @@ private: std::vector<Adjustment> append_adjustments (const std::vector<Adjustment> &adjustments) const; + std::vector<impl_item_candidate> + assemble_inherent_impl_candidates (const TyTy::BaseType &receiver); + + void assemble_trait_impl_candidates ( + const TyTy::BaseType &receiver, + std::vector<impl_item_candidate> &impl_candidates, + std::vector<trait_item_candidate> &trait_candidates); + + bool try_select_predicate_candidates (TyTy::BaseType &receiver); + + bool try_select_inherent_impl_candidates ( + TyTy::BaseType &receiver, + const std::vector<impl_item_candidate> &candidates, + bool trait_impl_blocks_only); + + bool try_select_trait_impl_candidates ( + TyTy::BaseType &receiver, + const std::vector<trait_item_candidate> &candidates); + private: // search const HIR::PathIdentSegment &segment_name; diff --git a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h index 5537b14..a66396f 100644 --- a/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h +++ b/gcc/rust/typecheck/rust-hir-inherent-impl-overlap.h @@ -79,27 +79,29 @@ public: if (query == candidate) continue; - if (query->can_eq (candidate, false)) + if (!types_compatable (TyTy::TyWithLocation (query), + TyTy::TyWithLocation (candidate), + UNKNOWN_LOCATION, false)) + continue; + + // we might be in the case that we have: + // + // *const T vs *const [T] + // + // so lets use an equality check when the + // candidates are both generic to be sure we dont emit a false + // positive + + bool a = query->is_concrete (); + bool b = candidate->is_concrete (); + bool both_generic = !a && !b; + if (both_generic) { - // we might be in the case that we have: - // - // *const T vs *const [T] - // - // so lets use an equality check when the - // candidates are both generic to be sure we dont emit a false - // positive - - bool a = query->is_concrete (); - bool b = candidate->is_concrete (); - bool both_generic = !a && !b; - if (both_generic) - { - if (!query->is_equal (*candidate)) - continue; - } - - possible_collision (it->second, iy->second); + if (!query->is_equal (*candidate)) + continue; } + + possible_collision (it->second, iy->second); } } } diff --git a/gcc/rust/typecheck/rust-hir-path-probe.cc b/gcc/rust/typecheck/rust-hir-path-probe.cc index 32e2399..c02702f 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.cc +++ b/gcc/rust/typecheck/rust-hir-path-probe.cc @@ -137,7 +137,7 @@ PathProbeCandidate::operator< (const PathProbeCandidate &c) const // PathProbeType -PathProbeType::PathProbeType (const TyTy::BaseType *receiver, +PathProbeType::PathProbeType (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query, DefId specific_trait_id) : TypeCheckBase (), receiver (receiver), search (query), @@ -145,7 +145,7 @@ PathProbeType::PathProbeType (const TyTy::BaseType *receiver, {} std::set<PathProbeCandidate> -PathProbeType::Probe (const TyTy::BaseType *receiver, +PathProbeType::Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, bool probe_impls, bool probe_bounds, bool ignore_mandatory_trait_items, @@ -443,7 +443,7 @@ PathProbeType::is_receiver_generic () const // PathProbImplTrait -PathProbeImplTrait::PathProbeImplTrait (const TyTy::BaseType *receiver, +PathProbeImplTrait::PathProbeImplTrait (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query, const TraitReference *trait_reference) : PathProbeType (receiver, query, UNKNOWN_DEFID), @@ -451,7 +451,7 @@ PathProbeImplTrait::PathProbeImplTrait (const TyTy::BaseType *receiver, {} std::set<PathProbeCandidate> -PathProbeImplTrait::Probe (const TyTy::BaseType *receiver, +PathProbeImplTrait::Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, const TraitReference *trait_reference) { diff --git a/gcc/rust/typecheck/rust-hir-path-probe.h b/gcc/rust/typecheck/rust-hir-path-probe.h index 59ffeb1..936bcb9 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.h +++ b/gcc/rust/typecheck/rust-hir-path-probe.h @@ -108,9 +108,8 @@ class PathProbeType : public TypeCheckBase, public HIR::HIRImplVisitor { public: static std::set<PathProbeCandidate> - Probe (const TyTy::BaseType *receiver, - const HIR::PathIdentSegment &segment_name, bool probe_impls, - bool probe_bounds, bool ignore_mandatory_trait_items, + Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, + bool probe_impls, bool probe_bounds, bool ignore_mandatory_trait_items, DefId specific_trait_id = UNKNOWN_DEFID); void visit (HIR::TypeAlias &alias) override; @@ -135,8 +134,8 @@ protected: bool ignore_mandatory_trait_items); protected: - PathProbeType (const TyTy::BaseType *receiver, - const HIR::PathIdentSegment &query, DefId specific_trait_id); + PathProbeType (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query, + DefId specific_trait_id); std::vector<std::pair<const TraitReference *, HIR::ImplBlock *>> union_bounds ( @@ -147,7 +146,7 @@ protected: bool is_receiver_generic () const; - const TyTy::BaseType *receiver; + TyTy::BaseType *receiver; const HIR::PathIdentSegment &search; std::set<PathProbeCandidate> candidates; HIR::ImplBlock *current_impl; @@ -178,12 +177,11 @@ class PathProbeImplTrait : public PathProbeType { public: static std::set<PathProbeCandidate> - Probe (const TyTy::BaseType *receiver, - const HIR::PathIdentSegment &segment_name, + Probe (TyTy::BaseType *receiver, const HIR::PathIdentSegment &segment_name, const TraitReference *trait_reference); private: - PathProbeImplTrait (const TyTy::BaseType *receiver, + PathProbeImplTrait (TyTy::BaseType *receiver, const HIR::PathIdentSegment &query, const TraitReference *trait_reference); diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc index 83985f0..74856f0 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.cc +++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc @@ -342,7 +342,15 @@ TraitReference::on_resolved () { for (auto &item : item_refs) { - item.on_resolved (); + if (item.get_trait_item_type () + == TraitItemReference::TraitItemType::TYPE) + item.on_resolved (); + } + for (auto &item : item_refs) + { + if (item.get_trait_item_type () + != TraitItemReference::TraitItemType::TYPE) + item.on_resolved (); } } @@ -424,7 +432,13 @@ TraitReference::trait_has_generics () const return !trait_substs.empty (); } -std::vector<TyTy::SubstitutionParamMapping> +std::vector<TyTy::SubstitutionParamMapping> & +TraitReference::get_trait_substs () +{ + return trait_substs; +} + +const std::vector<TyTy::SubstitutionParamMapping> & TraitReference::get_trait_substs () const { return trait_substs; diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h index 8b1ac7d..473513e 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.h +++ b/gcc/rust/typecheck/rust-hir-trait-reference.h @@ -224,7 +224,9 @@ public: bool trait_has_generics () const; - std::vector<TyTy::SubstitutionParamMapping> get_trait_substs () const; + std::vector<TyTy::SubstitutionParamMapping> &get_trait_substs (); + + const std::vector<TyTy::SubstitutionParamMapping> &get_trait_substs () const; bool satisfies_bound (const TraitReference &reference) const; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 032bb58..0fd0147 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -22,9 +22,6 @@ #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" -// used for flag_name_resolution_2_0 -#include "options.h" - namespace Rust { namespace Resolver { @@ -123,28 +120,16 @@ bool TraitResolver::resolve_path_to_trait (const HIR::TypePath &path, HIR::Trait **resolved) const { + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + NodeId ref; - bool ok; - if (flag_name_resolution_2_0) + if (auto ref_opt = nr_ctx.lookup (path.get_mappings ().get_nodeid ())) { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - auto ref_opt = nr_ctx.lookup (path.get_mappings ().get_nodeid ()); - - if ((ok = ref_opt.has_value ())) - ref = *ref_opt; + ref = *ref_opt; } else { - auto path_nodeid = path.get_mappings ().get_nodeid (); - ok = resolver->lookup_resolved_type (path_nodeid, &ref) - || resolver->lookup_resolved_name (path_nodeid, &ref) - || resolver->lookup_resolved_macro (path_nodeid, &ref); - } - - if (!ok) - { rust_error_at (path.get_locus (), "Failed to resolve path to node-id"); return false; } @@ -224,7 +209,8 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) // handling. break; - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { auto &typaram = static_cast<HIR::TypeParam &> (*generic_param); bool is_self = typaram.get_type_representation ().as_string ().compare ("Self") @@ -287,7 +273,8 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) auto predicate = get_predicate_from_bound ( b->get_path (), - tl::nullopt /*this will setup a PLACEHOLDER for self*/); + tl::nullopt /*this will setup a PLACEHOLDER for self*/, + BoundPolarity::RegularBound, false, true); if (predicate.is_error ()) return &TraitReference::error_node (); @@ -443,11 +430,27 @@ TraitItemReference::associated_type_set (TyTy::BaseType *ty) const { rust_assert (get_trait_item_type () == TraitItemType::TYPE); + // this isnt super safe there are cases like the FnTraits where the type is + // set to the impls placeholder associated type. For example + // + // type Output = F::Output; -- see the fn trait impls in libcore + // + // then this projection ends up resolving back to this placeholder so it just + // ends up being cyclical + TyTy::BaseType *item_ty = get_tyty (); rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER); TyTy::PlaceholderType *placeholder = static_cast<TyTy::PlaceholderType *> (item_ty); + if (ty->is<TyTy::ProjectionType> ()) + { + const auto &projection = *static_cast<const TyTy::ProjectionType *> (ty); + const auto resolved = projection.get (); + if (resolved == item_ty) + return; + } + placeholder->set_associated_type (ty->get_ty_ref ()); } @@ -543,7 +546,8 @@ AssociatedImplTrait::setup_associated_types ( // handling. break; - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { TyTy::BaseType *l = nullptr; bool ok = context->lookup_type ( generic_param->get_mappings ().get_hirid (), &l); @@ -580,8 +584,8 @@ AssociatedImplTrait::setup_associated_types ( } else { - TyTy::ParamType *param = p.get_param_ty (); - TyTy::BaseType *resolved = param->destructure (); + auto param = p.get_param_ty (); + auto resolved = param->destructure (); subst_args.push_back (TyTy::SubstitutionArg (&p, resolved)); param_mappings[param->get_symbol ()] = resolved->get_ref (); } @@ -609,8 +613,8 @@ AssociatedImplTrait::setup_associated_types ( if (i == 0) continue; - const TyTy::ParamType *p = arg.get_param_ty (); - TyTy::BaseType *r = p->resolve (); + const auto p = arg.get_param_ty (); + auto r = p->resolve (); if (!r->is_concrete ()) { r = SubstMapperInternal::Resolve (r, infer_arguments); @@ -626,8 +630,8 @@ AssociatedImplTrait::setup_associated_types ( if (i == 0) continue; - const TyTy::ParamType *p = arg.get_param_ty (); - TyTy::BaseType *r = p->resolve (); + const auto p = arg.get_param_ty (); + auto r = p->resolve (); if (!r->is_concrete ()) { r = SubstMapperInternal::Resolve (r, infer_arguments); @@ -753,7 +757,8 @@ TraitItemReference::is_object_safe () const // https://doc.rust-lang.org/reference/items/traits.html#object-safety switch (get_trait_item_type ()) { - case TraitItemReference::TraitItemType::FN: { + case TraitItemReference::TraitItemType::FN: + { // lets be boring and just check that this is indeed a method will do // for now const HIR::TraitItem *item = get_hir_trait_item (); diff --git a/gcc/rust/typecheck/rust-hir-type-bounds.h b/gcc/rust/typecheck/rust-hir-type-bounds.h index 82333f1..5384700 100644 --- a/gcc/rust/typecheck/rust-hir-type-bounds.h +++ b/gcc/rust/typecheck/rust-hir-type-bounds.h @@ -37,7 +37,11 @@ public: private: void scan (); - void assemble_sized_builtin (); + bool + process_impl_block (HirId id, HIR::ImplBlock *impl, + std::vector<std::pair<HIR::TypePath *, HIR::ImplBlock *>> + &possible_trait_paths); + void assemble_marker_builtins (); void add_trait_bound (HIR::Trait *trait); void assemble_builtin_candidate (LangItem::Kind item); diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index 14b8ab8..68001bf 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -17,28 +17,33 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check-base.h" +#include "rust-compile-base.h" +#include "rust-hir-item.h" #include "rust-hir-type-check-expr.h" #include "rust-hir-type-check-type.h" #include "rust-hir-trait-resolve.h" #include "rust-type-util.h" #include "rust-attribute-values.h" +#include "rust-tyty.h" +#include "tree.h" namespace Rust { namespace Resolver { TypeCheckBase::TypeCheckBase () - : mappings (Analysis::Mappings::get ()), resolver (Resolver::get ()), - context (TypeCheckContext::get ()) + : mappings (Analysis::Mappings::get ()), context (TypeCheckContext::get ()) {} void TypeCheckBase::ResolveGenericParams ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, ABI abi) { TypeCheckBase ctx; - ctx.resolve_generic_params (generic_params, substitutions, is_foreign, abi); + ctx.resolve_generic_params (item_kind, item_locus, generic_params, + substitutions, is_foreign, abi); } static void @@ -47,10 +52,10 @@ walk_types_to_constrain (std::set<HirId> &constrained_symbols, { for (const auto &c : constraints.get_mappings ()) { - const TyTy::BaseType *arg = c.get_tyty (); + auto arg = c.get_tyty (); if (arg != nullptr) { - const TyTy::BaseType *p = arg->get_root (); + const auto p = arg->get_root (); constrained_symbols.insert (p->get_ty_ref ()); if (p->has_substitutions_defined ()) { @@ -66,7 +71,7 @@ TypeCheckBase::check_for_unconstrained ( const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain, const TyTy::SubstitutionArgumentMappings &constraint_a, const TyTy::SubstitutionArgumentMappings &constraint_b, - const TyTy::BaseType *reference) + TyTy::BaseType *reference) { bool check_result = false; bool check_completed @@ -124,7 +129,8 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, TyTy::BaseType *infered = nullptr; switch (literal.get_lit_type ()) { - case HIR::Literal::LitType::INT: { + case HIR::Literal::LitType::INT: + { bool ok = false; switch (literal.get_type_hint ()) @@ -191,7 +197,8 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, } break; - case HIR::Literal::LitType::FLOAT: { + case HIR::Literal::LitType::FLOAT: + { bool ok = false; switch (literal.get_type_hint ()) @@ -216,25 +223,29 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, } break; - case HIR::Literal::LitType::BOOL: { + case HIR::Literal::LitType::BOOL: + { auto ok = context->lookup_builtin ("bool", &infered); rust_assert (ok); } break; - case HIR::Literal::LitType::CHAR: { + case HIR::Literal::LitType::CHAR: + { auto ok = context->lookup_builtin ("char", &infered); rust_assert (ok); } break; - case HIR::Literal::LitType::BYTE: { + case HIR::Literal::LitType::BYTE: + { auto ok = context->lookup_builtin ("u8", &infered); rust_assert (ok); } break; - case HIR::Literal::LitType::STRING: { + case HIR::Literal::LitType::STRING: + { TyTy::BaseType *base = nullptr; auto ok = context->lookup_builtin ("str", &base); rust_assert (ok); @@ -246,7 +257,8 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, } break; - case HIR::Literal::LitType::BYTE_STRING: { + case HIR::Literal::LitType::BYTE_STRING: + { /* This is an arraytype of u8 reference (&[u8;size]). It isn't in UTF-8, but really just a byte array. Code to construct the array reference copied from ArrayElemsValues and ArrayType. */ @@ -280,10 +292,21 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings, crate_num), UNKNOWN_LOCAL_DEFID); + auto ctx = Compile::Context::get (); + tree capacity = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, expected_ty, *literal_capacity); + + TyTy::ConstType *capacity_expr + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", + expected_ty, capacity, {}, + literal_capacity->get_locus (), + literal_capacity->get_mappings ().get_hirid (), + literal_capacity->get_mappings ().get_hirid (), + {}); + TyTy::ArrayType *array = new TyTy::ArrayType (array_mapping.get_hirid (), locus, - *literal_capacity, - TyTy::TyVar (u8->get_ref ())); + capacity_expr, TyTy::TyVar (u8->get_ref ())); context->insert_type (array_mapping, array); infered = new TyTy::ReferenceType (expr_mappings.get_hirid (), @@ -432,6 +455,7 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) void TypeCheckBase::resolve_generic_params ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, ABI abi) @@ -440,7 +464,8 @@ TypeCheckBase::resolve_generic_params ( { switch (generic_param->get_kind ()) { - case HIR::GenericParam::GenericKind::LIFETIME: { + case HIR::GenericParam::GenericKind::LIFETIME: + { auto lifetime_param = static_cast<HIR::LifetimeParam &> (*generic_param); auto lifetime = lifetime_param.get_lifetime (); @@ -449,7 +474,8 @@ TypeCheckBase::resolve_generic_params ( } break; - case HIR::GenericParam::GenericKind::CONST: { + case HIR::GenericParam::GenericKind::CONST: + { if (is_foreign && abi != Rust::ABI::INTRINSIC) { rust_error_at (generic_param->get_locus (), ErrorCode::E0044, @@ -462,6 +488,27 @@ TypeCheckBase::resolve_generic_params ( if (param.has_default_expression ()) { + switch (item_kind) + { + case HIR::Item::ItemKind::Struct: + case HIR::Item::ItemKind::Enum: + case HIR::Item::ItemKind::TypeAlias: + case HIR::Item::ItemKind::Trait: + case HIR::Item::ItemKind::Union: + break; + + default: + { + rich_location r (line_table, item_locus); + r.add_fixit_remove (param.get_locus ()); + rust_error_at ( + r, + "default values for const generic parameters are not " + "allowed here"); + } + break; + } + auto expr_type = TypeCheckExpr::Resolve (param.get_default_expression ()); @@ -471,14 +518,39 @@ TypeCheckBase::resolve_generic_params ( expr_type, param.get_default_expression ().get_locus ()), param.get_locus ()); + + // fold the default value + auto ctx = Compile::Context::get (); + auto &expr = param.get_default_expression (); + tree default_value + = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, specified_type, expr); + + TyTy::ConstType *default_const_decl + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + param.get_name (), specified_type, + default_value, {}, param.get_locus (), + expr.get_mappings ().get_hirid (), + expr.get_mappings ().get_hirid (), {}); + + context->insert_type (expr.get_mappings (), default_const_decl); } - context->insert_type (generic_param->get_mappings (), - specified_type); + TyTy::ConstType *const_decl + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Decl, + param.get_name (), specified_type, + error_mark_node, {}, param.get_locus (), + param.get_mappings ().get_hirid (), + param.get_mappings ().get_hirid (), {}); + + context->insert_type (generic_param->get_mappings (), const_decl); + TyTy::SubstitutionParamMapping p (*generic_param, const_decl); + substitutions.push_back (p); } break; - case HIR::GenericParam::GenericKind::TYPE: { + case HIR::GenericParam::GenericKind::TYPE: + { if (is_foreign && abi != Rust::ABI::INTRINSIC) { rust_error_at (generic_param->get_locus (), ErrorCode::E0044, @@ -489,8 +561,7 @@ TypeCheckBase::resolve_generic_params ( *generic_param, false /*resolve_trait_bounds*/); context->insert_type (generic_param->get_mappings (), param_type); - auto ¶m = static_cast<HIR::TypeParam &> (*generic_param); - TyTy::SubstitutionParamMapping p (param, param_type); + TyTy::SubstitutionParamMapping p (*generic_param, param_type); substitutions.push_back (p); } break; @@ -500,9 +571,16 @@ TypeCheckBase::resolve_generic_params ( // now walk them to setup any specified type param bounds for (auto &subst : substitutions) { - auto pty = subst.get_param_ty (); - TypeResolveGenericParam::ApplyAnyTraitBounds (subst.get_generic_param (), - pty); + auto &generic = subst.get_generic_param (); + if (generic.get_kind () != HIR::GenericParam::GenericKind::TYPE) + continue; + + auto &type_param = static_cast<HIR::TypeParam &> (generic); + auto bpty = subst.get_param_ty (); + rust_assert (bpty->get_kind () == TyTy::TypeKind::PARAM); + auto pty = static_cast<TyTy::ParamType *> (bpty); + + TypeResolveGenericParam::ApplyAnyTraitBounds (type_param, pty); } } diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h b/gcc/rust/typecheck/rust-hir-type-check-base.h index 580082a..6430089 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.h +++ b/gcc/rust/typecheck/rust-hir-type-check-base.h @@ -33,6 +33,7 @@ public: virtual ~TypeCheckBase () {} static void ResolveGenericParams ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign, ABI abi); @@ -46,13 +47,13 @@ protected: HIR::TypePath &path, tl::optional<std::reference_wrapper<HIR::Type>> associated_self, BoundPolarity polarity = BoundPolarity::RegularBound, - bool is_qualified_type = false); + bool is_qualified_type = false, bool is_super_trait = false); bool check_for_unconstrained ( const std::vector<TyTy::SubstitutionParamMapping> ¶ms_to_constrain, const TyTy::SubstitutionArgumentMappings &constraint_a, const TyTy::SubstitutionArgumentMappings &constraint_b, - const TyTy::BaseType *reference); + TyTy::BaseType *reference); TyTy::BaseType *resolve_literal (const Analysis::NodeMapping &mappings, HIR::Literal &literal, location_t locus); @@ -61,6 +62,7 @@ protected: location_t locus); void resolve_generic_params ( + const HIR::Item::ItemKind item_kind, location_t item_locus, const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params, std::vector<TyTy::SubstitutionParamMapping> &substitutions, bool is_foreign = false, ABI abi = ABI::RUST); @@ -69,7 +71,6 @@ protected: location_t locus); Analysis::Mappings &mappings; - Resolver *resolver; TypeCheckContext *context; }; diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc index c80a12f..23a8cca 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc @@ -23,9 +23,6 @@ #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" -// for flag_name_resolution_2_0 -#include "options.h" - namespace Rust { namespace Resolver { @@ -79,25 +76,13 @@ TypeCheckEnumItem::visit (HIR::EnumItem &item) rust_assert (ok); context->insert_type (mapping, isize); - tl::optional<CanonicalPath> canonical_path; - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); - } - else - { - canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path.has_value ()); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, item.get_locus ()}; + RustIdent ident{canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), item.get_identifier ().as_string (), ident, @@ -123,25 +108,13 @@ TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item) TyTy::TyWithLocation (expected_ty), TyTy::TyWithLocation (capacity_type), item.get_locus ()); - tl::optional<CanonicalPath> canonical_path; - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); - } - else - { - canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path.has_value ()); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, item.get_locus ()}; + RustIdent ident{canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), @@ -185,25 +158,13 @@ TypeCheckEnumItem::visit (HIR::EnumItemTuple &item) rust_assert (ok); context->insert_type (mapping, isize); - tl::optional<CanonicalPath> canonical_path; + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); - } - else - { - canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); - } - - rust_assert (canonical_path.has_value ()); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, item.get_locus ()}; + RustIdent ident{canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), item.get_identifier ().as_string (), ident, @@ -245,25 +206,13 @@ TypeCheckEnumItem::visit (HIR::EnumItemStruct &item) rust_assert (ok); context->insert_type (mapping, isize); - tl::optional<CanonicalPath> canonical_path; - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ()); - } - else - { - canonical_path - = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path.has_value ()); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (item.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, item.get_locus ()}; + RustIdent ident{canonical_path, item.get_locus ()}; variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (), item.get_mappings ().get_defid (), item.get_identifier ().as_string (), ident, diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index cbf529a7..438200b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -17,6 +17,7 @@ // <http://www.gnu.org/licenses/>. #include "optional.h" +#include "rust-common.h" #include "rust-hir-expr.h" #include "rust-system.h" #include "rust-tyty-call.h" @@ -31,9 +32,9 @@ #include "rust-hir-type-check-item.h" #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" - -// for flag_name_resolution_2_0 -#include "options.h" +#include "rust-compile-base.h" +#include "rust-tyty-util.h" +#include "tree.h" namespace Rust { namespace Resolver { @@ -58,6 +59,19 @@ TypeCheckExpr::Resolve (HIR::Expr &expr) return resolver.infered; } +TyTy::BaseType * +TypeCheckExpr::ResolveOpOverload (LangItem::Kind lang_item_type, + HIR::OperatorExprMeta expr, + TyTy::BaseType *lhs, TyTy::BaseType *rhs, + HIR::PathIdentSegment specified_segment) +{ + TypeCheckExpr resolver; + + resolver.resolve_operator_overload (lang_item_type, expr, lhs, rhs, + specified_segment); + return resolver.infered; +} + void TypeCheckExpr::visit (HIR::TupleIndexExpr &expr) { @@ -373,7 +387,8 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) switch (expr.get_expr_type ()) { case ArithmeticOrLogicalOperator::LEFT_SHIFT: - case ArithmeticOrLogicalOperator::RIGHT_SHIFT: { + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + { TyTy::TyWithLocation from (rhs, expr.get_rhs ().get_locus ()); TyTy::TyWithLocation to (lhs, expr.get_lhs ().get_locus ()); infered = cast_site (expr.get_mappings ().get_hirid (), from, to, @@ -381,7 +396,8 @@ TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr) } break; - default: { + default: + { infered = unify_site ( expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()), @@ -470,7 +486,8 @@ TypeCheckExpr::visit (HIR::NegationExpr &expr) // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators switch (expr.get_expr_type ()) { - case NegationOperator::NEGATE: { + case NegationOperator::NEGATE: + { bool valid = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT) @@ -492,7 +509,8 @@ TypeCheckExpr::visit (HIR::NegationExpr &expr) } break; - case NegationOperator::NOT: { + case NegationOperator::NOT: + { bool valid = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL) || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT) @@ -643,6 +661,33 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) } void +TypeCheckExpr::visit (HIR::AnonConst &expr) +{ + if (!expr.is_deferred ()) + { + infered = TypeCheckExpr::Resolve (expr.get_inner_expr ()); + return; + } + + auto locus = expr.get_locus (); + auto infer_ty_var = TyTy::TyVar::get_implicit_infer_var (locus); + + HirId next = mappings.get_next_hir_id (); + infered = new TyTy::ConstType (TyTy::ConstType::ConstKind::Infer, "", + infer_ty_var.get_tyty (), error_mark_node, {}, + locus, next, next, {}); + + context->insert_implicit_type (infered->get_ref (), infered); + mappings.insert_location (infered->get_ref (), locus); +} + +void +TypeCheckExpr::visit (HIR::ConstBlock &expr) +{ + infered = TypeCheckExpr::Resolve (expr.get_const_expr ()); +} + +void TypeCheckExpr::visit (HIR::RangeFromToExpr &expr) { auto lang_item_type = LangItem::Kind::RANGE; @@ -790,38 +835,45 @@ typecheck_inline_asm_operand (HIR::InlineAsm &expr) { switch (operand.get_register_type ()) { - case RegisterType::In: { + case RegisterType::In: + { auto in = operand.get_in (); TypeCheckExpr::Resolve (*in.expr); break; } - case RegisterType::Out: { + case RegisterType::Out: + { auto out = operand.get_out (); TypeCheckExpr::Resolve (*out.expr); break; } - case RegisterType::InOut: { + case RegisterType::InOut: + { auto in_out = operand.get_in_out (); TypeCheckExpr::Resolve (*in_out.expr); break; } - case RegisterType::SplitInOut: { + case RegisterType::SplitInOut: + { auto split_in_out = operand.get_split_in_out (); TypeCheckExpr::Resolve (*split_in_out.in_expr); TypeCheckExpr::Resolve (*split_in_out.out_expr); break; } - case RegisterType::Const: { + case RegisterType::Const: + { auto anon_const = operand.get_const ().anon_const; - TypeCheckExpr::Resolve (*anon_const.expr); + TypeCheckExpr::Resolve (anon_const.get_inner_expr ()); break; } - case RegisterType::Sym: { + case RegisterType::Sym: + { auto sym = operand.get_sym (); TypeCheckExpr::Resolve (*sym.expr); break; } - case RegisterType::Label: { + case RegisterType::Label: + { auto label = operand.get_label (); TypeCheckExpr::Resolve (*label.expr); break; @@ -837,7 +889,7 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr) // NOTE: Hoise out if we have noreturn as an option // to return a never type // TODO : new keyword for memory seems sooooo shaky - if (expr.options.count (AST::InlineAsmOption::NORETURN) == 1) + if (expr.options.count (AST::InlineAsm::Option::NORETURN) == 1) infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ()); else infered = TyTy::TupleType::get_unit_type (); @@ -857,6 +909,19 @@ TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr) } void +TypeCheckExpr::visit (HIR::OffsetOf &expr) +{ + TypeCheckType::Resolve (expr.get_type ()); + + // FIXME: Does offset_of always return a usize? + TyTy::BaseType *size_ty; + bool ok = context->lookup_builtin ("usize", &size_ty); + rust_assert (ok); + + infered = size_ty; +} + +void TypeCheckExpr::visit (HIR::RangeFullExpr &expr) { auto lang_item_type = LangItem::Kind::RANGE_FULL; @@ -960,7 +1025,10 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) bool ok = context->lookup_builtin ("usize", &size_ty); rust_assert (ok); - bool maybe_simple_array_access = index_expr_ty->can_eq (size_ty, false); + bool maybe_simple_array_access + = types_compatable (TyTy::TyWithLocation (index_expr_ty), + TyTy::TyWithLocation (size_ty), expr.get_locus (), + false); if (maybe_simple_array_access && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY) { @@ -996,8 +1064,7 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) rich_location r (line_table, expr.get_locus ()); r.add_range (expr.get_array_expr ().get_locus ()); r.add_range (expr.get_index_expr ().get_locus ()); - rust_error_at (r, ErrorCode::E0277, - "the type %qs cannot be indexed by %qs", + rust_error_at (r, ErrorCode::E0277, "the type %qs cannot be indexed by %qs", array_expr_ty->get_name ().c_str (), index_expr_ty->get_name ().c_str ()); } @@ -1007,35 +1074,40 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) { auto &elements = expr.get_internal_elements (); + TyTy::BaseType *expected_ty = nullptr; + bool ok = context->lookup_builtin ("usize", &expected_ty); + rust_assert (ok); + HIR::Expr *capacity_expr = nullptr; TyTy::BaseType *element_type = nullptr; + TyTy::BaseType *capacity_type = nullptr; switch (elements.get_array_expr_type ()) { - case HIR::ArrayElems::ArrayExprType::COPIED: { + case HIR::ArrayElems::ArrayExprType::COPIED: + { HIR::ArrayElemsCopied &elems = static_cast<HIR::ArrayElemsCopied &> (elements); element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ()); - auto capacity_type + auto capacity_expr_ty = TypeCheckExpr::Resolve (elems.get_num_copies_expr ()); - TyTy::BaseType *expected_ty = nullptr; - bool ok = context->lookup_builtin ("usize", &expected_ty); - rust_assert (ok); context->insert_type (elems.get_num_copies_expr ().get_mappings (), expected_ty); - unify_site (expr.get_mappings ().get_hirid (), - TyTy::TyWithLocation (expected_ty), - TyTy::TyWithLocation ( - capacity_type, elems.get_num_copies_expr ().get_locus ()), - expr.get_locus ()); + unify_site ( + expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (capacity_expr_ty, + elems.get_num_copies_expr ().get_locus ()), + expr.get_locus ()); capacity_expr = &elems.get_num_copies_expr (); + capacity_type = expected_ty; } break; - case HIR::ArrayElems::ArrayExprType::VALUES: { + case HIR::ArrayElems::ArrayExprType::VALUES: + { HIR::ArrayElemsValues &elems = static_cast<HIR::ArrayElemsValues &> (elements); @@ -1068,17 +1140,26 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) UNDEF_LOCATION, {}); // mark the type for this implicit node - TyTy::BaseType *expected_ty = nullptr; - bool ok = context->lookup_builtin ("usize", &expected_ty); - rust_assert (ok); context->insert_type (mapping, expected_ty); + capacity_type = expected_ty; } break; } - infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), - expr.get_locus (), *capacity_expr, - TyTy::TyVar (element_type->get_ref ())); + rust_assert (capacity_expr); + rust_assert (capacity_type); + auto ctx = Compile::Context::get (); + tree capacity_value + = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type, + *capacity_expr); + HirId size_id = capacity_expr->get_mappings ().get_hirid (); + TyTy::ConstType *const_type + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", expected_ty, + capacity_value, {}, capacity_expr->get_locus (), + size_id, size_id); + infered + = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (), + const_type, TyTy::TyVar (element_type->get_ref ())); } // empty struct @@ -1408,26 +1489,11 @@ TypeCheckExpr::visit (HIR::MethodCallExpr &expr) // store the expected fntype context->insert_type (expr.get_method_name ().get_mappings (), lookup); - if (flag_name_resolution_2_0) - { - auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( - Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); - nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), - Resolver2_0::Definition (resolved_node_id)); - } - // set up the resolved name on the path - else if (resolver->get_name_scope ().decl_was_declared_here ( - resolved_node_id)) - { - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); - } - else - { - resolver->insert_resolved_misc (expr.get_mappings ().get_nodeid (), - resolved_node_id); - } + nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); // return the result of the function back infered = function_ret_tyty; @@ -1702,16 +1768,22 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr) void TypeCheckExpr::visit (HIR::ClosureExpr &expr) { - TypeCheckContextItem current_context = context->peek_context (); - TyTy::FnType *current_context_fndecl = current_context.get_context_type (); - + std::vector<TyTy::SubstitutionParamMapping> subst_refs; HirId ref = expr.get_mappings ().get_hirid (); DefId id = expr.get_mappings ().get_defid (); - RustIdent ident{current_context_fndecl->get_ident ().path, expr.get_locus ()}; + RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()}; - // get from parent context - std::vector<TyTy::SubstitutionParamMapping> subst_refs - = current_context_fndecl->clone_substs (); + if (context->have_function_context ()) + { + TypeCheckContextItem current_context = context->peek_context (); + TyTy::FnType *current_context_fndecl + = current_context.get_context_type (); + + ident = RustIdent{current_context_fndecl->get_ident ().path, + expr.get_locus ()}; + + subst_refs = current_context_fndecl->clone_substs (); + } std::vector<TyTy::TyVar> parameter_types; for (auto &p : expr.get_params ()) @@ -1763,19 +1835,12 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) // Resolve closure captures std::set<NodeId> captures; - if (flag_name_resolution_2_0) - { - auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( - Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); - if (auto opt_cap = nr_ctx.mappings.lookup_captures (closure_node_id)) - for (auto cap : opt_cap.value ()) - captures.insert (cap); - } - else - { - captures = resolver->get_captures (closure_node_id); - } + if (auto opt_cap = nr_ctx.mappings.lookup_captures (closure_node_id)) + for (auto cap : opt_cap.value ()) + captures.insert (cap); infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type, subst_refs, captures); @@ -1826,7 +1891,7 @@ TypeCheckExpr::visit (HIR::ClosureExpr &expr) args.get_type_args ().push_back (std::unique_ptr<HIR::Type> (implicit_tuple)); // apply the arguments - predicate.apply_generic_arguments (&args, false); + predicate.apply_generic_arguments (&args, false, false); // finally inherit the trait bound infered->inherit_bounds ({predicate}); @@ -1845,7 +1910,16 @@ TypeCheckExpr::resolve_operator_overload ( // probe for the lang-item if (!lang_item_defined) return false; + DefId &respective_lang_item_id = lang_item_defined.value (); + auto def_lookup = mappings.lookup_defid (respective_lang_item_id); + rust_assert (def_lookup.has_value ()); + + HIR::Item *def_item = def_lookup.value (); + rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait); + HIR::Trait &trait = *static_cast<HIR::Trait *> (def_item); + TraitReference *defid_trait_reference = TraitResolver::Resolve (trait); + rust_assert (!defid_trait_reference->is_error ()); // we might be in a static or const context and unknown is fine TypeCheckContextItem current_context = TypeCheckContextItem::get_error (); @@ -1889,15 +1963,49 @@ TypeCheckExpr::resolve_operator_overload ( if (selected_candidates.size () > 1) { - // mutliple candidates - rich_location r (line_table, expr.get_locus ()); - for (auto &c : resolved_candidates) - r.add_range (c.candidate.locus); + auto infer + = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty (); + auto trait_subst = defid_trait_reference->get_trait_substs (); + rust_assert (trait_subst.size () > 0); - rust_error_at ( - r, "multiple candidates found for possible operator overload"); + TyTy::TypeBoundPredicate pred (respective_lang_item_id, trait_subst, + BoundPolarity::RegularBound, + expr.get_locus ()); - return false; + std::vector<TyTy::SubstitutionArg> mappings; + auto &self_param_mapping = trait_subst[0]; + mappings.push_back (TyTy::SubstitutionArg (&self_param_mapping, lhs)); + + if (rhs != nullptr) + { + rust_assert (trait_subst.size () == 2); + auto &rhs_param_mapping = trait_subst[1]; + mappings.push_back (TyTy::SubstitutionArg (&rhs_param_mapping, lhs)); + } + + std::map<std::string, TyTy::BaseType *> binding_args; + binding_args["Output"] = infer; + + TyTy::SubstitutionArgumentMappings arg_mappings (mappings, binding_args, + TyTy::RegionParamList ( + trait_subst.size ()), + expr.get_locus ()); + pred.apply_argument_mappings (arg_mappings, false); + + infer->inherit_bounds ({pred}); + DeferredOpOverload defer (expr.get_mappings ().get_hirid (), + lang_item_type, specified_segment, pred, expr); + context->insert_deferred_operator_overload (std::move (defer)); + + if (rhs != nullptr) + lhs = unify_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (lhs), + TyTy::TyWithLocation (rhs), expr.get_locus ()); + + infered = unify_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (lhs), + TyTy::TyWithLocation (infer), expr.get_locus ()); + return true; } // Get the adjusted self @@ -2040,19 +2148,11 @@ TypeCheckExpr::resolve_operator_overload ( context->insert_operator_overload (expr.get_mappings ().get_hirid (), type); // set up the resolved name on the path - if (flag_name_resolution_2_0) - { - auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( - Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); - nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), - Resolver2_0::Definition (resolved_node_id)); - } - else - { - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); - } + nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); // return the result of the function back infered = function_ret_tyty; @@ -2062,16 +2162,13 @@ TypeCheckExpr::resolve_operator_overload ( HIR::PathIdentSegment TypeCheckExpr::resolve_possible_fn_trait_call_method_name ( - TyTy::BaseType &receiver, TyTy::TypeBoundPredicate *associated_predicate) + const TyTy::BaseType &receiver, + TyTy::TypeBoundPredicate *associated_predicate) { - // Question - // do we need to probe possible bounds here? I think not, i think when we - // support Fn traits they are explicitly specified - // FIXME // the logic to map the FnTrait to their respective call trait-item is // duplicated over in the backend/rust-compile-expr.cc - for (auto &bound : receiver.get_specified_bounds ()) + for (const auto &bound : receiver.get_specified_bounds ()) { bool found_fn = bound.get_name ().compare ("Fn") == 0; bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0; @@ -2094,6 +2191,34 @@ TypeCheckExpr::resolve_possible_fn_trait_call_method_name ( } } + if (receiver.is<TyTy::ReferenceType> ()) + { + const auto &ref = static_cast<const TyTy::ReferenceType &> (receiver); + const auto &underlying = *ref.get_base (); + for (const auto &bound : underlying.get_specified_bounds ()) + { + bool found_fn = bound.get_name ().compare ("Fn") == 0; + bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0; + bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0; + + if (found_fn) + { + *associated_predicate = bound; + return HIR::PathIdentSegment ("call"); + } + else if (found_fn_mut) + { + *associated_predicate = bound; + return HIR::PathIdentSegment ("call_mut"); + } + else if (found_fn_once) + { + *associated_predicate = bound; + return HIR::PathIdentSegment ("call_once"); + } + } + } + // nothing *associated_predicate = TyTy::TypeBoundPredicate::error (); return HIR::PathIdentSegment (""); @@ -2220,32 +2345,15 @@ TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr, context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn); // set up the resolved name on the path - if (flag_name_resolution_2_0) - { - auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( - Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); - auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid ()); - if (existing) - rust_assert (*existing == resolved_node_id); - else - nr_ctx.map_usage (Resolver2_0::Usage ( - expr.get_mappings ().get_nodeid ()), - Resolver2_0::Definition (resolved_node_id)); - } + auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid ()); + if (existing) + rust_assert (*existing == resolved_node_id); else - { - NodeId existing = UNKNOWN_NODEID; - bool ok - = resolver->lookup_resolved_name (expr.get_mappings ().get_nodeid (), - &existing); - - if (ok) - rust_assert (existing == resolved_node_id); - else - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - resolved_node_id); - } + nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); // return the result of the function back *result = function_ret_tyty; diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 79121b3..0343922 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -19,6 +19,7 @@ #ifndef RUST_HIR_TYPE_CHECK_EXPR #define RUST_HIR_TYPE_CHECK_EXPR +#include "rust-hir-expr.h" #include "rust-hir-type-check-base.h" #include "rust-hir-visitor.h" #include "rust-tyty.h" @@ -31,6 +32,11 @@ class TypeCheckExpr : private TypeCheckBase, private HIR::HIRExpressionVisitor public: static TyTy::BaseType *Resolve (HIR::Expr &expr); + static TyTy::BaseType * + ResolveOpOverload (LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr, + TyTy::BaseType *lhs, TyTy::BaseType *rhs, + HIR::PathIdentSegment specified_segment); + void visit (HIR::TupleIndexExpr &expr) override; void visit (HIR::TupleExpr &expr) override; void visit (HIR::ReturnExpr &expr) override; @@ -46,6 +52,8 @@ public: void visit (HIR::IfExpr &expr) override; void visit (HIR::IfExprConseqElse &expr) override; void visit (HIR::BlockExpr &expr) override; + void visit (HIR::AnonConst &expr) override; + void visit (HIR::ConstBlock &expr) override; void visit (HIR::UnsafeBlockExpr &expr) override; void visit (HIR::ArrayIndexExpr &expr) override; void visit (HIR::ArrayExpr &expr) override; @@ -71,6 +79,7 @@ public: void visit (HIR::ClosureExpr &expr) override; void visit (HIR::InlineAsm &expr) override; void visit (HIR::LlvmInlineAsm &expr) override; + void visit (HIR::OffsetOf &expr) override; // TODO void visit (HIR::ErrorPropagationExpr &) override {} @@ -107,7 +116,8 @@ protected: TyTy::BaseType **result); HIR::PathIdentSegment resolve_possible_fn_trait_call_method_name ( - TyTy::BaseType &receiver, TyTy::TypeBoundPredicate *associated_predicate); + const TyTy::BaseType &receiver, + TyTy::TypeBoundPredicate *associated_predicate); private: TypeCheckExpr (); diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc index bc7f6dc..c8544a1 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc @@ -28,9 +28,6 @@ #include "rust-tyty.h" #include "rust-immutable-name-resolution-context.h" -// for flag_name_resolution_2_0 -#include "options.h" - namespace Rust { namespace Resolver { @@ -73,7 +70,9 @@ TypeCheckTopLevelExternItem::visit (HIR::ExternalFunctionItem &function) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (function.has_generics ()) { - resolve_generic_params (function.get_generic_params (), substitutions, + resolve_generic_params (HIR::Item::ItemKind::Function, + function.get_locus (), + function.get_generic_params (), substitutions, true /*is_foreign*/, parent.get_abi ()); } @@ -203,7 +202,9 @@ TypeCheckImplItem::visit (HIR::Function &function) auto binder_pin = context->push_lifetime_binder (); if (function.has_generics ()) - resolve_generic_params (function.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Function, + function.get_locus (), + function.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : function.get_where_clause ().get_items ()) @@ -266,7 +267,8 @@ TypeCheckImplItem::visit (HIR::Function &function) self_type = self->clone (); break; - case HIR::SelfParam::IMM_REF: { + case HIR::SelfParam::IMM_REF: + { tl::optional<TyTy::Region> region; if (self_param.has_lifetime ()) { @@ -290,7 +292,8 @@ TypeCheckImplItem::visit (HIR::Function &function) } break; - case HIR::SelfParam::MUT_REF: { + case HIR::SelfParam::MUT_REF: + { tl::optional<TyTy::Region> region; if (self_param.has_lifetime ()) { @@ -336,25 +339,13 @@ TypeCheckImplItem::visit (HIR::Function &function) TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); } - tl::optional<CanonicalPath> canonical_path; - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path = nr_ctx.values.to_canonical_path ( - function.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = mappings.lookup_canonical_path ( - function.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path.has_value ()); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, function.get_locus ()}; + RustIdent ident{canonical_path, function.get_locus ()}; auto fnType = new TyTy::FnType ( function.get_mappings ().get_hirid (), function.get_mappings ().get_defid (), @@ -410,7 +401,8 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias) auto binder_pin = context->push_lifetime_binder (); if (alias.has_generics ()) - resolve_generic_params (alias.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::TypeAlias, alias.get_locus (), + alias.get_generic_params (), substitutions); TyTy::BaseType *actual_type = TypeCheckType::Resolve (alias.get_type_aliased ()); @@ -494,10 +486,9 @@ TypeCheckImplItemWithTrait::visit (HIR::ConstantItem &constant) rich_location r (line_table, constant.get_locus ()); r.add_range (resolved_trait_item.get_locus ()); - rust_error_at ( - r, "constant %qs has an incompatible type for trait %qs", - constant.get_identifier ().as_string ().c_str (), - trait_reference.get_name ().c_str ()); + rust_error_at (r, "constant %qs has an incompatible type for trait %qs", + constant.get_identifier ().as_string ().c_str (), + trait_reference.get_name ().c_str ()); } } @@ -545,10 +536,9 @@ TypeCheckImplItemWithTrait::visit (HIR::TypeAlias &type) rich_location r (line_table, type.get_locus ()); r.add_range (resolved_trait_item.get_locus ()); - rust_error_at ( - r, "type alias %qs has an incompatible type for trait %qs", - type.get_new_type_name ().as_string ().c_str (), - trait_reference.get_name ().c_str ()); + rust_error_at (r, "type alias %qs has an incompatible type for trait %qs", + type.get_new_type_name ().as_string ().c_str (), + trait_reference.get_name ().c_str ()); } // its actually a projection, since we need a way to actually bind the diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index aaa04af..3ba607b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -20,6 +20,7 @@ #include "optional.h" #include "rust-canonical-path.h" #include "rust-diagnostics.h" +#include "rust-hir-item.h" #include "rust-hir-type-check-enumitem.h" #include "rust-hir-type-check-implitem.h" #include "rust-hir-type-check-type.h" @@ -33,9 +34,6 @@ #include "rust-type-util.h" #include "rust-tyty-variance-analysis.h" -// for flag_name_resolution_2_0 -#include "options.h" - namespace Rust { namespace Resolver { @@ -121,8 +119,8 @@ TypeCheckItem::ResolveImplBlockSelfWithInference ( } else { - TyTy::ParamType *param = p.get_param_ty (); - TyTy::BaseType *resolved = param->destructure (); + auto param = p.get_param_ty (); + auto resolved = param->destructure (); args.push_back (TyTy::SubstitutionArg (&p, resolved)); } } @@ -170,7 +168,9 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (struct_decl.has_generics ()) - resolve_generic_params (struct_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Struct, + struct_decl.get_locus (), + struct_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ()) @@ -195,25 +195,11 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) // get the path - auto path = CanonicalPath::create_empty (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - // FIXME: HACK: ARTHUR: Disgusting - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - path = nr_ctx.values - .to_canonical_path (struct_decl.get_mappings ().get_nodeid ()) - .value (); - } - else - { - path - = mappings - .lookup_canonical_path (struct_decl.get_mappings ().get_nodeid ()) - .value (); - } + CanonicalPath path + = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ()); RustIdent ident{path, struct_decl.get_locus ()}; @@ -255,7 +241,9 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) std::vector<TyTy::SubstitutionParamMapping> substitutions; if (struct_decl.has_generics ()) - resolve_generic_params (struct_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Struct, + struct_decl.get_locus (), + struct_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ()) @@ -276,27 +264,11 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) context->insert_type (field.get_mappings (), ty_field->get_field_type ()); } - auto path = CanonicalPath::create_empty (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - // FIXME: HACK: ARTHUR: Disgusting - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - auto canonical_path = nr_ctx.types.to_canonical_path ( - struct_decl.get_mappings ().get_nodeid ()); - - if (!canonical_path.has_value ()) - rust_unreachable (); - path = canonical_path.value (); - } - else - { - path - = mappings - .lookup_canonical_path (struct_decl.get_mappings ().get_nodeid ()) - .value (); - } + CanonicalPath path + = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ()); RustIdent ident{path, struct_decl.get_locus ()}; @@ -337,7 +309,8 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) auto lifetime_pin = context->push_clean_lifetime_resolver (); std::vector<TyTy::SubstitutionParamMapping> substitutions; if (enum_decl.has_generics ()) - resolve_generic_params (enum_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Enum, enum_decl.get_locus (), + enum_decl.get_generic_params (), substitutions); // Process #[repr(X)] attribute, if any const AST::AttrVec &attrs = enum_decl.get_outer_attrs (); @@ -367,26 +340,14 @@ TypeCheckItem::visit (HIR::Enum &enum_decl) } } - // get the path - tl::optional<CanonicalPath> canonical_path; - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path = nr_ctx.types.to_canonical_path ( - enum_decl.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = mappings.lookup_canonical_path ( - enum_decl.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path.has_value ()); + // get the path + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (enum_decl.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, enum_decl.get_locus ()}; + RustIdent ident{canonical_path, enum_decl.get_locus ()}; // multi variant ADT auto *type @@ -409,7 +370,8 @@ TypeCheckItem::visit (HIR::Union &union_decl) auto lifetime_pin = context->push_clean_lifetime_resolver (); std::vector<TyTy::SubstitutionParamMapping> substitutions; if (union_decl.has_generics ()) - resolve_generic_params (union_decl.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Union, union_decl.get_locus (), + union_decl.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : union_decl.get_where_clause ().get_items ()) @@ -431,26 +393,14 @@ TypeCheckItem::visit (HIR::Union &union_decl) ty_variant->get_field_type ()); } - // get the path - tl::optional<CanonicalPath> canonical_path; - - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path = nr_ctx.types.to_canonical_path ( - union_decl.get_mappings ().get_nodeid ()); - } - else - { - canonical_path = mappings.lookup_canonical_path ( - union_decl.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path.has_value ()); + // get the path + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (union_decl.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, union_decl.get_locus ()}; + RustIdent ident{canonical_path, union_decl.get_locus ()}; // there is only a single variant std::vector<TyTy::VariantDef *> variants; @@ -569,8 +519,9 @@ TypeCheckItem::visit (HIR::Function &function) auto lifetime_pin = context->push_clean_lifetime_resolver (); std::vector<TyTy::SubstitutionParamMapping> substitutions; if (function.has_generics ()) - resolve_generic_params (function.get_generic_params (), - substitutions); // TODO resolve constraints + resolve_generic_params (HIR::Item::ItemKind::Function, + function.get_locus (), + function.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : function.get_where_clause ().get_items ()) @@ -607,24 +558,11 @@ TypeCheckItem::visit (HIR::Function &function) TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); } - auto path = CanonicalPath::create_empty (); - - // FIXME: HACK: ARTHUR: Disgusting - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - auto canonical_path = nr_ctx.values.to_canonical_path ( - function.get_mappings ().get_nodeid ()); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - path = canonical_path.value (); - } - else - { - path = mappings - .lookup_canonical_path (function.get_mappings ().get_nodeid ()) - .value (); - } + CanonicalPath path + = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); RustIdent ident{path, function.get_locus ()}; @@ -745,13 +683,33 @@ TypeCheckItem::visit (HIR::ExternBlock &extern_block) } } +void +TypeCheckItem::visit (HIR::ExternCrate &extern_crate) +{ + if (extern_crate.references_self ()) + return; + + auto &mappings = Analysis::Mappings::get (); + CrateNum num + = mappings.lookup_crate_name (extern_crate.get_referenced_crate ()) + .value (); + HIR::Crate &crate = mappings.get_hir_crate (num); + + CrateNum saved_crate_num = mappings.get_current_crate (); + mappings.set_current_crate (num); + for (auto &item : crate.get_items ()) + TypeCheckItem::Resolve (*item); + mappings.set_current_crate (saved_crate_num); +} + std::pair<std::vector<TyTy::SubstitutionParamMapping>, TyTy::RegionConstraints> TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, bool &failure_flag) { std::vector<TyTy::SubstitutionParamMapping> substitutions; if (impl_block.has_generics ()) - resolve_generic_params (impl_block.get_generic_params (), substitutions); + resolve_generic_params (HIR::Item::ItemKind::Impl, impl_block.get_locus (), + impl_block.get_generic_params (), substitutions); TyTy::RegionConstraints region_constraints; for (auto &where_clause_item : impl_block.get_where_clause ().get_items ()) diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 56832e7..414694b 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -51,9 +51,9 @@ public: void visit (HIR::ImplBlock &impl_block) override; void visit (HIR::ExternBlock &extern_block) override; void visit (HIR::Trait &trait_block) override; + void visit (HIR::ExternCrate &extern_crate) override; // nothing to do - void visit (HIR::ExternCrate &) override {} void visit (HIR::UseDeclaration &) override {} protected: diff --git a/gcc/rust/typecheck/rust-hir-type-check-path.cc b/gcc/rust/typecheck/rust-hir-type-check-path.cc index 5662da5..cc5c412 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-path.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-path.cc @@ -157,20 +157,11 @@ TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr) bool fully_resolved = expr.get_segments ().size () <= 1; if (fully_resolved) { - if (flag_name_resolution_2_0) - { - auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( - Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); - nr_ctx.map_usage (Resolver2_0::Usage ( - expr.get_mappings ().get_nodeid ()), - Resolver2_0::Definition (root_resolved_node_id)); - } - else - { - resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (), - root_resolved_node_id); - } + nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()), + Resolver2_0::Definition (root_resolved_node_id)); return; } @@ -264,24 +255,16 @@ TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset, bool is_root = *offset == 0; NodeId ast_node_id = seg.get_mappings ().get_nodeid (); - // then lookup the reference_node_id - NodeId ref_node_id = UNKNOWN_NODEID; + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (flag_name_resolution_2_0) + // lookup the reference_node_id + NodeId ref_node_id; + if (auto res = nr_ctx.lookup (ast_node_id)) { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - // assign the ref_node_id if we've found something - nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) { - ref_node_id = resolved; - }); + ref_node_id = *res; } - else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - resolver->lookup_resolved_type (ast_node_id, &ref_node_id); - - // ref_node_id is the NodeId that the segments refers to. - if (ref_node_id == UNKNOWN_NODEID) + else { if (root_tyty != nullptr && *offset > 0) { @@ -561,33 +544,12 @@ TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id, } rust_assert (resolved_node_id != UNKNOWN_NODEID); - if (flag_name_resolution_2_0) - { - auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( - Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); - nr_ctx.map_usage (Resolver2_0::Usage (expr_mappings.get_nodeid ()), - Resolver2_0::Definition (resolved_node_id)); - } - // name scope first - else if (resolver->get_name_scope ().decl_was_declared_here ( - resolved_node_id)) - { - resolver->insert_resolved_name (expr_mappings.get_nodeid (), - resolved_node_id); - } - // check the type scope - else if (resolver->get_type_scope ().decl_was_declared_here ( - resolved_node_id)) - { - resolver->insert_resolved_type (expr_mappings.get_nodeid (), - resolved_node_id); - } - else - { - resolver->insert_resolved_misc (expr_mappings.get_nodeid (), - resolved_node_id); - } + auto &nr_ctx = const_cast<Resolver2_0::NameResolutionContext &> ( + Resolver2_0::ImmutableNameResolutionContext::get ().resolver ()); + + nr_ctx.map_usage (Resolver2_0::Usage (expr_mappings.get_nodeid ()), + Resolver2_0::Definition (resolved_node_id)); infered = tyseg; } diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc index bd13f7a..be926fc 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc @@ -22,9 +22,6 @@ #include "rust-type-util.h" #include "rust-immutable-name-resolution-context.h" -// for flag_name_resolution_2_0 -#include "options.h" - namespace Rust { namespace Resolver { @@ -54,23 +51,13 @@ TypeCheckPattern::visit (HIR::PathInExpression &pattern) NodeId ref_node_id = UNKNOWN_NODEID; bool maybe_item = false; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (auto id = nr_ctx.lookup (pattern.get_mappings ().get_nodeid ())) - { - ref_node_id = *id; - maybe_item = true; - } - } - else + if (auto id = nr_ctx.lookup (pattern.get_mappings ().get_nodeid ())) { - maybe_item |= resolver->lookup_resolved_name ( - pattern.get_mappings ().get_nodeid (), &ref_node_id); - maybe_item |= resolver->lookup_resolved_type ( - pattern.get_mappings ().get_nodeid (), &ref_node_id); + ref_node_id = *id; + maybe_item = true; } bool path_is_const_item = false; @@ -213,13 +200,15 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern) auto &items = pattern.get_items (); switch (items.get_item_type ()) { - case HIR::TupleStructItems::RANGED: { + case HIR::TupleStructItems::RANGED: + { // TODO rust_unreachable (); } break; - case HIR::TupleStructItems::MULTIPLE: { + case HIR::TupleStructItems::MULTIPLE: + { HIR::TupleStructItemsNoRange &items_no_range = static_cast<HIR::TupleStructItemsNoRange &> (items); @@ -333,13 +322,15 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) { switch (field->get_item_type ()) { - case HIR::StructPatternField::ItemType::TUPLE_PAT: { + case HIR::StructPatternField::ItemType::TUPLE_PAT: + { // TODO rust_unreachable (); } break; - case HIR::StructPatternField::ItemType::IDENT_PAT: { + case HIR::StructPatternField::ItemType::IDENT_PAT: + { HIR::StructPatternFieldIdentPat &ident = static_cast<HIR::StructPatternFieldIdentPat &> (*field); @@ -358,7 +349,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) } break; - case HIR::StructPatternField::ItemType::IDENT: { + case HIR::StructPatternField::ItemType::IDENT: + { HIR::StructPatternFieldIdent &ident = static_cast<HIR::StructPatternFieldIdent &> (*field); @@ -397,7 +389,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern) case HIR::StructPatternField::ItemType::IDENT: case HIR::StructPatternField::ItemType::IDENT_PAT: break; - default: { + default: + { auto first_elem = struct_pattern_elems.get_struct_pattern_fields () .at (0) @@ -457,25 +450,27 @@ void TypeCheckPattern::visit (HIR::TuplePattern &pattern) { std::unique_ptr<HIR::TuplePatternItems> items; + + // Check whether parent is tuple + auto resolved_parent = parent->destructure (); + if (resolved_parent->get_kind () != TyTy::TUPLE) + { + rust_error_at (pattern.get_locus (), "expected %s, found tuple", + parent->as_string ().c_str ()); + return; + } + TyTy::TupleType &par = *static_cast<TyTy::TupleType *> (resolved_parent); + switch (pattern.get_items ().get_item_type ()) { - case HIR::TuplePatternItems::ItemType::MULTIPLE: { + case HIR::TuplePatternItems::ItemType::MULTIPLE: + { auto &ref = static_cast<HIR::TuplePatternItemsMultiple &> ( pattern.get_items ()); - auto resolved_parent = parent->destructure (); - if (resolved_parent->get_kind () != TyTy::TUPLE) - { - rust_error_at (pattern.get_locus (), "expected %s, found tuple", - parent->as_string ().c_str ()); - break; - } - const auto &patterns = ref.get_patterns (); size_t nitems_to_resolve = patterns.size (); - TyTy::TupleType &par - = *static_cast<TyTy::TupleType *> (resolved_parent); if (patterns.size () != par.get_fields ().size ()) { emit_pattern_size_error (pattern, par.get_fields ().size (), @@ -498,12 +493,55 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) } break; - case HIR::TuplePatternItems::ItemType::RANGED: { - // HIR::TuplePatternItemsRanged &ref - // = *static_cast<HIR::TuplePatternItemsRanged *> ( - // pattern.get_items ().get ()); - // TODO - rust_unreachable (); + case HIR::TuplePatternItems::ItemType::RANGED: + { + HIR::TuplePatternItemsRanged &ref + = static_cast<HIR::TuplePatternItemsRanged &> (pattern.get_items ()); + + const auto &lower = ref.get_lower_patterns (); + const auto &upper = ref.get_upper_patterns (); + size_t min_size_required = lower.size () + upper.size (); + + // Ensure that size of lower and upper patterns <= parent size + if (min_size_required > par.get_fields ().size ()) + { + emit_pattern_size_error (pattern, par.get_fields ().size (), + min_size_required); + // TODO attempt to continue to do typechecking even after wrong size + break; + } + + // Resolve lower patterns + std::vector<TyTy::TyVar> pattern_elems; + for (size_t i = 0; i < lower.size (); i++) + { + auto &p = lower[i]; + TyTy::BaseType *par_type = par.get_field (i); + + TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type); + pattern_elems.push_back (TyTy::TyVar (elem->get_ref ())); + } + + // Pad pattern_elems until needing to resolve upper patterns + size_t rest_end = par.get_fields ().size () - upper.size (); + for (size_t i = lower.size (); i < rest_end; i++) + { + TyTy::BaseType *par_type = par.get_field (i); + pattern_elems.push_back (TyTy::TyVar (par_type->get_ref ())); + } + + // Resolve upper patterns + for (size_t i = 0; i < upper.size (); i++) + { + auto &p = upper[i]; + TyTy::BaseType *par_type = par.get_field (rest_end + i); + + TyTy::BaseType *elem = TypeCheckPattern::Resolve (*p, par_type); + pattern_elems.push_back (TyTy::TyVar (elem->get_ref ())); + } + + infered = new TyTy::TupleType (pattern.get_mappings ().get_hirid (), + pattern.get_locus (), pattern_elems); } break; } @@ -512,8 +550,18 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) void TypeCheckPattern::visit (HIR::LiteralPattern &pattern) { - infered = resolve_literal (pattern.get_mappings (), pattern.get_literal (), - pattern.get_locus ()); + TyTy::BaseType *resolved + = resolve_literal (pattern.get_mappings (), pattern.get_literal (), + pattern.get_locus ()); + if (resolved->get_kind () == TyTy::TypeKind::ERROR) + { + infered = resolved; + return; + } + + infered = unify_site (pattern.get_mappings ().get_hirid (), + TyTy::TyWithLocation (parent), + TyTy::TyWithLocation (resolved), pattern.get_locus ()); } void @@ -538,6 +586,11 @@ TypeCheckPattern::visit (HIR::RangePattern &pattern) void TypeCheckPattern::visit (HIR::IdentifierPattern &pattern) { + if (pattern.has_subpattern ()) + { + TypeCheckPattern::Resolve (pattern.get_subpattern (), parent); + } + if (!pattern.get_is_ref ()) { infered = parent; @@ -580,8 +633,72 @@ TypeCheckPattern::visit (HIR::ReferencePattern &pattern) void TypeCheckPattern::visit (HIR::SlicePattern &pattern) { - rust_sorry_at (pattern.get_locus (), - "type checking qualified path patterns not supported"); + auto resolved_parent = parent->destructure (); + TyTy::BaseType *parent_element_ty = nullptr; + switch (resolved_parent->get_kind ()) + { + case TyTy::ARRAY: + { + auto &array_ty_ty = static_cast<TyTy::ArrayType &> (*parent); + parent_element_ty = array_ty_ty.get_element_type (); + auto capacity = array_ty_ty.get_capacity (); + tree cap = capacity->get_value (); + if (error_operand_p (cap)) + { + rust_error_at (parent->get_locus (), + "capacity of array %qs is not known at compile time", + array_ty_ty.get_name ().c_str ()); + break; + } + auto cap_wi = wi::to_wide (cap).to_uhwi (); + if (cap_wi != pattern.get_items ().size ()) + { + rust_error_at (pattern.get_locus (), ErrorCode::E0527, + "pattern requires %lu elements but array has %lu", + (unsigned long) pattern.get_items ().size (), + (unsigned long) cap_wi); + break; + } + break; + } + case TyTy::SLICE: + { + auto &slice_ty_ty = static_cast<TyTy::SliceType &> (*parent); + parent_element_ty = slice_ty_ty.get_element_type (); + break; + } + case TyTy::REF: + { + auto &ref_ty_ty = static_cast<TyTy::ReferenceType &> (*parent); + const TyTy::SliceType *slice = nullptr; + if (!ref_ty_ty.is_dyn_slice_type (&slice)) + { + rust_error_at (pattern.get_locus (), "expected %s, found slice", + parent->as_string ().c_str ()); + return; + } + parent_element_ty = slice->get_element_type (); + break; + } + default: + { + rust_error_at (pattern.get_locus (), "expected %s, found slice", + parent->as_string ().c_str ()); + return; + } + } + + rust_assert (parent_element_ty != nullptr); + // infered inherits array/slice typing from parent + infered = parent->clone (); + infered->set_ref (pattern.get_mappings ().get_hirid ()); + + // Type check every item in the SlicePattern against parent's element ty + // TODO update this after adding support for RestPattern in SlicePattern + for (const auto &item : pattern.get_items ()) + { + TypeCheckPattern::Resolve (*item, parent_element_ty); + } } void @@ -608,7 +725,8 @@ TypeCheckPattern::typecheck_range_pattern_bound ( TyTy::BaseType *resolved_bound = nullptr; switch (bound.get_bound_type ()) { - case HIR::RangePatternBound::RangePatternBoundType::LITERAL: { + case HIR::RangePatternBound::RangePatternBoundType::LITERAL: + { auto &ref = static_cast<HIR::RangePatternBoundLiteral &> (bound); HIR::Literal lit = ref.get_literal (); @@ -617,14 +735,16 @@ TypeCheckPattern::typecheck_range_pattern_bound ( } break; - case HIR::RangePatternBound::RangePatternBoundType::PATH: { + case HIR::RangePatternBound::RangePatternBoundType::PATH: + { auto &ref = static_cast<HIR::RangePatternBoundPath &> (bound); resolved_bound = TypeCheckExpr::Resolve (ref.get_path ()); } break; - case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: { + case HIR::RangePatternBound::RangePatternBoundType::QUALPATH: + { auto &ref = static_cast<HIR::RangePatternBoundQualPath &> (bound); resolved_bound = TypeCheckExpr::Resolve (ref.get_qualified_path ()); diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc index 4e53856..87141af 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.cc @@ -60,6 +60,12 @@ void TypeCheckStmt::visit (HIR::ConstantItem &constant) { TyTy::BaseType *type = TypeCheckType::Resolve (constant.get_type ()); + if (!constant.has_expr ()) + { + infered = type; + return; + } + TyTy::BaseType *expr_type = TypeCheckExpr::Resolve (constant.get_expr ()); infered = coercion_site ( diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc index df1636a..4ef8348 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -329,8 +329,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field) repeat_location.add_range (prev_field_locus); rust_error_at (repeat_location, ErrorCode::E0062, - "field %qs specified more than once", - field_name.c_str ()); + "field %qs specified more than once", field_name.c_str ()); return false; } @@ -363,7 +362,7 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifier &field) if (!ok) { rust_error_at (field.get_locus (), "unknown field"); - return true; + return false; } auto it = adtFieldIndexToField.find (field_index); diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc b/gcc/rust/typecheck/rust-hir-type-check-type.cc index 6919093..78037bd 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc @@ -29,6 +29,7 @@ #include "rust-substitution-mapper.h" #include "rust-type-util.h" #include "rust-system.h" +#include "rust-compile-base.h" namespace Rust { namespace Resolver { @@ -335,19 +336,13 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset, seg->get_lang_item ()); else { - // FIXME: HACK: ARTHUR: Remove this - if (flag_name_resolution_2_0) - { - auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get () - .resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - // assign the ref_node_id if we've found something - nr_ctx.lookup (ast_node_id) - .map ( - [&ref_node_id] (NodeId resolved) { ref_node_id = resolved; }); - } - else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) - resolver->lookup_resolved_type (ast_node_id, &ref_node_id); + // assign the ref_node_id if we've found something + nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) { + ref_node_id = resolved; + }); } // ref_node_id is the NodeId that the segments refers to. @@ -549,8 +544,7 @@ TypeCheckType::resolve_segments ( bool selfResolveOk = false; if (first_segment && tySegIsBigSelf - && context->block_context ().is_in_context () - && context->block_context ().peek ().is_impl_block ()) + && context->block_context ().is_in_context ()) { TypeCheckBlockContextItem ctx = context->block_context ().peek (); TyTy::BaseType *lookup = nullptr; @@ -695,6 +689,7 @@ TypeCheckType::visit (HIR::ParenthesisedType &type) void TypeCheckType::visit (HIR::ArrayType &type) { + auto element_type = TypeCheckType::Resolve (type.get_element_type ()); auto capacity_type = TypeCheckExpr::Resolve (type.get_size_expr ()); if (capacity_type->get_kind () == TyTy::TypeKind::ERROR) return; @@ -704,16 +699,38 @@ TypeCheckType::visit (HIR::ArrayType &type) rust_assert (ok); context->insert_type (type.get_size_expr ().get_mappings (), expected_ty); - unify_site (type.get_size_expr ().get_mappings ().get_hirid (), - TyTy::TyWithLocation (expected_ty), - TyTy::TyWithLocation (capacity_type, - type.get_size_expr ().get_locus ()), - type.get_size_expr ().get_locus ()); + TyTy::ConstType *const_type = nullptr; + if (capacity_type->get_kind () == TyTy::TypeKind::CONST) + { + const_type = static_cast<TyTy::ConstType *> (capacity_type); - TyTy::BaseType *base = TypeCheckType::Resolve (type.get_element_type ()); - translated = new TyTy::ArrayType (type.get_mappings ().get_hirid (), - type.get_locus (), type.get_size_expr (), - TyTy::TyVar (base->get_ref ())); + unify_site (type.get_size_expr ().get_mappings ().get_hirid (), + TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (const_type->get_ty (), + type.get_size_expr ().get_locus ()), + type.get_size_expr ().get_locus ()); + } + else + { + HirId size_id = type.get_size_expr ().get_mappings ().get_hirid (); + unify_site (size_id, TyTy::TyWithLocation (expected_ty), + TyTy::TyWithLocation (capacity_type, + type.get_size_expr ().get_locus ()), + type.get_size_expr ().get_locus ()); + + auto ctx = Compile::Context::get (); + tree capacity_expr = Compile::HIRCompileBase::query_compile_const_expr ( + ctx, capacity_type, type.get_size_expr ()); + + const_type = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", + expected_ty, capacity_expr, {}, + type.get_size_expr ().get_locus (), + size_id, size_id); + } + + translated + = new TyTy::ArrayType (type.get_mappings ().get_hirid (), type.get_locus (), + const_type, TyTy::TyVar (element_type->get_ref ())); } void @@ -850,10 +867,9 @@ TypeResolveGenericParam::visit (HIR::TypeParam ¶m) if (param.has_type ()) TypeCheckType::Resolve (param.get_type ()); - resolved - = new TyTy::ParamType (param.get_type_representation ().as_string (), - param.get_locus (), - param.get_mappings ().get_hirid (), param, {}); + resolved = new TyTy::ParamType (param.get_type_representation ().as_string (), + param.get_locus (), + param.get_mappings ().get_hirid (), {}); if (resolve_trait_bounds) apply_trait_bounds (param, resolved); @@ -872,7 +888,7 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, HirId implicit_id = mappings.get_next_hir_id (); TyTy::ParamType *p = new TyTy::ParamType (param.get_type_representation ().as_string (), - param.get_locus (), implicit_id, param, + param.get_locus (), implicit_id, {} /*empty specified bounds*/); context->insert_implicit_type (implicit_id, p); @@ -908,7 +924,8 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, { switch (bound->get_bound_type ()) { - case HIR::TypeParamBound::BoundType::TRAITBOUND: { + case HIR::TypeParamBound::BoundType::TRAITBOUND: + { HIR::TraitBound &b = static_cast<HIR::TraitBound &> (*bound); TyTy::TypeBoundPredicate predicate = get_predicate_from_bound ( @@ -920,7 +937,8 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, { switch (predicate.get_polarity ()) { - case BoundPolarity::AntiBound: { + case BoundPolarity::AntiBound: + { bool found = predicates.find (predicate.get_id ()) != predicates.end (); if (found) @@ -937,7 +955,8 @@ TypeResolveGenericParam::apply_trait_bounds (HIR::TypeParam ¶m, } break; - default: { + default: + { if (predicates.find (predicate.get_id ()) == predicates.end ()) { @@ -1033,7 +1052,8 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) { switch (bound->get_bound_type ()) { - case HIR::TypeParamBound::BoundType::TRAITBOUND: { + case HIR::TypeParamBound::BoundType::TRAITBOUND: + { auto *b = static_cast<HIR::TraitBound *> (bound.get ()); TyTy::TypeBoundPredicate predicate @@ -1042,7 +1062,8 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) specified_bounds.push_back (std::move (predicate)); } break; - case HIR::TypeParamBound::BoundType::LIFETIME: { + case HIR::TypeParamBound::BoundType::LIFETIME: + { if (auto param = binding->try_as<TyTy::ParamType> ()) { auto *b = static_cast<HIR::Lifetime *> (bound.get ()); @@ -1071,23 +1092,15 @@ ResolveWhereClauseItem::visit (HIR::TypeBoundWhereClauseItem &item) // then lookup the reference_node_id NodeId ref_node_id = UNKNOWN_NODEID; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (auto id = nr_ctx.lookup (ast_node_id)) - ref_node_id = *id; - } - else - { - NodeId id = UNKNOWN_NODEID; + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - if (resolver->lookup_resolved_type (ast_node_id, &id)) - ref_node_id = id; + if (auto id = nr_ctx.lookup (ast_node_id)) + { + ref_node_id = *id; } - - if (ref_node_id == UNKNOWN_NODEID) + else { // FIXME rust_error_at (UNDEF_LOCATION, diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc index fbaf323..aba4ab5 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -26,11 +26,7 @@ #include "rust-hir-type-check-struct-field.h" #include "rust-immutable-name-resolution-context.h" -// for flag_name_resolution_2_0 -#include "options.h" - -extern bool -saw_errors (void); +extern bool saw_errors (void); namespace Rust { namespace Resolver { @@ -165,7 +161,9 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const HIR::TraitFunctionDecl &function = fn.get_decl (); if (function.has_generics ()) { - TypeCheckBase::ResolveGenericParams (function.get_generic_params (), + TypeCheckBase::ResolveGenericParams (HIR::Item::ItemKind::Function, + fn.get_locus (), + function.get_generic_params (), substitutions, false /*is_foreign*/, ABI::RUST); } @@ -231,7 +229,8 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const break; case HIR::SelfParam::IMM_REF: - case HIR::SelfParam::MUT_REF: { + case HIR::SelfParam::MUT_REF: + { auto mutability = self_param.get_self_kind () == HIR::SelfParam::IMM_REF ? Mutability::Imm @@ -275,26 +274,13 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); } - auto &mappings = Analysis::Mappings::get (); - - tl::optional<CanonicalPath> canonical_path; - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - - canonical_path - = nr_ctx.values.to_canonical_path (fn.get_mappings ().get_nodeid ()); - } - else - { - canonical_path - = mappings.lookup_canonical_path (fn.get_mappings ().get_nodeid ()); - } + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - rust_assert (canonical_path); + CanonicalPath canonical_path + = nr_ctx.to_canonical_path (fn.get_mappings ().get_nodeid ()); - RustIdent ident{*canonical_path, fn.get_locus ()}; + RustIdent ident{canonical_path, fn.get_locus ()}; auto resolved = new TyTy::FnType ( fn.get_mappings ().get_hirid (), fn.get_mappings ().get_defid (), function.get_function_name ().as_string (), ident, diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h index 18a65fe..e5a6e9e 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.h +++ b/gcc/rust/typecheck/rust-hir-type-check.h @@ -20,6 +20,7 @@ #define RUST_HIR_TYPE_CHECK #include "rust-hir-map.h" +#include "rust-mapping-common.h" #include "rust-tyty.h" #include "rust-hir-trait-reference.h" #include "rust-stacked-contexts.h" @@ -157,6 +158,39 @@ public: WARN_UNUSED_RESULT Lifetime next () { return Lifetime (interner_index++); } }; +struct DeferredOpOverload +{ + HirId expr_id; + LangItem::Kind lang_item_type; + HIR::PathIdentSegment specified_segment; + TyTy::TypeBoundPredicate predicate; + HIR::OperatorExprMeta op; + + DeferredOpOverload (HirId expr_id, LangItem::Kind lang_item_type, + HIR::PathIdentSegment specified_segment, + TyTy::TypeBoundPredicate &predicate, + HIR::OperatorExprMeta op) + : expr_id (expr_id), lang_item_type (lang_item_type), + specified_segment (specified_segment), predicate (predicate), op (op) + {} + + DeferredOpOverload (const struct DeferredOpOverload &other) + : expr_id (other.expr_id), lang_item_type (other.lang_item_type), + specified_segment (other.specified_segment), predicate (other.predicate), + op (other.op) + {} + + DeferredOpOverload &operator= (struct DeferredOpOverload const &other) + { + expr_id = other.expr_id; + lang_item_type = other.lang_item_type; + specified_segment = other.specified_segment; + op = other.op; + + return *this; + } +}; + class TypeCheckContext { public: @@ -215,10 +249,10 @@ public: bool lookup_associated_type_mapping (HirId id, HirId *mapping); void insert_associated_impl_mapping (HirId trait_id, - const TyTy::BaseType *impl_type, + TyTy::BaseType *impl_type, HirId impl_id); bool lookup_associated_impl_mapping_for_self (HirId trait_id, - const TyTy::BaseType *self, + TyTy::BaseType *self, HirId *mapping); void insert_autoderef_mappings (HirId id, @@ -237,6 +271,13 @@ public: void insert_operator_overload (HirId id, TyTy::FnType *call_site); bool lookup_operator_overload (HirId id, TyTy::FnType **call); + void insert_deferred_operator_overload (DeferredOpOverload deferred); + bool lookup_deferred_operator_overload (HirId id, + DeferredOpOverload *deferred); + + void iterate_deferred_operator_overloads ( + std::function<bool (HirId, DeferredOpOverload &)> cb); + void insert_unconstrained_check_marker (HirId id, bool status); bool have_checked_for_unconstrained (HirId id, bool *result); @@ -263,13 +304,16 @@ public: WARN_UNUSED_RESULT std::vector<TyTy::Region> regions_from_generic_args (const HIR::GenericArgs &args) const; - void compute_inference_variables (bool error); + void compute_inference_variables (bool emit_error); TyTy::VarianceAnalysis::CrateCtx &get_variance_analysis_ctx (); private: TypeCheckContext (); + bool compute_infer_var (HirId id, TyTy::BaseType *ty, bool emit_error); + bool compute_ambigious_op_overload (HirId id, DeferredOpOverload &op); + std::map<NodeId, HirId> node_id_refs; std::map<HirId, TyTy::BaseType *> resolved; std::vector<std::unique_ptr<TyTy::BaseType>> builtins; @@ -281,7 +325,7 @@ private: std::map<HirId, AssociatedImplTrait> associated_impl_traits; // trait-id -> list of < self-tyty:impl-id> - std::map<HirId, std::vector<std::pair<const TyTy::BaseType *, HirId>>> + std::map<HirId, std::vector<std::pair<TyTy::BaseType *, HirId>>> associated_traits_to_impls; std::map<HirId, HirId> associated_type_mappings; @@ -306,6 +350,9 @@ private: std::set<HirId> querys_in_progress; std::set<DefId> trait_queries_in_progress; + // deferred operator overload + std::map<HirId, DeferredOpOverload> deferred_operator_overloads; + // variance analysis TyTy::VarianceAnalysis::CrateCtx variance_analysis_ctx; diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc index f0bd1f8..c5b823e 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.cc +++ b/gcc/rust/typecheck/rust-substitution-mapper.cc @@ -268,6 +268,12 @@ SubstMapperInternal::visit (TyTy::ParamType &type) } void +SubstMapperInternal::visit (TyTy::ConstType &type) +{ + resolved = type.handle_substitions (mappings); +} + +void SubstMapperInternal::visit (TyTy::PlaceholderType &type) { rust_assert (type.can_resolve ()); @@ -374,7 +380,7 @@ SubstMapperInternal::visit (TyTy::DynamicObjectType &type) void SubstMapperInternal::visit (TyTy::OpaqueType &type) { - resolved = type.handle_substitions (mappings); + resolved = type.clone (); } // SubstMapperFromExisting diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h index 32ab71c..2389d83 100644 --- a/gcc/rust/typecheck/rust-substitution-mapper.h +++ b/gcc/rust/typecheck/rust-substitution-mapper.h @@ -61,6 +61,7 @@ public: void visit (TyTy::ReferenceType &) override { rust_unreachable (); } void visit (TyTy::PointerType &) override { rust_unreachable (); } void visit (TyTy::ParamType &) override { rust_unreachable (); } + void visit (TyTy::ConstType &) override { rust_unreachable (); } void visit (TyTy::StrType &) override { rust_unreachable (); } void visit (TyTy::NeverType &) override { rust_unreachable (); } void visit (TyTy::DynamicObjectType &) override { rust_unreachable (); } @@ -92,6 +93,7 @@ public: void visit (TyTy::ReferenceType &type) override; void visit (TyTy::PointerType &type) override; void visit (TyTy::ParamType &type) override; + void visit (TyTy::ConstType &type) override; void visit (TyTy::PlaceholderType &type) override; void visit (TyTy::ProjectionType &type) override; void visit (TyTy::ClosureType &type) override; @@ -145,6 +147,7 @@ public: void visit (TyTy::ReferenceType &) override { rust_unreachable (); } void visit (TyTy::PointerType &) override { rust_unreachable (); } void visit (TyTy::ParamType &) override { rust_unreachable (); } + void visit (TyTy::ConstType &) override { rust_unreachable (); } void visit (TyTy::StrType &) override { rust_unreachable (); } void visit (TyTy::NeverType &) override { rust_unreachable (); } void visit (TyTy::PlaceholderType &) override { rust_unreachable (); } @@ -185,12 +188,13 @@ public: void visit (const TyTy::ReferenceType &) override {} void visit (const TyTy::PointerType &) override {} void visit (const TyTy::ParamType &) override {} + void visit (const TyTy::ConstType &) override {} void visit (const TyTy::StrType &) override {} void visit (const TyTy::NeverType &) override {} void visit (const TyTy::PlaceholderType &) override {} void visit (const TyTy::ProjectionType &) override {} void visit (const TyTy::DynamicObjectType &) override {} - void visit (const TyTy::OpaqueType &type) override {} + void visit (const TyTy::OpaqueType &) override {} private: GetUsedSubstArgs (); diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index c6c5b4b..2d66166 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -24,6 +24,7 @@ #include "rust-hir-type-check.h" #include "rust-hir-type-check-type.h" #include "rust-casts.h" +#include "rust-mapping-common.h" #include "rust-unify.h" #include "rust-coercion.h" #include "rust-hir-type-bounds.h" @@ -37,15 +38,14 @@ bool query_type (HirId reference, TyTy::BaseType **result) { auto &mappings = Analysis::Mappings::get (); - auto &resolver = *Resolver::get (); TypeCheckContext *context = TypeCheckContext::get (); - if (context->query_in_progress (reference)) - return false; - if (context->lookup_type (reference, result)) return true; + if (context->query_in_progress (reference)) + return false; + context->insert_query (reference); std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate @@ -103,18 +103,13 @@ query_type (HirId reference, TyTy::BaseType **result) NodeId ref_node_id = UNKNOWN_NODEID; NodeId ast_node_id = ty.get_mappings ().get_nodeid (); - if (flag_name_resolution_2_0) - { - auto &nr_ctx = Resolver2_0::ImmutableNameResolutionContext::get () - .resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - // assign the ref_node_id if we've found something - nr_ctx.lookup (ast_node_id) - .map ( - [&ref_node_id] (NodeId resolved) { ref_node_id = resolved; }); - } - else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) - resolver.lookup_resolved_type (ast_node_id, &ref_node_id); + // assign the ref_node_id if we've found something + nr_ctx.lookup (ast_node_id).map ([&ref_node_id] (NodeId resolved) { + ref_node_id = resolved; + }); if (ref_node_id != UNKNOWN_NODEID) { @@ -192,10 +187,12 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, TyTy::BaseType *expected = lhs.get_ty (); TyTy::BaseType *expr = rhs.get_ty (); - rust_debug ( - "unify_site_and commit %s infer %s id={%u} expected={%s} expr={%s}", - commit_if_ok ? "true" : "false", implicit_infer_vars ? "true" : "false", id, - expected->debug_str ().c_str (), expr->debug_str ().c_str ()); + rust_debug_loc ( + unify_locus, + "begin unify_site_and commit %s infer %s id={%u} expected={%s} expr={%s}", + commit_if_ok ? "true" : "false", implicit_infer_vars ? "true" : "false", + id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (), + expr->debug_str ().c_str ()); std::vector<UnifyRules::CommitSite> commits; std::vector<UnifyRules::InferenceSite> infers; @@ -203,6 +200,15 @@ unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/, emit_errors, implicit_infer_vars, commits, infers); bool ok = result->get_kind () != TyTy::TypeKind::ERROR; + + rust_debug_loc (unify_locus, + "unify_site_and done ok=%s commit %s infer %s id={%u} " + "expected={%s} expr={%s}", + ok ? "true" : "false", commit_if_ok ? "true" : "false", + implicit_infer_vars ? "true" : "false", + id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (), + expr->debug_str ().c_str ()); + if (ok && commit_if_ok) { for (auto &c : commits) diff --git a/gcc/rust/typecheck/rust-type-util.h b/gcc/rust/typecheck/rust-type-util.h index 03874a4..dd97f1e 100644 --- a/gcc/rust/typecheck/rust-type-util.h +++ b/gcc/rust/typecheck/rust-type-util.h @@ -25,33 +25,30 @@ namespace Rust { namespace Resolver { -bool -query_type (HirId reference, TyTy::BaseType **result); +bool query_type (HirId reference, TyTy::BaseType **result); -bool -types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t unify_locus, bool emit_errors); +bool types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, + location_t unify_locus, bool emit_errors); -TyTy::BaseType * -unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t unify_locus); +TyTy::BaseType *unify_site (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, location_t unify_locus); -TyTy::BaseType * -unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t unify_locus, bool emit_errors, bool commit_if_ok, - bool implicit_infer_vars, bool cleanup); +TyTy::BaseType *unify_site_and (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, + location_t unify_locus, bool emit_errors, + bool commit_if_ok, bool implicit_infer_vars, + bool cleanup); -TyTy::BaseType * -coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t coercion_locus); +TyTy::BaseType *coercion_site (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, + location_t coercion_locus); -TyTy::BaseType * -try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, - location_t coercion_locus); +TyTy::BaseType *try_coercion (HirId id, TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs, + location_t coercion_locus); -TyTy::BaseType * -cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to, - location_t cast_locus); +TyTy::BaseType *cast_site (HirId id, TyTy::TyWithLocation from, + TyTy::TyWithLocation to, location_t cast_locus); AssociatedImplTrait * lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound, diff --git a/gcc/rust/typecheck/rust-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 9112b99..c74a920 100644 --- a/gcc/rust/typecheck/rust-typecheck-context.cc +++ b/gcc/rust/typecheck/rust-typecheck-context.cc @@ -18,6 +18,7 @@ #include "rust-hir-type-check.h" #include "rust-type-util.h" +#include "rust-hir-type-check-expr.h" namespace Rust { namespace Resolver { @@ -299,8 +300,9 @@ TypeCheckContext::lookup_associated_type_mapping (HirId id, HirId *mapping) } void -TypeCheckContext::insert_associated_impl_mapping ( - HirId trait_id, const TyTy::BaseType *impl_type, HirId impl_id) +TypeCheckContext::insert_associated_impl_mapping (HirId trait_id, + TyTy::BaseType *impl_type, + HirId impl_id) { auto it = associated_traits_to_impls.find (trait_id); if (it == associated_traits_to_impls.end ()) @@ -312,8 +314,9 @@ TypeCheckContext::insert_associated_impl_mapping ( } bool -TypeCheckContext::lookup_associated_impl_mapping_for_self ( - HirId trait_id, const TyTy::BaseType *self, HirId *mapping) +TypeCheckContext::lookup_associated_impl_mapping_for_self (HirId trait_id, + TyTy::BaseType *self, + HirId *mapping) { auto it = associated_traits_to_impls.find (trait_id); if (it == associated_traits_to_impls.end ()) @@ -321,7 +324,9 @@ TypeCheckContext::lookup_associated_impl_mapping_for_self ( for (auto &item : it->second) { - if (item.first->can_eq (self, false)) + if (types_compatable (TyTy::TyWithLocation (item.first), + TyTy::TyWithLocation (self), UNKNOWN_LOCATION, + false)) { *mapping = item.second; return true; @@ -409,6 +414,38 @@ TypeCheckContext::lookup_operator_overload (HirId id, TyTy::FnType **call) } void +TypeCheckContext::insert_deferred_operator_overload ( + DeferredOpOverload deferred) +{ + HirId expr_id = deferred.expr_id; + deferred_operator_overloads.emplace (std::make_pair (expr_id, deferred)); +} + +bool +TypeCheckContext::lookup_deferred_operator_overload ( + HirId id, DeferredOpOverload *deferred) +{ + auto it = deferred_operator_overloads.find (id); + if (it == deferred_operator_overloads.end ()) + return false; + + *deferred = it->second; + return true; +} + +void +TypeCheckContext::iterate_deferred_operator_overloads ( + std::function<bool (HirId, DeferredOpOverload &)> cb) +{ + for (auto it = deferred_operator_overloads.begin (); + it != deferred_operator_overloads.end (); it++) + { + if (!cb (it->first, it->second)) + return; + } +} + +void TypeCheckContext::insert_unconstrained_check_marker (HirId id, bool status) { unconstrained[id] = status; @@ -574,44 +611,77 @@ TypeCheckContext::regions_from_generic_args (const HIR::GenericArgs &args) const return regions; } +bool +TypeCheckContext::compute_ambigious_op_overload (HirId id, + DeferredOpOverload &op) +{ + rust_debug ("attempting resolution of op overload: %s", + op.predicate.as_string ().c_str ()); + + TyTy::BaseType *lhs = nullptr; + bool ok = lookup_type (op.op.get_lvalue_mappings ().get_hirid (), &lhs); + rust_assert (ok); + + TyTy::BaseType *rhs = nullptr; + if (op.op.has_rvalue_mappings ()) + { + bool ok = lookup_type (op.op.get_rvalue_mappings ().get_hirid (), &rhs); + rust_assert (ok); + } + + TypeCheckExpr::ResolveOpOverload (op.lang_item_type, op.op, lhs, rhs, + op.specified_segment); + + return true; +} + void -TypeCheckContext::compute_inference_variables (bool error) +TypeCheckContext::compute_inference_variables (bool emit_error) { - auto &mappings = Analysis::Mappings::get (); + iterate_deferred_operator_overloads ( + [&] (HirId id, DeferredOpOverload &op) mutable -> bool { + return compute_ambigious_op_overload (id, op); + }); - // default inference variables if possible iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool { - // nothing to do - if (ty->get_kind () != TyTy::TypeKind::INFER) - return true; + return compute_infer_var (id, ty, emit_error); + }); +} - TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty); - TyTy::BaseType *default_type; - - rust_debug_loc (mappings.lookup_location (id), - "trying to default infer-var: %s", - infer_var->as_string ().c_str ()); - bool ok = infer_var->default_type (&default_type); - if (!ok) - { - if (error) - rust_error_at (mappings.lookup_location (id), ErrorCode::E0282, - "type annotations needed"); - return true; - } - - auto result - = unify_site (id, TyTy::TyWithLocation (ty), - TyTy::TyWithLocation (default_type), UNDEF_LOCATION); - rust_assert (result); - rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); - result->set_ref (id); - insert_type (Analysis::NodeMapping (mappings.get_current_crate (), 0, id, - UNKNOWN_LOCAL_DEFID), - result); +bool +TypeCheckContext::compute_infer_var (HirId id, TyTy::BaseType *ty, + bool emit_error) +{ + auto &mappings = Analysis::Mappings::get (); + // nothing to do + if (ty->get_kind () != TyTy::TypeKind::INFER) return true; - }); + + TyTy::InferType *infer_var = static_cast<TyTy::InferType *> (ty); + TyTy::BaseType *default_type; + + rust_debug_loc (mappings.lookup_location (id), + "trying to default infer-var: %s", + infer_var->as_string ().c_str ()); + bool ok = infer_var->default_type (&default_type); + if (!ok) + { + if (emit_error) + rust_error_at (mappings.lookup_location (id), ErrorCode::E0282, + "type annotations needed"); + return true; + } + + auto result + = unify_site (id, TyTy::TyWithLocation (ty), + TyTy::TyWithLocation (default_type), UNDEF_LOCATION); + rust_assert (result); + rust_assert (result->get_kind () != TyTy::TypeKind::ERROR); + result->set_ref (id); + insert_implicit_type (id, result); + + return true; } TyTy::VarianceAnalysis::CrateCtx & diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index e028a0a..6cf9b04 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -61,6 +61,39 @@ TypeBoundsProbe::is_bound_satisfied_for_type (TyTy::BaseType *receiver, return false; } +bool +TypeBoundsProbe::process_impl_block ( + HirId id, HIR::ImplBlock *impl, + std::vector<std::pair<HIR::TypePath *, HIR::ImplBlock *>> + &possible_trait_paths) +{ + // we are filtering for trait-impl-blocks + if (!impl->has_trait_ref ()) + return true; + + // can be recursive trait resolution + HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ()); + if (t == nullptr) + return true; + // DefId trait_id = t->get_mappings ().get_defid (); + // if (context->trait_query_in_progress (trait_id)) + // return true; + + HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); + TyTy::BaseType *impl_type = nullptr; + if (!query_type (impl_ty_id, &impl_type)) + return true; + + if (!receiver->can_eq (impl_type, false)) + { + if (!impl_type->can_eq (receiver, false)) + return true; + } + + possible_trait_paths.push_back ({&impl->get_trait_ref (), impl}); + return true; +} + void TypeBoundsProbe::scan () { @@ -68,31 +101,7 @@ TypeBoundsProbe::scan () possible_trait_paths; mappings.iterate_impl_blocks ( [&] (HirId id, HIR::ImplBlock *impl) mutable -> bool { - // we are filtering for trait-impl-blocks - if (!impl->has_trait_ref ()) - return true; - - // can be recursive trait resolution - HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ()); - if (t == nullptr) - return true; - DefId trait_id = t->get_mappings ().get_defid (); - if (context->trait_query_in_progress (trait_id)) - return true; - - HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); - TyTy::BaseType *impl_type = nullptr; - if (!query_type (impl_ty_id, &impl_type)) - return true; - - if (!receiver->can_eq (impl_type, false)) - { - if (!impl_type->can_eq (receiver, false)) - return true; - } - - possible_trait_paths.push_back ({&impl->get_trait_ref (), impl}); - return true; + return process_impl_block (id, impl, possible_trait_paths); }); for (auto &path : possible_trait_paths) @@ -105,7 +114,7 @@ TypeBoundsProbe::scan () } // marker traits... - assemble_sized_builtin (); + assemble_marker_builtins (); // add auto trait bounds for (auto *auto_trait : mappings.get_auto_traits ()) @@ -113,7 +122,7 @@ TypeBoundsProbe::scan () } void -TypeBoundsProbe::assemble_sized_builtin () +TypeBoundsProbe::assemble_marker_builtins () { const TyTy::BaseType *raw = receiver->destructure (); @@ -132,7 +141,6 @@ TypeBoundsProbe::assemble_sized_builtin () case TyTy::POINTER: case TyTy::PARAM: case TyTy::FNDEF: - case TyTy::FNPTR: case TyTy::BOOL: case TyTy::CHAR: case TyTy::INT: @@ -140,7 +148,6 @@ TypeBoundsProbe::assemble_sized_builtin () case TyTy::FLOAT: case TyTy::USIZE: case TyTy::ISIZE: - case TyTy::CLOSURE: case TyTy::INFER: case TyTy::NEVER: case TyTy::PLACEHOLDER: @@ -149,6 +156,14 @@ TypeBoundsProbe::assemble_sized_builtin () assemble_builtin_candidate (LangItem::Kind::SIZED); break; + case TyTy::FNPTR: + case TyTy::CLOSURE: + assemble_builtin_candidate (LangItem::Kind::SIZED); + assemble_builtin_candidate (LangItem::Kind::FN_ONCE); + assemble_builtin_candidate (LangItem::Kind::FN); + assemble_builtin_candidate (LangItem::Kind::FN_MUT); + break; + // FIXME str and slice need to be moved and test cases updated case TyTy::SLICE: case TyTy::STR: @@ -158,6 +173,7 @@ TypeBoundsProbe::assemble_sized_builtin () assemble_builtin_candidate (LangItem::Kind::SIZED); break; + case TyTy::CONST: case TyTy::DYNAMIC: case TyTy::ERROR: break; @@ -206,7 +222,7 @@ TyTy::TypeBoundPredicate TypeCheckBase::get_predicate_from_bound ( HIR::TypePath &type_path, tl::optional<std::reference_wrapper<HIR::Type>> associated_self, - BoundPolarity polarity, bool is_qualified_type_path) + BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait) { TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error (); bool already_resolved @@ -226,7 +242,8 @@ TypeCheckBase::get_predicate_from_bound ( auto &final_seg = type_path.get_final_segment (); switch (final_seg.get_type ()) { - case HIR::TypePathSegment::SegmentType::GENERIC: { + case HIR::TypePathSegment::SegmentType::GENERIC: + { auto &final_generic_seg = static_cast<HIR::TypePathSegmentGeneric &> (final_seg); if (final_generic_seg.has_generic_args ()) @@ -251,7 +268,8 @@ TypeCheckBase::get_predicate_from_bound ( } break; - case HIR::TypePathSegment::SegmentType::FUNCTION: { + case HIR::TypePathSegment::SegmentType::FUNCTION: + { auto &final_function_seg = static_cast<HIR::TypePathSegmentFunction &> (final_seg); auto &fn = final_function_seg.get_function_path (); @@ -327,7 +345,8 @@ TypeCheckBase::get_predicate_from_bound ( if (!args.is_empty () || predicate.requires_generic_args ()) { // this is applying generic arguments to a trait reference - predicate.apply_generic_arguments (&args, associated_self.has_value ()); + predicate.apply_generic_arguments (&args, associated_self.has_value (), + is_super_trait); } context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (), @@ -508,7 +527,8 @@ TypeBoundPredicate::is_object_safe (bool emit_error, location_t locus) const void TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, - bool has_associated_self) + bool has_associated_self, + bool is_super_trait) { rust_assert (!substitutions.empty ()); if (has_associated_self) @@ -529,23 +549,26 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, Resolver::TypeCheckContext::get ()->regions_from_generic_args ( *generic_args)); - apply_argument_mappings (args); + apply_argument_mappings (args, is_super_trait); } void TypeBoundPredicate::apply_argument_mappings ( - SubstitutionArgumentMappings &arguments) + SubstitutionArgumentMappings &arguments, bool is_super_trait) { used_arguments = arguments; error_flag |= used_arguments.is_error (); auto &subst_mappings = used_arguments; + + bool substs_need_bounds_check = !is_super_trait; for (auto &sub : get_substs ()) { SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (sub.get_param_ty (), &arg); if (ok && arg.get_tyty () != nullptr) - sub.fill_param_ty (subst_mappings, subst_mappings.get_locus ()); + sub.fill_param_ty (subst_mappings, subst_mappings.get_locus (), + substs_need_bounds_check); } // associated argument mappings @@ -566,7 +589,7 @@ TypeBoundPredicate::apply_argument_mappings ( auto adjusted = super_trait.adjust_mappings_for_this (used_arguments, true /*trait mode*/); - super_trait.apply_argument_mappings (adjusted); + super_trait.apply_argument_mappings (adjusted, is_super_trait); } } @@ -699,7 +722,7 @@ TypeBoundPredicate::handle_substitions ( if (sub.get_param_ty () == nullptr) continue; - ParamType *p = sub.get_param_ty (); + auto p = sub.get_param_ty (); BaseType *r = p->resolve (); BaseType *s = Resolver::SubstMapperInternal::Resolve (r, subst_mappings); @@ -746,16 +769,34 @@ size_t TypeBoundPredicate::get_num_associated_bindings () const { size_t count = 0; + + get_trait_hierachy ([&count] (const Resolver::TraitReference &ref) { + for (const auto &trait_item : ref.get_trait_items ()) + { + bool is_associated_type + = trait_item.get_trait_item_type () + == Resolver::TraitItemReference::TraitItemType::TYPE; + if (is_associated_type) + count++; + } + }); + + return count; +} + +void +TypeBoundPredicate::get_trait_hierachy ( + std::function<void (const Resolver::TraitReference &)> callback) const +{ auto trait_ref = get (); - for (const auto &trait_item : trait_ref->get_trait_items ()) + callback (*trait_ref); + + for (auto &super : super_traits) { - bool is_associated_type - = trait_item.get_trait_item_type () - == Resolver::TraitItemReference::TraitItemType::TYPE; - if (is_associated_type) - count++; + const auto &super_trait_ref = *super.get (); + callback (super_trait_ref); + super.get_trait_hierachy (callback); } - return count; } TypeBoundPredicateItem @@ -808,21 +849,19 @@ TypeBoundPredicate::is_equal (const TypeBoundPredicate &other) const // then match the generics applied for (size_t i = 0; i < get_num_substitutions (); i++) { - const SubstitutionParamMapping &a = substitutions.at (i); - const SubstitutionParamMapping &b = other.substitutions.at (i); + SubstitutionParamMapping a = substitutions.at (i); + SubstitutionParamMapping b = other.substitutions.at (i); - const ParamType *ap = a.get_param_ty (); - const ParamType *bp = b.get_param_ty (); + auto ap = a.get_param_ty (); + auto bp = b.get_param_ty (); - const BaseType *apd = ap->destructure (); - const BaseType *bpd = bp->destructure (); + BaseType *apd = ap->destructure (); + BaseType *bpd = bp->destructure (); - // FIXME use the unify_and infer inteface or try coerce - if (!apd->can_eq (bpd, false /*emit_errors*/)) - { - if (!bpd->can_eq (apd, false /*emit_errors*/)) - return false; - } + if (!Resolver::types_compatable (TyTy::TyWithLocation (apd), + TyTy::TyWithLocation (bpd), + UNKNOWN_LOCATION, false)) + return false; } return true; diff --git a/gcc/rust/typecheck/rust-tyty-call.cc b/gcc/rust/typecheck/rust-tyty-call.cc index 2e0830e..63bb1ff 100644 --- a/gcc/rust/typecheck/rust-tyty-call.cc +++ b/gcc/rust/typecheck/rust-tyty-call.cc @@ -171,7 +171,8 @@ TypeCheckCallExpr::visit (FnType &type) { case TyTy::TypeKind::ERROR: return; - case TyTy::TypeKind::INT: { + case TyTy::TypeKind::INT: + { auto &int_ty = static_cast<TyTy::IntType &> (*argument_expr_tyty); if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8) @@ -186,7 +187,8 @@ TypeCheckCallExpr::visit (FnType &type) } break; } - case TyTy::TypeKind::UINT: { + case TyTy::TypeKind::UINT: + { auto &uint_ty = static_cast<TyTy::UintType &> (*argument_expr_tyty); if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8) @@ -202,7 +204,8 @@ TypeCheckCallExpr::visit (FnType &type) } break; } - case TyTy::TypeKind::FLOAT: { + case TyTy::TypeKind::FLOAT: + { if (static_cast<TyTy::FloatType &> (*argument_expr_tyty) .get_float_kind () == TyTy::FloatType::FloatKind::F32) @@ -216,14 +219,16 @@ TypeCheckCallExpr::visit (FnType &type) } break; } - case TyTy::TypeKind::BOOL: { + case TyTy::TypeKind::BOOL: + { rich_location richloc (line_table, arg_locus); richloc.add_fixit_replace ("cast the value to c_int: as c_int"); rust_error_at (arg_locus, ErrorCode::E0617, "expected %<c_int%> variadic argument"); return; } - case TyTy::TypeKind::FNDEF: { + case TyTy::TypeKind::FNDEF: + { rust_error_at ( arg_locus, ErrorCode::E0617, "unexpected function definition type as variadic " @@ -246,7 +251,7 @@ TypeCheckCallExpr::visit (FnType &type) } type.monomorphize (); - resolved = type.get_return_type ()->clone (); + resolved = type.get_return_type ()->monomorphized_clone (); } void diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h index c42fdcd..9e4aab5 100644 --- a/gcc/rust/typecheck/rust-tyty-call.h +++ b/gcc/rust/typecheck/rust-tyty-call.h @@ -62,6 +62,7 @@ public: void visit (DynamicObjectType &) override { rust_unreachable (); } void visit (ClosureType &type) override { rust_unreachable (); } void visit (OpaqueType &type) override { rust_unreachable (); } + void visit (ConstType &type) override { rust_unreachable (); } // tuple-structs void visit (ADTType &type) override; diff --git a/gcc/rust/typecheck/rust-tyty-cmp.h b/gcc/rust/typecheck/rust-tyty-cmp.h index c897c13..c22dfdd 100644 --- a/gcc/rust/typecheck/rust-tyty-cmp.h +++ b/gcc/rust/typecheck/rust-tyty-cmp.h @@ -447,6 +447,22 @@ public: } } + virtual void visit (const ConstType &type) override + { + ok = false; + if (emit_error_flag) + { + location_t ref_locus = mappings.lookup_location (type.get_ref ()); + location_t base_locus + = mappings.lookup_location (get_base ()->get_ref ()); + rich_location r (line_table, ref_locus); + r.add_range (base_locus); + rust_error_at (r, "expected [%s] got [%s]", + get_base ()->as_string ().c_str (), + type.as_string ().c_str ()); + } + } + protected: BaseCmp (const BaseType *base, bool emit_errors) : mappings (Analysis::Mappings::get ()), @@ -621,7 +637,8 @@ public: ok = true; return; - case InferType::InferTypeKind::INTEGRAL: { + case InferType::InferTypeKind::INTEGRAL: + { if (type.get_infer_kind () == InferType::InferTypeKind::INTEGRAL) { ok = true; @@ -635,7 +652,8 @@ public: } break; - case InferType::InferTypeKind::FLOAT: { + case InferType::InferTypeKind::FLOAT: + { if (type.get_infer_kind () == InferType::InferTypeKind::FLOAT) { ok = true; @@ -1604,6 +1622,23 @@ private: const OpaqueType *base; }; +class ConstCmp : public BaseCmp +{ + using Rust::TyTy::BaseCmp::visit; + +public: + ConstCmp (const ConstType *base, bool emit_errors) + : BaseCmp (base, emit_errors), base (base) + {} + + // TODO + +private: + const BaseType *get_base () const override { return base; } + + const ConstType *base; +}; + } // namespace TyTy } // namespace Rust diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index bdb6474..817910b 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -18,18 +18,22 @@ #include "rust-tyty-subst.h" +#include "rust-hir-generic-param.h" #include "rust-system.h" #include "rust-tyty.h" #include "rust-hir-type-check.h" #include "rust-substitution-mapper.h" #include "rust-hir-type-check-type.h" +#include "rust-hir-type-check-expr.h" +#include "rust-compile-base.h" #include "rust-type-util.h" +#include "tree.h" namespace Rust { namespace TyTy { -SubstitutionParamMapping::SubstitutionParamMapping (HIR::TypeParam &generic, - ParamType *param) +SubstitutionParamMapping::SubstitutionParamMapping (HIR::GenericParam &generic, + BaseGeneric *param) : generic (generic), param (param) {} @@ -54,30 +58,42 @@ SubstitutionParamMapping::clone () const static_cast<ParamType *> (param->clone ())); } -ParamType * +BaseGeneric * SubstitutionParamMapping::get_param_ty () { return param; } -const ParamType * +const BaseGeneric * SubstitutionParamMapping::get_param_ty () const { return param; } -HIR::TypeParam & +HIR::GenericParam & SubstitutionParamMapping::get_generic_param () { return generic; } +const HIR::GenericParam & +SubstitutionParamMapping::get_generic_param () const +{ + return generic; +} + bool SubstitutionParamMapping::needs_substitution () const { return !(get_param_ty ()->is_concrete ()); } +Identifier +SubstitutionParamMapping::get_type_representation () const +{ + return param->get_symbol (); +} + location_t SubstitutionParamMapping::get_param_locus () const { @@ -87,13 +103,35 @@ SubstitutionParamMapping::get_param_locus () const bool SubstitutionParamMapping::param_has_default_ty () const { - return generic.has_type (); + if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) + { + const auto &type_param = static_cast<const HIR::TypeParam &> (generic); + return type_param.has_type (); + } + + rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::CONST); + const auto &const_param + = static_cast<const HIR::ConstGenericParam &> (generic); + return const_param.has_default_expression (); } BaseType * SubstitutionParamMapping::get_default_ty () const { - TyVar var (generic.get_type_mappings ().get_hirid ()); + if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) + { + const auto &type_param = static_cast<const HIR::TypeParam &> (generic); + TyVar var (type_param.get_type_mappings ().get_hirid ()); + return var.get_tyty (); + } + + rust_assert (generic.get_kind () == HIR::GenericParam::GenericKind::CONST); + const auto &const_param + = static_cast<const HIR::ConstGenericParam &> (generic); + rust_assert (const_param.has_default_expression ()); + + const auto &expr = const_param.get_default_expression (); + TyVar var (expr.get_mappings ().get_hirid ()); return var.get_tyty (); } @@ -109,7 +147,8 @@ SubstitutionParamMapping::need_substitution () const bool SubstitutionParamMapping::fill_param_ty ( - SubstitutionArgumentMappings &subst_mappings, location_t locus) + SubstitutionArgumentMappings &subst_mappings, location_t locus, + bool needs_bounds_check) { SubstitutionArg arg = SubstitutionArg::error (); bool ok = subst_mappings.get_argument_for_symbol (get_param_ty (), &arg); @@ -124,17 +163,21 @@ SubstitutionParamMapping::fill_param_ty ( if (type.get_kind () == TypeKind::PARAM) { - // delete param; - param = static_cast<ParamType *> (type.clone ()); + param = static_cast<BaseGeneric *> (type.clone ()); } - else + else if (type.get_kind () == TyTy::TypeKind::CONST) { + param = static_cast<BaseGeneric *> (type.clone ()); + } + else if (param->get_kind () == TypeKind::PARAM) + { + auto &p = *static_cast<TyTy::ParamType *> (param); + // check the substitution is compatible with bounds rust_debug_loc (locus, "fill_param_ty bounds_compatible: param %s type %s", param->get_name ().c_str (), type.get_name ().c_str ()); - - if (!param->is_implicit_self_trait ()) + if (needs_bounds_check && !p.is_implicit_self_trait ()) { if (!param->bounds_compatible (type, locus, true)) return false; @@ -145,7 +188,7 @@ SubstitutionParamMapping::fill_param_ty ( bound.handle_substitions (subst_mappings); param->set_ty_ref (type.get_ref ()); - subst_mappings.on_param_subst (*param, arg); + subst_mappings.on_param_subst (p, arg); } return true; @@ -191,12 +234,6 @@ SubstitutionArg::operator= (const SubstitutionArg &other) } BaseType * -SubstitutionArg::get_tyty () -{ - return argument; -} - -const BaseType * SubstitutionArg::get_tyty () const { return argument; @@ -208,7 +245,7 @@ SubstitutionArg::get_param_mapping () const return param; } -const ParamType * +const BaseGeneric * SubstitutionArg::get_param_ty () const { return original_param; @@ -313,11 +350,11 @@ SubstitutionArgumentMappings::is_error () const bool SubstitutionArgumentMappings::get_argument_for_symbol ( - const ParamType *param_to_find, SubstitutionArg *argument) const + const BaseGeneric *param_to_find, SubstitutionArg *argument) const { for (const auto &mapping : mappings) { - const ParamType *p = mapping.get_param_ty (); + const auto *p = mapping.get_param_ty (); if (p->get_symbol () == param_to_find->get_symbol ()) { *argument = mapping; @@ -618,7 +655,6 @@ SubstitutionRef::get_mappings_from_generic_args ( if (args.get_binding_args ().size () > get_num_associated_bindings ()) { rich_location r (line_table, args.get_locus ()); - rust_error_at (r, "generic item takes at most %lu type binding " "arguments but %lu were supplied", @@ -666,11 +702,17 @@ SubstitutionRef::get_mappings_from_generic_args ( // for inherited arguments size_t offs = used_arguments.size (); - if (args.get_type_args ().size () + offs > substitutions.size ()) + size_t total_arguments + = args.get_type_args ().size () + args.get_const_args ().size () + offs; + if (total_arguments > substitutions.size ()) { rich_location r (line_table, args.get_locus ()); if (!substitutions.empty ()) - r.add_range (substitutions.front ().get_param_locus ()); + { + const auto &subst = substitutions.front (); + const auto &generic = subst.get_generic_param (); + r.add_range (generic.get_locus ()); + } rust_error_at ( r, @@ -680,10 +722,15 @@ SubstitutionRef::get_mappings_from_generic_args ( return SubstitutionArgumentMappings::error (); } - if (args.get_type_args ().size () + offs < min_required_substitutions ()) + if (total_arguments < min_required_substitutions ()) { rich_location r (line_table, args.get_locus ()); - r.add_range (substitutions.front ().get_param_locus ()); + if (!substitutions.empty ()) + { + const auto &subst = substitutions.front (); + const auto &generic = subst.get_generic_param (); + r.add_range (generic.get_locus ()); + } rust_error_at ( r, ErrorCode::E0107, @@ -702,7 +749,91 @@ SubstitutionRef::get_mappings_from_generic_args ( return SubstitutionArgumentMappings::error (); } - SubstitutionArg subst_arg (&substitutions.at (offs), resolved); + const auto ¶m_mapping = substitutions.at (offs); + const auto &generic = param_mapping.get_generic_param (); + if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) + { + const auto &type_param + = static_cast<const HIR::TypeParam &> (generic); + if (type_param.from_impl_trait ()) + { + rich_location r (line_table, arg->get_locus ()); + r.add_fixit_remove (arg->get_locus ()); + rust_error_at (r, ErrorCode::E0632, + "cannot provide explicit generic arguments when " + "%<impl Trait%> is used in argument position"); + return SubstitutionArgumentMappings::error (); + } + } + else if (generic.get_kind () == HIR::GenericParam::GenericKind::CONST) + { + if (!resolved->is<ConstType> ()) + { + rich_location r (line_table, arg->get_locus ()); + r.add_fixit_remove (arg->get_locus ()); + rust_error_at (r, ErrorCode::E0747, + "type provided when a constant was expected"); + return SubstitutionArgumentMappings::error (); + } + } + + SubstitutionArg subst_arg (¶m_mapping, resolved); + offs++; + mappings.push_back (std::move (subst_arg)); + } + + for (auto &arg : args.get_const_args ()) + { + auto &expr = *arg.get_expression ().get (); + BaseType *expr_type = Resolver::TypeCheckExpr::Resolve (expr); + if (expr_type == nullptr || expr_type->is<ErrorType> ()) + return SubstitutionArgumentMappings::error (); + + // validate this param is really a const generic + const auto ¶m_mapping = substitutions.at (offs); + const auto &generic = param_mapping.get_generic_param (); + if (generic.get_kind () != HIR::GenericParam::GenericKind::CONST) + { + rich_location r (line_table, arg.get_locus ()); + r.add_fixit_remove (expr.get_locus ()); + rust_error_at (r, "invalid position for a const generic argument"); + return SubstitutionArgumentMappings::error (); + } + + // get the const generic specified type + const auto base_generic = param_mapping.get_param_ty (); + rust_assert (base_generic->is<ConstType> ()); + const auto const_param + = static_cast<const TyTy::ConstType *> (base_generic); + auto specified_type = const_param->get_ty (); + + // validate this const generic is of the correct type + auto coereced_type + = Resolver::coercion_site (expr.get_mappings ().get_hirid (), + TyTy::TyWithLocation (specified_type), + TyTy::TyWithLocation (expr_type, + expr.get_locus ()), + arg.get_locus ()); + if (coereced_type->is<ErrorType> ()) + return SubstitutionArgumentMappings::error (); + + // const fold it + auto ctx = Compile::Context::get (); + tree folded + = Compile::HIRCompileBase::query_compile_const_expr (ctx, coereced_type, + expr); + + if (folded == error_mark_node) + return SubstitutionArgumentMappings::error (); + + // create const type + auto const_value + = new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, "", + coereced_type, folded, {}, expr.get_locus (), + expr.get_mappings ().get_hirid (), + expr.get_mappings ().get_hirid (), {}); + + SubstitutionArg subst_arg (¶m_mapping, const_value); offs++; mappings.push_back (std::move (subst_arg)); } @@ -754,6 +885,7 @@ SubstitutionRef::infer_substitions (location_t locus) { if (p.needs_substitution ()) { + const HIR::GenericParam &generic = p.get_generic_param (); const std::string &symbol = p.get_param_ty ()->get_symbol (); auto it = argument_mappings.find (symbol); bool have_mapping = it != argument_mappings.end (); @@ -762,12 +894,24 @@ SubstitutionRef::infer_substitions (location_t locus) { args.push_back (SubstitutionArg (&p, it->second)); } - else + else if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) { TyVar infer_var = TyVar::get_implicit_infer_var (locus); args.push_back (SubstitutionArg (&p, infer_var.get_tyty ())); argument_mappings[symbol] = infer_var.get_tyty (); } + else if (generic.get_kind () == HIR::GenericParam::GenericKind::CONST) + { + const auto const_param = p.get_param_ty (); + rust_assert (const_param->is<TyTy::ConstType> ()); + const auto &const_type + = *static_cast<const TyTy::ConstType *> (const_param); + + TyVar infer_var + = TyVar::get_implicit_const_infer_var (const_type, locus); + args.push_back (SubstitutionArg (&p, infer_var.get_tyty ())); + argument_mappings[symbol] = infer_var.get_tyty (); + } } else { @@ -905,7 +1049,7 @@ SubstitutionRef::prepare_higher_ranked_bounds () { for (const auto &subst : get_substs ()) { - const TyTy::ParamType *pty = subst.get_param_ty (); + const auto pty = subst.get_param_ty (); for (const auto &bound : pty->get_specified_bounds ()) { const auto ref = bound.get (); @@ -919,8 +1063,7 @@ SubstitutionRef::monomorphize () { for (const auto &subst : get_substs ()) { - const TyTy::ParamType *pty = subst.get_param_ty (); - + const auto pty = subst.get_param_ty (); if (!pty->can_resolve ()) continue; diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index e6ed1fc..c1bc96a 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -24,12 +24,14 @@ #include "rust-hir-full-decls.h" #include "rust-tyty-bounds.h" #include "rust-tyty-region.h" +#include "rust-ast.h" #include "optional.h" namespace Rust { namespace TyTy { class ParamType; +class BaseGeneric; struct RegionConstraints { @@ -44,22 +46,24 @@ class SubstitutionArgumentMappings; class SubstitutionParamMapping { public: - SubstitutionParamMapping (HIR::TypeParam &generic, ParamType *param); + SubstitutionParamMapping (HIR::GenericParam &generic, BaseGeneric *param); SubstitutionParamMapping (const SubstitutionParamMapping &other); std::string as_string () const; bool fill_param_ty (SubstitutionArgumentMappings &subst_mappings, - location_t locus); + location_t locus, bool needs_bounds_check = true); SubstitutionParamMapping clone () const; - ParamType *get_param_ty (); + BaseGeneric *get_param_ty (); + const BaseGeneric *get_param_ty () const; - const ParamType *get_param_ty () const; + HIR::GenericParam &get_generic_param (); + const HIR::GenericParam &get_generic_param () const; - HIR::TypeParam &get_generic_param (); + Identifier get_type_representation () const; // this is used for the backend to override the HirId ref of the param to // what the concrete type is for the rest of the context @@ -76,8 +80,8 @@ public: bool need_substitution () const; private: - HIR::TypeParam &generic; - ParamType *param; + HIR::GenericParam &generic; + BaseGeneric *param; }; /** @@ -147,13 +151,11 @@ public: SubstitutionArg &operator= (const SubstitutionArg &other); - BaseType *get_tyty (); - - const BaseType *get_tyty () const; + BaseType *get_tyty () const; const SubstitutionParamMapping *get_param_mapping () const; - const ParamType *get_param_ty () const; + const BaseGeneric *get_param_ty () const; static SubstitutionArg error (); @@ -165,7 +167,7 @@ public: private: const SubstitutionParamMapping *param; - const ParamType *original_param; + const BaseGeneric *original_param; BaseType *argument; }; @@ -205,7 +207,7 @@ public: bool is_error () const; - bool get_argument_for_symbol (const ParamType *param_to_find, + bool get_argument_for_symbol (const BaseGeneric *param_to_find, SubstitutionArg *argument) const; /** Return type parameter index for symbol */ diff --git a/gcc/rust/typecheck/rust-tyty-util.cc b/gcc/rust/typecheck/rust-tyty-util.cc index ff210ce..4bc1723 100644 --- a/gcc/rust/typecheck/rust-tyty-util.cc +++ b/gcc/rust/typecheck/rust-tyty-util.cc @@ -17,6 +17,8 @@ // <http://www.gnu.org/licenses/>. #include "rust-hir-type-check.h" +#include "rust-mapping-common.h" +#include "rust-system.h" #include "rust-tyty.h" namespace Rust { @@ -47,14 +49,30 @@ TyVar::get_implicit_infer_var (location_t locus) auto &mappings = Analysis::Mappings::get (); auto context = Resolver::TypeCheckContext::get (); - InferType *infer = new InferType (mappings.get_next_hir_id (), - InferType::InferTypeKind::GENERAL, - InferType::TypeHint::Default (), locus); - context->insert_type (Analysis::NodeMapping (mappings.get_current_crate (), - UNKNOWN_NODEID, - infer->get_ref (), - UNKNOWN_LOCAL_DEFID), - infer); + HirId next = mappings.get_next_hir_id (); + auto infer = new InferType (next, InferType::InferTypeKind::GENERAL, + InferType::TypeHint::Default (), locus); + + context->insert_implicit_type (infer->get_ref (), infer); + mappings.insert_location (infer->get_ref (), locus); + + return TyVar (infer->get_ref ()); +} + +TyVar +TyVar::get_implicit_const_infer_var (const ConstType &const_type, + location_t locus) +{ + auto &mappings = Analysis::Mappings::get (); + auto context = Resolver::TypeCheckContext::get (); + + HirId next = mappings.get_next_hir_id (); + auto infer + = new ConstType (ConstType::ConstKind::Infer, const_type.get_symbol (), + const_type.get_ty (), error_mark_node, + const_type.get_specified_bounds (), locus, next, next, {}); + + context->insert_implicit_type (infer->get_ref (), infer); mappings.insert_location (infer->get_ref (), locus); return TyVar (infer->get_ref ()); diff --git a/gcc/rust/typecheck/rust-tyty-util.h b/gcc/rust/typecheck/rust-tyty-util.h index cbb3e8e..1c8fd72 100644 --- a/gcc/rust/typecheck/rust-tyty-util.h +++ b/gcc/rust/typecheck/rust-tyty-util.h @@ -25,6 +25,7 @@ namespace Rust { namespace TyTy { class BaseType; +class ConstType; // this is a placeholder for types that can change like inference variables class TyVar @@ -42,6 +43,9 @@ public: static TyVar get_implicit_infer_var (location_t locus); + static TyVar get_implicit_const_infer_var (const TyTy::ConstType &const_type, + location_t locus); + static TyVar subst_covariant_var (TyTy::BaseType *orig, TyTy::BaseType *subst); diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h b/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h index d36afc8..deb76a7 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h @@ -170,6 +170,8 @@ public: } void visit (OpaqueType &type) override {} + + void visit (ConstType &type) override {} }; /** Per crate context for generic type variance analysis. */ diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.cc b/gcc/rust/typecheck/rust-tyty-variance-analysis.cc index 38f9d52..7971ccf 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis.cc +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.cc @@ -199,9 +199,7 @@ GenericTyPerCrateCtx::debug_print_solutions () { if (i > solution_index) result += ", "; - result += param.get_generic_param () - .get_type_representation () - .as_string (); + result += param.get_type_representation ().as_string (); result += "="; result += solutions[i].as_string (); i++; @@ -239,8 +237,7 @@ GenericTyVisitorCtx::process_type (ADTType &ty) first_type = first_lifetime + ty.get_used_arguments ().get_regions ().size (); for (auto ¶m : ty.get_substs ()) - param_names.push_back ( - param.get_generic_param ().get_type_representation ().as_string ()); + param_names.push_back (param.get_type_representation ().as_string ()); for (const auto &variant : ty.get_variants ()) { diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.h b/gcc/rust/typecheck/rust-tyty-variance-analysis.h index 9059a2f..282c6f3 100644 --- a/gcc/rust/typecheck/rust-tyty-variance-analysis.h +++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.h @@ -41,9 +41,10 @@ private: std::unique_ptr<GenericTyPerCrateCtx> private_ctx; }; -std::vector<size_t> -query_field_regions (const ADTType *parent, size_t variant_index, - size_t field_index, const FreeRegions &parent_regions); +std::vector<size_t> query_field_regions (const ADTType *parent, + size_t variant_index, + size_t field_index, + const FreeRegions &parent_regions); /** Variance semilattice */ class Variance diff --git a/gcc/rust/typecheck/rust-tyty-visitor.h b/gcc/rust/typecheck/rust-tyty-visitor.h index 4f8e7856..7783075 100644 --- a/gcc/rust/typecheck/rust-tyty-visitor.h +++ b/gcc/rust/typecheck/rust-tyty-visitor.h @@ -45,6 +45,7 @@ public: virtual void visit (ReferenceType &type) = 0; virtual void visit (PointerType &type) = 0; virtual void visit (ParamType &type) = 0; + virtual void visit (ConstType &type) = 0; virtual void visit (StrType &type) = 0; virtual void visit (NeverType &type) = 0; virtual void visit (PlaceholderType &type) = 0; @@ -75,6 +76,7 @@ public: virtual void visit (const ReferenceType &type) = 0; virtual void visit (const PointerType &type) = 0; virtual void visit (const ParamType &type) = 0; + virtual void visit (const ConstType &type) = 0; virtual void visit (const StrType &type) = 0; virtual void visit (const NeverType &type) = 0; virtual void visit (const PlaceholderType &type) = 0; diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index f0f4a07..db96773 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -19,6 +19,7 @@ #include "rust-tyty.h" #include "optional.h" +#include "rust-tyty-subst.h" #include "rust-tyty-visitor.h" #include "rust-hir-map.h" #include "rust-location.h" @@ -30,9 +31,14 @@ #include "rust-tyty-cmp.h" #include "rust-type-util.h" #include "rust-hir-type-bounds.h" +#include "print-tree.h" +#include "tree-pretty-print.h" #include "options.h" #include "rust-system.h" +#include "tree.h" +#include "fold-const.h" +#include <string> namespace Rust { namespace TyTy { @@ -114,6 +120,9 @@ TypeKindFormat::to_string (TypeKind kind) case TypeKind::OPAQUE: return "Opaque"; + case TypeKind::CONST: + return "Const"; + case TypeKind::ERROR: return "ERROR"; } @@ -223,6 +232,7 @@ BaseType::is_unit () const case OPAQUE: case STR: case DYNAMIC: + case CONST: case ERROR: return false; @@ -230,11 +240,13 @@ BaseType::is_unit () const case NEVER: return true; - case TUPLE: { + case TUPLE: + { return x->as<const TupleType> ()->num_fields () == 0; } - case ADT: { + case ADT: + { auto adt = x->as<const ADTType> (); if (adt->is_enum ()) return false; @@ -438,11 +450,10 @@ BaseType::inherit_bounds ( } } -const BaseType * -BaseType::get_root () const +BaseType * +BaseType::get_root () { - // FIXME this needs to be it its own visitor class with a vector adjustments - const TyTy::BaseType *root = this; + TyTy::BaseType *root = this; if (const auto r = root->try_as<const ReferenceType> ()) { @@ -546,17 +557,14 @@ BaseType::destructure () const { x = p->get (); } - // else if (auto p = x->try_as<const OpaqueType> ()) - // { - // auto pr = p->resolve (); - - // rust_debug ("XXXXXX") - - // if (pr == x) - // return pr; + else if (auto p = x->try_as<const OpaqueType> ()) + { + auto pr = p->resolve (); + if (pr == x) + return pr; - // x = pr; - // } + x = pr; + } else { return x; @@ -575,7 +583,7 @@ BaseType::monomorphized_clone () const { TyVar elm = arr->get_var_element_type ().monomorphized_clone (); return new ArrayType (arr->get_ref (), arr->get_ty_ref (), ident.locus, - arr->get_capacity_expr (), elm, + arr->get_capacity (), elm, arr->get_combined_refs ()); } else if (auto slice = x->try_as<const SliceType> ()) @@ -824,7 +832,8 @@ BaseType::is_concrete () const } else if (auto arr = x->try_as<const ArrayType> ()) { - return arr->get_element_type ()->is_concrete (); + return arr->get_element_type ()->is_concrete () + && arr->get_capacity ()->is_concrete (); } else if (auto slice = x->try_as<const SliceType> ()) { @@ -853,6 +862,10 @@ BaseType::is_concrete () const return false; return closure->get_result_type ().is_concrete (); } + else if (auto const_type = x->try_as<const ConstType> ()) + { + return const_type->get_value () != error_mark_node; + } else if (x->is<InferType> () || x->is<BoolType> () || x->is<CharType> () || x->is<IntType> () || x->is<UintType> () || x->is<FloatType> () || x->is<USizeType> () || x->is<ISizeType> () || x->is<NeverType> () @@ -891,31 +904,36 @@ BaseType::has_substitutions_defined () const case TUPLE: case PARAM: case PLACEHOLDER: + case CONST: case OPAQUE: return false; - case PROJECTION: { + case PROJECTION: + { const ProjectionType &p = *static_cast<const ProjectionType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (p); return ref.has_substitutions (); } break; - case FNDEF: { + case FNDEF: + { const FnType &fn = *static_cast<const FnType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (fn); return ref.has_substitutions (); } break; - case ADT: { + case ADT: + { const ADTType &adt = *static_cast<const ADTType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (adt); return ref.has_substitutions (); } break; - case CLOSURE: { + case CLOSURE: + { const ClosureType &closure = *static_cast<const ClosureType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (closure); @@ -953,31 +971,36 @@ BaseType::needs_generic_substitutions () const case TUPLE: case PARAM: case PLACEHOLDER: + case CONST: case OPAQUE: return false; - case PROJECTION: { + case PROJECTION: + { const ProjectionType &p = *static_cast<const ProjectionType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (p); return ref.needs_substitution (); } break; - case FNDEF: { + case FNDEF: + { const FnType &fn = *static_cast<const FnType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (fn); return ref.needs_substitution (); } break; - case ADT: { + case ADT: + { const ADTType &adt = *static_cast<const ADTType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (adt); return ref.needs_substitution (); } break; - case CLOSURE: { + case CLOSURE: + { const ClosureType &closure = *static_cast<const ClosureType *> (x); const SubstitutionRef &ref = static_cast<const SubstitutionRef &> (closure); @@ -996,28 +1019,32 @@ BaseType::get_subst_argument_mappings () const const TyTy::BaseType *x = destructure (); switch (x->get_kind ()) { - case PROJECTION: { + case PROJECTION: + { const auto &p = *static_cast<const ProjectionType *> (x); const auto &ref = static_cast<const SubstitutionRef &> (p); return ref.get_substitution_arguments (); } break; - case FNDEF: { + case FNDEF: + { const auto &fn = *static_cast<const FnType *> (x); const auto &ref = static_cast<const SubstitutionRef &> (fn); return ref.get_substitution_arguments (); } break; - case ADT: { + case ADT: + { const auto &adt = *static_cast<const ADTType *> (x); const auto &ref = static_cast<const SubstitutionRef &> (adt); return ref.get_substitution_arguments (); } break; - case CLOSURE: { + case CLOSURE: + { const auto &closure = *static_cast<const ClosureType *> (x); const auto &ref = static_cast<const SubstitutionRef &> (closure); return ref.get_substitution_arguments (); @@ -1140,13 +1167,15 @@ InferType::default_type (BaseType **type) const case GENERAL: return false; - case INTEGRAL: { + case INTEGRAL: + { ok = context->lookup_builtin ("i32", type); rust_assert (ok); return ok; } - case FLOAT: { + case FLOAT: + { ok = context->lookup_builtin ("f64", type); rust_assert (ok); return ok; @@ -1269,7 +1298,8 @@ InferType::apply_primitive_type_hint (const BaseType &hint) default_hint.kind = hint.get_kind (); break; - case INT: { + case INT: + { infer_kind = INTEGRAL; default_hint.kind = hint.get_kind (); default_hint.shint = TypeHint::SignedHint::SIGNED; @@ -1294,7 +1324,8 @@ InferType::apply_primitive_type_hint (const BaseType &hint) } break; - case UINT: { + case UINT: + { infer_kind = INTEGRAL; default_hint.kind = hint.get_kind (); default_hint.shint = TypeHint::SignedHint::UNSIGNED; @@ -1319,7 +1350,8 @@ InferType::apply_primitive_type_hint (const BaseType &hint) } break; - case TypeKind::FLOAT: { + case TypeKind::FLOAT: + { infer_kind = FLOAT; default_hint.shint = TypeHint::SignedHint::SIGNED; default_hint.kind = hint.get_kind (); @@ -1800,11 +1832,9 @@ ADTType::is_equal (const BaseType &other) const const SubstitutionParamMapping &a = substitutions.at (i); const SubstitutionParamMapping &b = other2->substitutions.at (i); - const ParamType *aa = a.get_param_ty (); - const ParamType *bb = b.get_param_ty (); - BaseType *aaa = aa->resolve (); - BaseType *bbb = bb->resolve (); - if (!aaa->is_equal (*bbb)) + const auto &aa = a.get_param_ty (); + const auto &bb = b.get_param_ty (); + if (!aa->is_equal (*bb)) return false; } } @@ -1992,7 +2022,7 @@ TupleType::get_name () const std::string fields_buffer; for (const TyVar &field : get_fields ()) { - fields_buffer += field.get_tyty ()->as_string (); + fields_buffer += field.get_tyty ()->get_name (); bool has_next = (i + 1) < get_fields ().size (); fields_buffer += has_next ? ", " : ""; i++; @@ -2129,9 +2159,8 @@ FnType::is_equal (const BaseType &other) const const SubstitutionParamMapping &a = get_substs ().at (i); const SubstitutionParamMapping &b = ofn.get_substs ().at (i); - const ParamType *pa = a.get_param_ty (); - const ParamType *pb = b.get_param_ty (); - + const auto *pa = a.get_param_ty (); + const auto *pb = b.get_param_ty (); if (!pa->is_equal (*pb)) return false; } @@ -2470,7 +2499,8 @@ ArrayType::accept_vis (TyConstVisitor &vis) const std::string ArrayType::as_string () const { - return "[" + get_element_type ()->as_string () + ":" + "CAPACITY" + "]"; + return "[" + get_element_type ()->as_string () + "; " + capacity->as_string () + + "]"; } bool @@ -2509,7 +2539,7 @@ ArrayType::get_var_element_type () const BaseType * ArrayType::clone () const { - return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity_expr, + return new ArrayType (get_ref (), get_ty_ref (), ident.locus, capacity, element_type, get_combined_refs ()); } @@ -2526,6 +2556,13 @@ ArrayType::handle_substitions (SubstitutionArgumentMappings &mappings) BaseType *concrete = Resolver::SubstMapperInternal::Resolve (base, mappings); ref->element_type = TyVar::subst_covariant_var (base, concrete); + // handle capacity type + auto cap = ref->get_capacity (); + BaseType *concrete_cap + = Resolver::SubstMapperInternal::Resolve (cap, mappings); + rust_assert (concrete_cap->get_kind () == TyTy::TypeKind::CONST); + ref->capacity = static_cast<TyTy::ConstType *> (concrete_cap); + return ref; } @@ -3382,33 +3419,26 @@ PointerType::handle_substitions (SubstitutionArgumentMappings &mappings) // PARAM Type ParamType::ParamType (std::string symbol, location_t locus, HirId ref, - HIR::GenericParam ¶m, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs) - : BaseType (ref, ref, KIND, - {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), - locus}, - specified_bounds, refs), - is_trait_self (false), symbol (symbol), param (param) + : BaseGeneric (ref, ref, KIND, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), + locus}, + specified_bounds, refs), + is_trait_self (false), symbol (symbol) {} ParamType::ParamType (bool is_trait_self, std::string symbol, location_t locus, - HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + HirId ref, HirId ty_ref, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs) - : BaseType (ref, ty_ref, KIND, - {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), - locus}, - specified_bounds, refs), - is_trait_self (is_trait_self), symbol (symbol), param (param) + : BaseGeneric (ref, ty_ref, KIND, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, symbol), + locus}, + specified_bounds, refs), + is_trait_self (is_trait_self), symbol (symbol) {} -HIR::GenericParam & -ParamType::get_generic_param () -{ - return param; -} - bool ParamType::can_resolve () const { @@ -3459,7 +3489,7 @@ BaseType * ParamType::clone () const { return new ParamType (is_trait_self, get_symbol (), ident.locus, get_ref (), - get_ty_ref (), param, get_specified_bounds (), + get_ty_ref (), get_specified_bounds (), get_combined_refs ()); } @@ -3529,12 +3559,12 @@ ParamType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) ParamType *p = static_cast<ParamType *> (clone ()); subst_mappings.on_param_subst (*p, arg); - // there are two cases one where we substitute directly to a new PARAM and - // otherwise - if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) + const BaseType *resolved = arg.get_tyty (); + if (resolved->get_kind () == TyTy::TypeKind::PARAM) { - p->set_ty_ref (arg.get_tyty ()->get_ref ()); - return p; + const ParamType &pp = *static_cast<const ParamType *> (resolved); + if (pp.can_resolve ()) + resolved = pp.resolve (); } // this is the new subst that this needs to pass @@ -3556,6 +3586,157 @@ ParamType::is_implicit_self_trait () const return is_trait_self; } +// ConstType + +ConstType::ConstType (ConstKind kind, std::string symbol, TyTy::BaseType *ty, + tree value, + std::vector<TypeBoundPredicate> specified_bounds, + location_t locus, HirId ref, HirId ty_ref, + std::set<HirId> refs) + : BaseGeneric (ref, ty_ref, KIND, + {Resolver::CanonicalPath::new_seg (UNKNOWN_NODEID, + symbol.empty () ? "<n/a>" + : symbol), + locus}, + specified_bounds, refs), + const_kind (kind), ty (ty), value (value), symbol (symbol) +{} + +void +ConstType::accept_vis (TyVisitor &vis) +{ + vis.visit (*this); +} + +void +ConstType::accept_vis (TyConstVisitor &vis) const +{ + vis.visit (*this); +} + +void +ConstType::set_value (tree v) +{ + value = v; + const_kind = ConstType::ConstKind::Value; +} + +std::string +ConstType::as_string () const +{ + return get_name (); +} + +bool +ConstType::can_eq (const BaseType *other, bool emit_errors) const +{ + ConstCmp r (this, emit_errors); + return r.can_eq (other); +} + +BaseType * +ConstType::clone () const +{ + return new ConstType (const_kind, symbol, ty, value, get_specified_bounds (), + ident.locus, ref, ty_ref, get_combined_refs ()); +} + +std::string +ConstType::get_symbol () const +{ + return symbol; +} + +bool +ConstType::can_resolve () const +{ + return false; +} + +BaseType * +ConstType::resolve () const +{ + rust_unreachable (); + return nullptr; +} + +static std::string +generate_tree_str (tree value) +{ + char *buf = nullptr; + size_t size = 0; + + FILE *stream = open_memstream (&buf, &size); + if (!stream) + return "<error>"; + + print_generic_stmt (stream, value, TDF_NONE); + fclose (stream); + + std::string result = (buf ? std::string (buf, size) : "<error>"); + free (buf); + + if (!result.empty () && result.back () == '\n') + result.pop_back (); + + return result; +} + +std::string +ConstType::get_name () const +{ + if (value == error_mark_node) + { + switch (get_const_kind ()) + { + case Rust::TyTy::ConstType::Decl: + return "ConstType:<" + get_ty ()->get_name () + " " + get_symbol () + + ">"; + + case Rust::TyTy::ConstType::Infer: + return "ConstType:<" + get_ty ()->get_name () + " ?" + ">"; + + default: + return "ConstType:<" + get_ty ()->get_name () + " - <error>" + ">"; + } + } + + return generate_tree_str (value); +} + +bool +ConstType::is_equal (const BaseType &other) const +{ + if (get_kind () != other.get_kind ()) + { + return false; + } + + const ConstType &rhs = static_cast<const ConstType &> (other); + if (!get_ty ()->is_equal (*rhs.get_ty ())) + return false; + + tree lv = get_value (); + tree rv = rhs.get_value (); + + return operand_equal_p (lv, rv, 0); +} + +ConstType * +ConstType::handle_substitions (SubstitutionArgumentMappings &mappings) +{ + SubstitutionArg arg = SubstitutionArg::error (); + bool found = mappings.get_argument_for_symbol (this, &arg); + if (found && !arg.is_error ()) + { + TyTy::BaseType *subst = arg.get_tyty (); + rust_assert (subst->is<TyTy::ConstType> ()); + return static_cast<TyTy::ConstType *> (subst); + } + + return this; +} + // OpaqueType OpaqueType::OpaqueType (location_t locus, HirId ref, @@ -3624,28 +3805,7 @@ BaseType * OpaqueType::resolve () const { TyVar var (get_ty_ref ()); - BaseType *r = var.get_tyty (); - - while (r->get_kind () == TypeKind::OPAQUE) - { - OpaqueType *rr = static_cast<OpaqueType *> (r); - if (!rr->can_resolve ()) - break; - - TyVar v (rr->get_ty_ref ()); - BaseType *n = v.get_tyty (); - - // fix infinite loop - if (r == n) - break; - - r = n; - } - - if (r->get_kind () == TypeKind::OPAQUE && (r->get_ref () == r->get_ty_ref ())) - return TyVar (r->get_ty_ref ()).get_tyty (); - - return r; + return var.get_tyty (); } bool @@ -3655,41 +3815,9 @@ OpaqueType::is_equal (const BaseType &other) const if (can_resolve () != other2.can_resolve ()) return false; - if (can_resolve ()) - return resolve ()->can_eq (other2.resolve (), false); - return bounds_compatible (other, UNDEF_LOCATION, false); } -OpaqueType * -OpaqueType::handle_substitions (SubstitutionArgumentMappings &subst_mappings) -{ - // SubstitutionArg arg = SubstitutionArg::error (); - // bool ok = subst_mappings.get_argument_for_symbol (this, &arg); - // if (!ok || arg.is_error ()) - // return this; - - // OpaqueType *p = static_cast<OpaqueType *> (clone ()); - // subst_mappings.on_param_subst (*p, arg); - - // // there are two cases one where we substitute directly to a new PARAM and - // // otherwise - // if (arg.get_tyty ()->get_kind () == TyTy::TypeKind::PARAM) - // { - // p->set_ty_ref (arg.get_tyty ()->get_ref ()); - // return p; - // } - - // // this is the new subst that this needs to pass - // p->set_ref (mappings.get_next_hir_id ()); - // p->set_ty_ref (arg.get_tyty ()->get_ref ()); - - // return p; - - rust_unreachable (); - return nullptr; -} - // StrType StrType::StrType (HirId ref, std::set<HirId> refs) diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 1cada9a..49415ea 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -19,6 +19,7 @@ #ifndef RUST_TYTY #define RUST_TYTY +#include "optional.h" #include "rust-hir-map.h" #include "rust-common.h" #include "rust-identifier.h" @@ -29,6 +30,7 @@ #include "rust-tyty-region.h" #include "rust-system.h" #include "rust-hir.h" +#include "tree.h" namespace Rust { @@ -56,6 +58,7 @@ enum TypeKind REF, POINTER, PARAM, + CONST, ARRAY, SLICE, FNDEF, @@ -78,8 +81,7 @@ enum TypeKind ERROR }; -extern bool -is_primitive_type_kind (TypeKind kind); +extern bool is_primitive_type_kind (TypeKind kind); class TypeKindFormat { @@ -165,8 +167,7 @@ public: void debug () const; - // FIXME this will eventually go away - const BaseType *get_root () const; + BaseType *get_root (); // This will get the monomorphized type from Params, Placeholders or // Projections if available or error @@ -268,8 +269,8 @@ public: {} WARN_UNUSED_RESULT virtual size_t get_num_params () const = 0; - WARN_UNUSED_RESULT virtual BaseType * - get_param_type_at (size_t index) const = 0; + WARN_UNUSED_RESULT virtual BaseType *get_param_type_at (size_t index) const + = 0; WARN_UNUSED_RESULT virtual BaseType *get_return_type () const = 0; }; @@ -365,18 +366,34 @@ public: std::string get_name () const override final; }; -class ParamType : public BaseType +class BaseGeneric : public BaseType +{ +public: + virtual std::string get_symbol () const = 0; + + virtual bool can_resolve () const = 0; + + virtual BaseType *resolve () const = 0; + +protected: + BaseGeneric (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, + std::vector<TypeBoundPredicate> specified_bounds, + std::set<HirId> refs = std::set<HirId> ()) + : BaseType (ref, ty_ref, kind, ident, specified_bounds, refs) + {} +}; + +class ParamType : public BaseGeneric { public: static constexpr auto KIND = TypeKind::PARAM; ParamType (std::string symbol, location_t locus, HirId ref, - HIR::GenericParam ¶m, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs = std::set<HirId> ()); ParamType (bool is_trait_self, std::string symbol, location_t locus, - HirId ref, HirId ty_ref, HIR::GenericParam ¶m, + HirId ref, HirId ty_ref, std::vector<TypeBoundPredicate> specified_bounds, std::set<HirId> refs = std::set<HirId> ()); @@ -389,13 +406,11 @@ public: BaseType *clone () const final override; - std::string get_symbol () const; - - HIR::GenericParam &get_generic_param (); + std::string get_symbol () const override final; - bool can_resolve () const; + bool can_resolve () const override final; - BaseType *resolve () const; + BaseType *resolve () const override final; std::string get_name () const override final; @@ -409,7 +424,58 @@ public: private: bool is_trait_self; std::string symbol; - HIR::GenericParam ¶m; +}; + +class ConstType : public BaseGeneric +{ +public: + static constexpr auto KIND = TypeKind::CONST; + + enum ConstKind + { + Decl, + Value, + Infer, + Error + }; + + ConstType (ConstKind kind, std::string symbol, TyTy::BaseType *ty, tree value, + std::vector<TypeBoundPredicate> specified_bounds, location_t locus, + HirId ref, HirId ty_ref, + std::set<HirId> refs = std::set<HirId> ()); + + void accept_vis (TyVisitor &vis) override; + void accept_vis (TyConstVisitor &vis) const override; + + ConstKind get_const_kind () const { return const_kind; } + TyTy::BaseType *get_ty () const { return ty; } + tree get_value () const { return value; } + + void set_value (tree value); + + std::string as_string () const override; + + bool can_eq (const BaseType *other, bool emit_errors) const override final; + + BaseType *clone () const final override; + + std::string get_symbol () const override final; + + bool can_resolve () const override final; + + BaseType *resolve () const override final; + + std::string get_name () const override final; + + bool is_equal (const BaseType &other) const override; + + ConstType *handle_substitions (SubstitutionArgumentMappings &mappings); + +private: + ConstKind const_kind; + TyTy::BaseType *ty; + tree value; + std::string symbol; }; class OpaqueType : public BaseType @@ -441,8 +507,6 @@ public: std::string get_name () const override final; bool is_equal (const BaseType &other) const override; - - OpaqueType *handle_substitions (SubstitutionArgumentMappings &mappings); }; class StructFieldType @@ -541,14 +605,15 @@ public: std::string get_name () const; - // check that this predicate is object-safe see: + // check that this is object-safe see: // https://doc.rust-lang.org/reference/items/traits.html#object-safety bool is_object_safe (bool emit_error, location_t locus) const; void apply_generic_arguments (HIR::GenericArgs *generic_args, - bool has_associated_self); + bool has_associated_self, bool is_super_trait); - void apply_argument_mappings (SubstitutionArgumentMappings &arguments); + void apply_argument_mappings (SubstitutionArgumentMappings &arguments, + bool is_super_trait); bool contains_item (const std::string &search) const; @@ -596,6 +661,9 @@ private: TypeBoundPredicate (mark_is_error); + void get_trait_hierachy ( + std::function<void (const Resolver::TraitReference &)> callback) const; + DefId reference; location_t locus; bool error_flag; @@ -1156,19 +1224,18 @@ class ArrayType : public BaseType public: static constexpr auto KIND = TypeKind::ARRAY; - ArrayType (HirId ref, location_t locus, HIR::Expr &capacity_expr, TyVar base, + ArrayType (HirId ref, location_t locus, ConstType *capacity, TyVar base, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), - element_type (base), capacity_expr (capacity_expr) + element_type (base), capacity (capacity) {} - ArrayType (HirId ref, HirId ty_ref, location_t locus, - HIR::Expr &capacity_expr, TyVar base, - std::set<HirId> refs = std::set<HirId> ()) + ArrayType (HirId ref, HirId ty_ref, location_t locus, ConstType *capacity, + TyVar base, std::set<HirId> refs = std::set<HirId> ()) : BaseType (ref, ty_ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), - element_type (base), capacity_expr (capacity_expr) + element_type (base), capacity (capacity) {} void accept_vis (TyVisitor &vis) override; @@ -1187,15 +1254,13 @@ public: BaseType *clone () const final override; - HIR::Expr &get_capacity_expr () const { return capacity_expr; } + ConstType *get_capacity () const { return capacity; } ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; - // FIXME: I dont think this should be in tyty - tyty should already be const - // evaluated - HIR::Expr &capacity_expr; + ConstType *capacity; }; class SliceType : public BaseType diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 294b677..30ead5b 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -17,6 +17,9 @@ // <http://www.gnu.org/licenses/>. #include "rust-unify.h" +#include "fold-const.h" +#include "rust-tyty.h" +#include "tree.h" namespace Rust { namespace Resolver { @@ -53,6 +56,22 @@ UnifyRules::Resolve (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, } TyTy::BaseType * +UnifyRules::resolve_subtype (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs) +{ + TyTy::BaseType *result + = UnifyRules::Resolve (lhs, rhs, locus, commit_flag, emit_error, infer_flag, + commits, infers); + + // If the recursive call resulted in an error and would have emitted an error + // message, disable error emission for the current level to avoid duplicate + // errors + if (result->get_kind () == TyTy::TypeKind::ERROR && emit_error) + emit_error = false; + + return result; +} + +TyTy::BaseType * UnifyRules::get_base () { return lhs.get_ty ()->destructure (); @@ -69,7 +88,6 @@ UnifyRules::commit (TyTy::BaseType *base, TyTy::BaseType *other, TyTy::BaseType *resolved) { TypeCheckContext &context = *TypeCheckContext::get (); - Analysis::Mappings &mappings = Analysis::Mappings::get (); TyTy::BaseType *b = base->destructure (); TyTy::BaseType *o = other->destructure (); @@ -102,13 +120,8 @@ UnifyRules::commit (TyTy::BaseType *base, TyTy::BaseType *other, continue; // if any of the types are inference variables lets fix them - if (ref_tyty->get_kind () == TyTy::TypeKind::INFER) - { - auto node = Analysis::NodeMapping (mappings.get_current_crate (), - UNKNOWN_NODEID, ref, - UNKNOWN_LOCAL_DEFID); - context.insert_type (node, resolved->clone ()); - } + if (ref_tyty->is<TyTy::InferType> ()) + context.insert_implicit_type (ref, resolved); } } } @@ -315,6 +328,9 @@ UnifyRules::go () case TyTy::OPAQUE: return expect_opaque (static_cast<TyTy::OpaqueType *> (ltype), rtype); + case TyTy::CONST: + return expect_const (static_cast<TyTy::ConstType *> (ltype), rtype); + case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -328,30 +344,33 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); switch (ltype->get_infer_kind ()) { case TyTy::InferType::InferTypeKind::GENERAL: return rtype->clone (); - case TyTy::InferType::InferTypeKind::INTEGRAL: { + case TyTy::InferType::InferTypeKind::INTEGRAL: + { bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::INTEGRAL || r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; if (is_valid) - return rtype->clone (); + return rtype; } break; - case TyTy::InferType::InferTypeKind::FLOAT: { + case TyTy::InferType::InferTypeKind::FLOAT: + { bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::FLOAT || r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; if (is_valid) - return rtype->clone (); + return rtype; } break; } @@ -361,7 +380,8 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, case TyTy::INT: case TyTy::UINT: case TyTy::USIZE: - case TyTy::ISIZE: { + case TyTy::ISIZE: + { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) || (ltype->get_infer_kind () @@ -369,12 +389,13 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, if (is_valid) { ltype->apply_primitive_type_hint (*rtype); - return rtype->clone (); + return rtype; } } break; - case TyTy::FLOAT: { + case TyTy::FLOAT: + { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL) || (ltype->get_infer_kind () @@ -382,7 +403,7 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, if (is_valid) { ltype->apply_primitive_type_hint (*rtype); - return rtype->clone (); + return rtype; } } break; @@ -404,7 +425,9 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: - case TyTy::OPAQUE: { + case TyTy::CONST: + case TyTy::OPAQUE: + { bool is_valid = (ltype->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL); if (is_valid) @@ -424,7 +447,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -433,7 +457,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::ADT: { + case TyTy::ADT: + { TyTy::ADTType &type = *static_cast<TyTy::ADTType *> (rtype); if (ltype->get_adt_kind () != type.get_adt_kind ()) { @@ -469,11 +494,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *other_field_ty = other_field->get_field_type (); TyTy::BaseType *unified_ty - = UnifyRules::Resolve (TyTy::TyWithLocation (this_field_ty), - TyTy::TyWithLocation (other_field_ty), - locus, commit_flag, - false /* emit_error */, infer_flag, - commits, infers); + = resolve_subtype (TyTy::TyWithLocation (this_field_ty), + TyTy::TyWithLocation (other_field_ty)); if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -495,11 +517,8 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) auto pa = a.get_param_ty (); auto pb = b.get_param_ty (); - auto res - = UnifyRules::Resolve (TyTy::TyWithLocation (pa), - TyTy::TyWithLocation (pb), locus, - commit_flag, false /* emit_error */, - infer_flag, commits, infers); + auto res = resolve_subtype (TyTy::TyWithLocation (pa), + TyTy::TyWithLocation (pb)); if (res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -533,6 +552,7 @@ UnifyRules::expect_adt (TyTy::ADTType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -544,7 +564,8 @@ UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -578,6 +599,7 @@ UnifyRules::expect_str (TyTy::StrType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -589,7 +611,8 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -598,16 +621,15 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::REF: { + case TyTy::REF: + { TyTy::ReferenceType &type = *static_cast<TyTy::ReferenceType *> (rtype); auto base_type = ltype->get_base (); auto other_base_type = type.get_base (); TyTy::BaseType *base_resolved - = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), - TyTy::TyWithLocation (other_base_type), locus, - commit_flag, false /* emit_error */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (base_type), + TyTy::TyWithLocation (other_base_type)); if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -649,6 +671,7 @@ UnifyRules::expect_reference (TyTy::ReferenceType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -660,7 +683,8 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -669,16 +693,15 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::POINTER: { + case TyTy::POINTER: + { TyTy::PointerType &type = *static_cast<TyTy::PointerType *> (rtype); auto base_type = ltype->get_base (); auto other_base_type = type.get_base (); TyTy::BaseType *base_resolved - = UnifyRules::Resolve (TyTy::TyWithLocation (base_type), - TyTy::TyWithLocation (other_base_type), locus, - commit_flag, false /* emit_error */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (base_type), + TyTy::TyWithLocation (other_base_type)); if (base_resolved->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -720,6 +743,7 @@ UnifyRules::expect_pointer (TyTy::PointerType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -731,7 +755,8 @@ UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -740,7 +765,8 @@ UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::PARAM: { + case TyTy::PARAM: + { TyTy::ParamType &type = *static_cast<TyTy::ParamType *> (rtype); // bool symbol_matches // = ltype->get_symbol ().compare (type.get_symbol ()) == 0; @@ -782,6 +808,7 @@ UnifyRules::expect_param (TyTy::ParamType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -793,7 +820,8 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -802,21 +830,32 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::ARRAY: { + case TyTy::ARRAY: + { TyTy::ArrayType &type = *static_cast<TyTy::ArrayType *> (rtype); - TyTy::BaseType *element_unify = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_element_type ()), - TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, - false /* emit_error*/, infer_flag, commits, infers); - - if (element_unify->get_kind () != TyTy::TypeKind::ERROR) - { - return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, - type.get_capacity_expr (), - TyTy::TyVar ( - element_unify->get_ref ())); - } + TyTy::BaseType *element_unify + = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()), + TyTy::TyWithLocation (type.get_element_type ())); + + if (element_unify->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + + bool save_emit_error = emit_error; + emit_error = false; + TyTy::BaseType *capacity_unify + = resolve_subtype (TyTy::TyWithLocation (ltype->get_capacity ()), + TyTy::TyWithLocation (type.get_capacity ())); + emit_error = save_emit_error; + + if (capacity_unify->get_kind () != TyTy::TypeKind::CONST) + return new TyTy::ErrorType (0); + + TyTy::ConstType *capacity_type_unify + = static_cast<TyTy::ConstType *> (capacity_unify); + return new TyTy::ArrayType (type.get_ref (), type.get_ty_ref (), + type.get_ident ().locus, + capacity_type_unify, + TyTy::TyVar (element_unify->get_ref ())); } break; @@ -842,6 +881,7 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -853,7 +893,8 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -862,12 +903,12 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::SLICE: { + case TyTy::SLICE: + { TyTy::SliceType &type = *static_cast<TyTy::SliceType *> (rtype); - TyTy::BaseType *element_unify = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_element_type ()), - TyTy::TyWithLocation (type.get_element_type ()), locus, commit_flag, - false /* emit_error*/, infer_flag, commits, infers); + TyTy::BaseType *element_unify + = resolve_subtype (TyTy::TyWithLocation (ltype->get_element_type ()), + TyTy::TyWithLocation (type.get_element_type ())); if (element_unify->get_kind () != TyTy::TypeKind::ERROR) { @@ -901,6 +942,7 @@ UnifyRules::expect_slice (TyTy::SliceType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -912,7 +954,8 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -921,7 +964,8 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FNDEF: { + case TyTy::FNDEF: + { TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype); if (ltype->num_params () != type.num_params ()) { @@ -933,21 +977,17 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) auto a = ltype->param_at (i).get_type (); auto b = type.param_at (i).get_type (); - auto unified_param - = UnifyRules::Resolve (TyTy::TyWithLocation (a), - TyTy::TyWithLocation (b), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + auto unified_param = resolve_subtype (TyTy::TyWithLocation (a), + TyTy::TyWithLocation (b)); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } } - auto unified_return = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_return_type ()), - TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag, - false /* emit_errors */, infer_flag, commits, infers); + auto unified_return + = resolve_subtype (TyTy::TyWithLocation (ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ())); if (unified_return->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -992,6 +1032,7 @@ UnifyRules::expect_fndef (TyTy::FnType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1003,7 +1044,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1012,7 +1054,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FNPTR: { + case TyTy::FNPTR: + { TyTy::FnPtr &type = *static_cast<TyTy::FnPtr *> (rtype); if (ltype->num_params () != type.num_params ()) { @@ -1024,21 +1067,17 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto a = ltype->get_param_type_at (i); auto b = type.get_param_type_at (i); - auto unified_param - = UnifyRules::Resolve (TyTy::TyWithLocation (a), - TyTy::TyWithLocation (b), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + auto unified_param = resolve_subtype (TyTy::TyWithLocation (a), + TyTy::TyWithLocation (b)); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } } - auto unified_return = UnifyRules::Resolve ( - TyTy::TyWithLocation (ltype->get_return_type ()), - TyTy::TyWithLocation (type.get_return_type ()), locus, commit_flag, - false /* emit_errors */, infer_flag, commits, infers); + auto unified_return + = resolve_subtype (TyTy::TyWithLocation (ltype->get_return_type ()), + TyTy::TyWithLocation (type.get_return_type ())); if (unified_return->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1048,16 +1087,15 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FNDEF: { + case TyTy::FNDEF: + { TyTy::FnType &type = *static_cast<TyTy::FnType *> (rtype); auto this_ret_type = ltype->get_return_type (); auto other_ret_type = type.get_return_type (); auto unified_result - = UnifyRules::Resolve (TyTy::TyWithLocation (this_ret_type), - TyTy::TyWithLocation (other_ret_type), locus, - commit_flag, false /*emit_errors*/, infer_flag, - commits, infers); + = resolve_subtype (TyTy::TyWithLocation (this_ret_type), + TyTy::TyWithLocation (other_ret_type)); if (unified_result->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1074,10 +1112,45 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) auto other_param = type.param_at (i).get_type (); auto unified_param - = UnifyRules::Resolve (TyTy::TyWithLocation (this_param), - TyTy::TyWithLocation (other_param), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (this_param), + TyTy::TyWithLocation (other_param)); + if (unified_param->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + } + + return ltype->clone (); + } + break; + + case TyTy::CLOSURE: + { + TyTy::ClosureType &type = *static_cast<TyTy::ClosureType *> (rtype); + auto this_ret_type = ltype->get_return_type (); + auto other_ret_type = type.get_return_type (); + + auto unified_result + = resolve_subtype (TyTy::TyWithLocation (this_ret_type), + TyTy::TyWithLocation (other_ret_type)); + if (unified_result->get_kind () == TyTy::TypeKind::ERROR) + { + return new TyTy::ErrorType (0); + } + + if (ltype->num_params () != type.get_num_params ()) + { + return new TyTy::ErrorType (0); + } + + for (size_t i = 0; i < ltype->num_params (); i++) + { + auto this_param = ltype->get_param_type_at (i); + auto other_param = type.get_param_type_at (i); + + auto unified_param + = resolve_subtype (TyTy::TyWithLocation (this_param), + TyTy::TyWithLocation (other_param)); if (unified_param->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1107,8 +1180,8 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) case TyTy::PLACEHOLDER: case TyTy::PROJECTION: case TyTy::DYNAMIC: - case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1120,7 +1193,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1129,7 +1203,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::TUPLE: { + case TyTy::TUPLE: + { TyTy::TupleType &type = *static_cast<TyTy::TupleType *> (rtype); if (ltype->num_fields () != type.num_fields ()) { @@ -1143,10 +1218,8 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) TyTy::BaseType *fo = type.get_field (i); TyTy::BaseType *unified_ty - = UnifyRules::Resolve (TyTy::TyWithLocation (bo), - TyTy::TyWithLocation (fo), locus, - commit_flag, false /* emit_errors */, - infer_flag, commits, infers); + = resolve_subtype (TyTy::TyWithLocation (bo), + TyTy::TyWithLocation (fo)); if (unified_ty->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (0); @@ -1180,6 +1253,7 @@ UnifyRules::expect_tuple (TyTy::TupleType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1191,7 +1265,8 @@ UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1228,6 +1303,7 @@ UnifyRules::expect_bool (TyTy::BoolType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1239,7 +1315,8 @@ UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1276,6 +1353,7 @@ UnifyRules::expect_char (TyTy::CharType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1287,7 +1365,8 @@ UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL @@ -1300,7 +1379,8 @@ UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::INT: { + case TyTy::INT: + { TyTy::IntType &type = *static_cast<TyTy::IntType *> (rtype); bool is_valid = ltype->get_int_kind () == type.get_int_kind (); if (is_valid) @@ -1331,6 +1411,7 @@ UnifyRules::expect_int (TyTy::IntType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1342,7 +1423,8 @@ UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL @@ -1355,7 +1437,8 @@ UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::UINT: { + case TyTy::UINT: + { TyTy::UintType &type = *static_cast<TyTy::UintType *> (rtype); bool is_valid = ltype->get_uint_kind () == type.get_uint_kind (); if (is_valid) @@ -1386,6 +1469,7 @@ UnifyRules::expect_uint (TyTy::UintType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1397,7 +1481,8 @@ UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL @@ -1410,7 +1495,8 @@ UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::FLOAT: { + case TyTy::FLOAT: + { TyTy::FloatType &type = *static_cast<TyTy::FloatType *> (rtype); bool is_valid = ltype->get_float_kind () == type.get_float_kind (); if (is_valid) @@ -1441,6 +1527,7 @@ UnifyRules::expect_float (TyTy::FloatType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1452,7 +1539,8 @@ UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT; @@ -1489,6 +1577,7 @@ UnifyRules::expect_isize (TyTy::ISizeType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1500,7 +1589,8 @@ UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () != TyTy::InferType::InferTypeKind::FLOAT; @@ -1537,6 +1627,7 @@ UnifyRules::expect_usize (TyTy::USizeType *ltype, TyTy::BaseType *rtype) case TyTy::DYNAMIC: case TyTy::CLOSURE: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1548,7 +1639,8 @@ UnifyRules::expect_never (TyTy::NeverType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1569,7 +1661,8 @@ UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype, { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1607,6 +1700,7 @@ UnifyRules::expect_placeholder (TyTy::PlaceholderType *ltype, return rtype->clone (); gcc_fallthrough (); + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1619,7 +1713,8 @@ UnifyRules::expect_projection (TyTy::ProjectionType *ltype, { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1655,6 +1750,7 @@ UnifyRules::expect_projection (TyTy::ProjectionType *ltype, case TyTy::NEVER: case TyTy::PLACEHOLDER: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1666,7 +1762,8 @@ UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1675,7 +1772,8 @@ UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::DYNAMIC: { + case TyTy::DYNAMIC: + { TyTy::DynamicObjectType &type = *static_cast<TyTy::DynamicObjectType *> (rtype); if (ltype->num_specified_bounds () != type.num_specified_bounds ()) @@ -1714,6 +1812,7 @@ UnifyRules::expect_dyn (TyTy::DynamicObjectType *ltype, TyTy::BaseType *rtype) case TyTy::PLACEHOLDER: case TyTy::PROJECTION: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1725,7 +1824,8 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) { switch (rtype->get_kind ()) { - case TyTy::INFER: { + case TyTy::INFER: + { TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); bool is_valid = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; @@ -1734,26 +1834,25 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) } break; - case TyTy::CLOSURE: { + case TyTy::CLOSURE: + { TyTy::ClosureType &type = *static_cast<TyTy::ClosureType *> (rtype); if (ltype->get_def_id () != type.get_def_id ()) { return new TyTy::ErrorType (0); } - TyTy::BaseType *args_res = UnifyRules::Resolve ( - TyTy::TyWithLocation (<ype->get_parameters ()), - TyTy::TyWithLocation (&type.get_parameters ()), locus, commit_flag, - false /* emit_error */, infer_flag, commits, infers); + TyTy::BaseType *args_res + = resolve_subtype (TyTy::TyWithLocation (<ype->get_parameters ()), + TyTy::TyWithLocation (&type.get_parameters ())); if (args_res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); } - TyTy::BaseType *res = UnifyRules::Resolve ( - TyTy::TyWithLocation (<ype->get_result_type ()), - TyTy::TyWithLocation (&type.get_result_type ()), locus, commit_flag, - false /* emit_error */, infer_flag, commits, infers); + TyTy::BaseType *res + = resolve_subtype (TyTy::TyWithLocation (<ype->get_result_type ()), + TyTy::TyWithLocation (&type.get_result_type ())); if (res == nullptr || res->get_kind () == TyTy::TypeKind::ERROR) { return new TyTy::ErrorType (0); @@ -1785,6 +1884,7 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::OPAQUE: + case TyTy::CONST: case TyTy::ERROR: return new TyTy::ErrorType (0); } @@ -1794,58 +1894,113 @@ UnifyRules::expect_closure (TyTy::ClosureType *ltype, TyTy::BaseType *rtype) TyTy::BaseType * UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, TyTy::BaseType *rtype) { - switch (rtype->get_kind ()) + if (rtype->is<TyTy::OpaqueType> ()) { - case TyTy::INFER: { - TyTy::InferType *r = static_cast<TyTy::InferType *> (rtype); - bool is_valid - = r->get_infer_kind () == TyTy::InferType::InferTypeKind::GENERAL; - if (is_valid) - return ltype->clone (); - } - break; + TyTy::OpaqueType *ro = rtype->as<TyTy::OpaqueType> (); + if (!ltype->is_equal (*ro)) + return new TyTy::ErrorType (0); - case TyTy::OPAQUE: { - auto &type = *static_cast<TyTy::OpaqueType *> (rtype); - if (ltype->num_specified_bounds () != type.num_specified_bounds ()) - { - return new TyTy::ErrorType (0); - } + if (ltype->can_resolve () && ro->can_resolve ()) + { + auto lr = ltype->resolve (); + auto rr = ro->resolve (); - if (!ltype->bounds_compatible (type, locus, true)) - { + auto res = resolve_subtype (TyTy::TyWithLocation (lr), + TyTy::TyWithLocation (rr)); + if (res->get_kind () == TyTy::TypeKind::ERROR) return new TyTy::ErrorType (0); - } + } + else if (ltype->can_resolve ()) + { + auto lr = ltype->resolve (); + ro->set_ty_ref (lr->get_ref ()); + } + else if (ro->can_resolve ()) + { + auto rr = ro->resolve (); + ltype->set_ty_ref (rr->get_ref ()); + } + } + else if (ltype->can_resolve ()) + { + auto underly = ltype->resolve (); + auto res = resolve_subtype (TyTy::TyWithLocation (underly), + TyTy::TyWithLocation (rtype)); + if (res->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + } + else + { + ltype->set_ty_ref (rtype->get_ref ()); + } - return ltype->clone (); - } - break; + return ltype; +} + +TyTy::BaseType * +UnifyRules::expect_const (TyTy::ConstType *ltype, TyTy::BaseType *rtype) +{ + if (rtype->get_kind () != TyTy::TypeKind::CONST) + return new TyTy::ErrorType (0); + + TyTy::ConstType &lhs = *ltype; + TyTy::ConstType &rhs = *static_cast<TyTy::ConstType *> (rtype); + + auto res = resolve_subtype (TyTy::TyWithLocation (lhs.get_ty ()), + TyTy::TyWithLocation (rhs.get_ty ())); + if (res->get_kind () == TyTy::TypeKind::ERROR) + return new TyTy::ErrorType (0); + + tree lv = lhs.get_value (); + tree rv = rhs.get_value (); + + if (error_operand_p (lv) && error_operand_p (rv)) + { + // this is only allowed for some silly senarios like: + // gcc/testsuite/rust/compile/issue-const_generics_5.rs + if (lhs.get_const_kind () == rhs.get_const_kind ()) + { + return new TyTy::ConstType (lhs.get_const_kind (), lhs.get_symbol (), + res, error_mark_node, + lhs.get_specified_bounds (), + lhs.get_locus (), lhs.get_ref (), + lhs.get_ty_ref (), + lhs.get_combined_refs ()); + } - case TyTy::CLOSURE: - case TyTy::SLICE: - case TyTy::PARAM: - case TyTy::POINTER: - case TyTy::STR: - case TyTy::ADT: - case TyTy::REF: - case TyTy::ARRAY: - case TyTy::FNDEF: - case TyTy::FNPTR: - case TyTy::TUPLE: - case TyTy::BOOL: - case TyTy::CHAR: - case TyTy::INT: - case TyTy::UINT: - case TyTy::FLOAT: - case TyTy::USIZE: - case TyTy::ISIZE: - case TyTy::NEVER: - case TyTy::PLACEHOLDER: - case TyTy::PROJECTION: - case TyTy::DYNAMIC: - case TyTy::ERROR: return new TyTy::ErrorType (0); } + + bool equal = operand_equal_p (lv, rv, 0); + if (equal) + { + return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + lhs.get_symbol (), res, lv, + lhs.get_specified_bounds (), lhs.get_locus (), + lhs.get_ref (), lhs.get_ty_ref (), + lhs.get_combined_refs ()); + } + + if (lhs.get_const_kind () == TyTy::ConstType::Infer && !error_operand_p (rv)) + { + lhs.set_value (rv); + return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + lhs.get_symbol (), res, rv, + lhs.get_specified_bounds (), lhs.get_locus (), + lhs.get_ref (), lhs.get_ty_ref (), + lhs.get_combined_refs ()); + } + else if (rhs.get_const_kind () == TyTy::ConstType::Infer + && !error_operand_p (lv)) + { + rhs.set_value (lv); + return new TyTy::ConstType (TyTy::ConstType::ConstKind::Value, + rhs.get_symbol (), res, lv, + rhs.get_specified_bounds (), rhs.get_locus (), + rhs.get_ref (), rhs.get_ty_ref (), + rhs.get_combined_refs ()); + } + return new TyTy::ErrorType (0); } diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h index 5ff3b7c..b8c9cbc 100644 --- a/gcc/rust/typecheck/rust-unify.h +++ b/gcc/rust/typecheck/rust-unify.h @@ -84,6 +84,7 @@ protected: TyTy::BaseType *rtype); TyTy::BaseType *expect_opaque (TyTy::OpaqueType *ltype, TyTy::BaseType *rtype); + TyTy::BaseType *expect_const (TyTy::ConstType *ltype, TyTy::BaseType *rtype); private: UnifyRules (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs, @@ -91,6 +92,9 @@ private: std::vector<CommitSite> &commits, std::vector<InferenceSite> &infers); + TyTy::BaseType *resolve_subtype (TyTy::TyWithLocation lhs, + TyTy::TyWithLocation rhs); + void emit_type_mismatch () const; void emit_abi_mismatch (const TyTy::FnType &expected, const TyTy::FnType &got) const; diff --git a/gcc/rust/util/optional.h b/gcc/rust/util/optional.h index 2c59459..9d2cd97 100644 --- a/gcc/rust/util/optional.h +++ b/gcc/rust/util/optional.h @@ -1364,7 +1364,7 @@ public: this->m_has_value = false; } } -}; // namespace tl +}; /// Compares two optional objects template <class T, class U> @@ -2110,7 +2110,7 @@ public: private: T *m_value; -}; // namespace tl +}; @@ -2128,4 +2128,4 @@ template <class T> struct hash<tl::optional<T>> { }; } // namespace std -#endif
\ No newline at end of file +#endif diff --git a/gcc/rust/util/rust-abi.h b/gcc/rust/util/rust-abi.h index a0180ed..357a5db 100644 --- a/gcc/rust/util/rust-abi.h +++ b/gcc/rust/util/rust-abi.h @@ -34,11 +34,9 @@ enum ABI SYSV64 }; -extern Rust::ABI -get_abi_from_string (const std::string &abi); +extern Rust::ABI get_abi_from_string (const std::string &abi); -extern std::string -get_string_from_abi (Rust::ABI abi); +extern std::string get_string_from_abi (Rust::ABI abi); } // namespace Rust diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h index 47e6a17..367044a 100644 --- a/gcc/rust/util/rust-attribute-values.h +++ b/gcc/rust/util/rust-attribute-values.h @@ -85,6 +85,13 @@ public: static constexpr auto &NON_EXHAUSTIVE = "non_exhaustive"; static constexpr auto &RUSTFMT = "rustfmt"; + + static constexpr auto &TEST = "test"; + + static constexpr auto &SIMD_TEST = "simd_test"; + + static constexpr auto &RUSTC_ARGS_REQUIRED_CONST + = "rustc_args_required_const"; }; } // namespace Values } // namespace Rust diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc index c77e99c..c846c2d 100644 --- a/gcc/rust/util/rust-attributes.cc +++ b/gcc/rust/util/rust-attributes.cc @@ -88,6 +88,9 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::RUSTC_LAYOUT_SCALAR_VALID_RANGE_START, CODE_GENERATION}, + // TODO: be careful about calling functions marked with this? + {Attrs::RUSTC_ARGS_REQUIRED_CONST, CODE_GENERATION}, + {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}, {Attrs::RUSTC_DIAGNOSTIC_ITEM, STATIC_ANALYSIS}, @@ -95,7 +98,10 @@ static const BuiltinAttrDefinition __definitions[] {Attrs::FUNDAMENTAL, TYPE_CHECK}, {Attrs::NON_EXHAUSTIVE, TYPE_CHECK}, - {Attrs::RUSTFMT, EXTERNAL}}; + {Attrs::RUSTFMT, EXTERNAL}, + + {Attrs::TEST, CODE_GENERATION}, + {Attrs::SIMD_TEST, CODE_GENERATION}}; BuiltinAttributeMappings * BuiltinAttributeMappings::get () @@ -221,7 +227,8 @@ check_doc_attribute (const AST::Attribute &attribute) break; // FIXME: Handle them as well - case AST::AttrInput::TOKEN_TREE: { + case AST::AttrInput::TOKEN_TREE: + { // FIXME: This doesn't check for #[doc(alias(...))] const auto &option = static_cast<const AST::DelimTokenTree &> ( attribute.get_attr_input ()); @@ -388,7 +395,7 @@ AttributeChecker::visit (AST::MetaItemLitExpr &) {} void -AttributeChecker::visit (AST::MetaItemPathLit &) +AttributeChecker::visit (AST::MetaItemPathExpr &) {} void diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h index 7c7a1fc..db8fe23 100644 --- a/gcc/rust/util/rust-attributes.h +++ b/gcc/rust/util/rust-attributes.h @@ -130,7 +130,7 @@ private: void visit (AST::AttrInputLiteral &attr_input) override; void visit (AST::AttrInputMacro &attr_input) override; void visit (AST::MetaItemLitExpr &meta_item) override; - void visit (AST::MetaItemPathLit &meta_item) override; + void visit (AST::MetaItemPathExpr &meta_item) override; void visit (AST::BorrowExpr &expr) override; void visit (AST::DereferenceExpr &expr) override; void visit (AST::ErrorPropagationExpr &expr) override; diff --git a/gcc/rust/util/rust-base62.h b/gcc/rust/util/rust-base62.h index e751c95..5fd7a37 100644 --- a/gcc/rust/util/rust-base62.h +++ b/gcc/rust/util/rust-base62.h @@ -26,8 +26,7 @@ namespace Rust { /** * Get the Base62 representation of an integer */ -std::string -base62_integer (uint64_t value); +std::string base62_integer (uint64_t value); } // namespace Rust diff --git a/gcc/rust/util/rust-canonical-path.h b/gcc/rust/util/rust-canonical-path.h index 4d8f954..079ae76 100644 --- a/gcc/rust/util/rust-canonical-path.h +++ b/gcc/rust/util/rust-canonical-path.h @@ -57,10 +57,11 @@ public: return *this; } - static CanonicalPath new_seg (NodeId id, const std::string &path) + static CanonicalPath new_seg (NodeId id, std::string path) { rust_assert (!path.empty ()); - return CanonicalPath ({std::pair<NodeId, std::string> (id, path)}, + return CanonicalPath ({std::pair<NodeId, std::string> (id, + std::move (path))}, UNKNOWN_CRATENUM); } @@ -68,14 +69,18 @@ public: trait_impl_projection_seg (NodeId id, const CanonicalPath &trait_seg, const CanonicalPath &impl_type_seg) { - return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + " as " + // https://doc.rust-lang.org/reference/paths.html#canonical-paths + // should be "<X>"? + return CanonicalPath::new_seg (id, "<impl " + impl_type_seg.get () + " as " + trait_seg.get () + ">"); } static CanonicalPath inherent_impl_seg (NodeId id, const CanonicalPath &impl_type_seg) { - return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + ">"); + // https://doc.rust-lang.org/reference/paths.html#canonical-paths + // should be "<X as Y>"? + return CanonicalPath::new_seg (id, "<impl " + impl_type_seg.get () + ">"); } std::string get () const diff --git a/gcc/rust/util/rust-dir-owner.h b/gcc/rust/util/rust-dir-owner.h index dcb45d8..fb72bb1 100644 --- a/gcc/rust/util/rust-dir-owner.h +++ b/gcc/rust/util/rust-dir-owner.h @@ -26,8 +26,7 @@ namespace Rust { // extracts the owned subdirectory name from a file name -bool -get_file_subdir (const std::string &filename, std::string &subdir); +bool get_file_subdir (const std::string &filename, std::string &subdir); } // namespace Rust diff --git a/gcc/rust/util/rust-edition.h b/gcc/rust/util/rust-edition.h index d034ea0..532fedb 100644 --- a/gcc/rust/util/rust-edition.h +++ b/gcc/rust/util/rust-edition.h @@ -33,8 +33,7 @@ enum class Edition E2021 }; -Edition -get_rust_edition (); +Edition get_rust_edition (); } // namespace Rust diff --git a/gcc/rust/util/rust-ggc.cc b/gcc/rust/util/rust-ggc.cc new file mode 100644 index 0000000..0722af2 --- /dev/null +++ b/gcc/rust/util/rust-ggc.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#include "rust-ggc.h" +#include "stringpool.h" + +namespace Rust { + +namespace GGC { + +Ident::Ident (const char *str) : inner (get_identifier (str)) {} + +Ident::Ident (const std::string &str) + : inner (get_identifier_with_length (str.c_str (), str.length ())) +{} + +bool +Ident::operator== (const std::string &other) const +{ + // maybe_get_identifier_with_length doesn't seem to exist + return maybe_get_identifier (other.c_str ()) == inner; +} + +} // namespace GGC + +} // namespace Rust diff --git a/gcc/rust/util/rust-ggc.h b/gcc/rust/util/rust-ggc.h new file mode 100644 index 0000000..da28ede --- /dev/null +++ b/gcc/rust/util/rust-ggc.h @@ -0,0 +1,63 @@ +// Copyright (C) 2025 Free Software Foundation, Inc. + +// This file is part of GCC. + +// GCC is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3, or (at your option) any later +// version. + +// GCC is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. + +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +#ifndef RUST_GGC_H +#define RUST_GGC_H + +#include "rust-system.h" +#include "tree.h" + +namespace Rust { + +namespace GGC { + +class Ident +{ + tree inner; + +public: + Ident (const char *str); + Ident (const std::string &str); + + bool operator== (const Ident &other) const { return inner == other.inner; } + bool operator== (const std::string &other) const; + + const char *c_str () const { return IDENTIFIER_POINTER (inner); } + size_t size () const { return IDENTIFIER_LENGTH (inner); } + + bool empty () const { return !size (); } + + std::string as_string () const + { + return std::string (c_str (), c_str () + size ()); + } + + tree as_tree () const { return inner; } +}; + +static inline bool +operator== (const std::string &a, const Ident &b) +{ + return b == a; +} + +} // namespace GGC + +} // namespace Rust + +#endif // RUST_GGC_H diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index eaa640c..4629e6a 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -1148,17 +1148,19 @@ Mappings::lookup_module_children (NodeId module) } void -Mappings::insert_ast_module (AST::Module *module) +Mappings::insert_glob_container (AST::Item *container) { - rust_assert (modules.find (module->get_node_id ()) == modules.end ()); - modules[module->get_node_id ()] = module; + rust_assert (glob_containers.find (container->get_node_id ()) + == glob_containers.end ()); + + glob_containers[container->get_node_id ()] = container; } -tl::optional<AST::Module *> -Mappings::lookup_ast_module (NodeId id) +tl::optional<AST::Item *> +Mappings::lookup_glob_container (NodeId id) { - auto it = modules.find (id); - if (it == modules.end ()) + auto it = glob_containers.find (id); + if (it == glob_containers.end ()) return tl::nullopt; return {it->second}; diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h index b523a36..c8fafa4 100644 --- a/gcc/rust/util/rust-hir-map.h +++ b/gcc/rust/util/rust-hir-map.h @@ -321,8 +321,8 @@ public: void insert_visibility (NodeId id, Privacy::ModuleVisibility visibility); tl::optional<Privacy::ModuleVisibility &> lookup_visibility (NodeId id); - void insert_ast_module (AST::Module *); - tl::optional<AST::Module *> lookup_ast_module (NodeId id); + void insert_glob_container (AST::Item *); + tl::optional<AST::Item *> lookup_glob_container (NodeId id); void insert_module_child (NodeId module, NodeId child); tl::optional<std::vector<NodeId> &> lookup_module_children (NodeId module); @@ -436,7 +436,7 @@ private: std::map<NodeId, std::vector<NodeId>> module_child_map; std::map<NodeId, std::vector<Resolver::CanonicalPath>> module_child_items; std::map<NodeId, NodeId> child_to_parent_module_map; - std::map<NodeId, AST::Module *> modules; + std::map<NodeId, AST::Item *> glob_containers; // AST mappings std::map<NodeId, AST::Item *> ast_item_mappings; diff --git a/gcc/rust/util/rust-punycode.h b/gcc/rust/util/rust-punycode.h index a939f05..75260ce 100644 --- a/gcc/rust/util/rust-punycode.h +++ b/gcc/rust/util/rust-punycode.h @@ -27,8 +27,7 @@ namespace Rust { /* Encode a string as punycode. Returns a string if encoding is successful. * Returns nullopt otherwise. Note that a returned string contains only ASCII * characters and does not start with `xn--`. */ -tl::optional<std::string> -encode_punycode (const Utf8String &src); +tl::optional<std::string> encode_punycode (const Utf8String &src); } // namespace Rust @@ -36,8 +35,7 @@ encode_punycode (const Utf8String &src); namespace selftest { -void -rust_punycode_encode_test (); +void rust_punycode_encode_test (); } // namespace selftest diff --git a/gcc/rust/util/rust-token-converter.cc b/gcc/rust/util/rust-token-converter.cc index fc34adb..52172f4 100644 --- a/gcc/rust/util/rust-token-converter.cc +++ b/gcc/rust/util/rust-token-converter.cc @@ -202,7 +202,8 @@ convert (const std::vector<const_TokenPtr> &tokens) case PERCENT_EQ: case SCOPE_RESOLUTION: case NOT_EQUAL: - case EQUAL_EQUAL: { + case EQUAL_EQUAL: + { auto str = token->as_string (); auto it = str.cbegin (); for (; it != str.cend () - 1; it++) @@ -260,9 +261,8 @@ convert (const std::vector<const_TokenPtr> &tokens) return trees.back (); } -static void -from_tokenstream (const ProcMacro::TokenStream &ts, - std::vector<const_TokenPtr> &result); +static void from_tokenstream (const ProcMacro::TokenStream &ts, + std::vector<const_TokenPtr> &result); /** * Append the token corresponding to a given Ident to a vector. diff --git a/gcc/rust/util/rust-token-converter.h b/gcc/rust/util/rust-token-converter.h index 5405d6e..6e4af50 100644 --- a/gcc/rust/util/rust-token-converter.h +++ b/gcc/rust/util/rust-token-converter.h @@ -23,14 +23,11 @@ namespace Rust { -ProcMacro::TokenStream -convert (const std::vector<const_TokenPtr> &tokens); +ProcMacro::TokenStream convert (const std::vector<const_TokenPtr> &tokens); -std::vector<const_TokenPtr> -convert (const ProcMacro::TokenStream &ts); +std::vector<const_TokenPtr> convert (const ProcMacro::TokenStream &ts); -ProcMacro::Literal -convert_literal (const_TokenPtr lit); +ProcMacro::Literal convert_literal (const_TokenPtr lit); } // namespace Rust diff --git a/gcc/rust/util/rust-unicode.h b/gcc/rust/util/rust-unicode.h index 6a6526d..6579b80 100644 --- a/gcc/rust/util/rust-unicode.h +++ b/gcc/rust/util/rust-unicode.h @@ -59,20 +59,15 @@ public: Utf8String nfc_normalize () const; }; -bool -is_alphabetic (uint32_t codepoint); +bool is_alphabetic (uint32_t codepoint); -bool -is_ascii_only (const std::string &str); +bool is_ascii_only (const std::string &str); -bool -is_numeric (uint32_t codepoint); +bool is_numeric (uint32_t codepoint); -bool -is_nfc_qc_no (uint32_t codepoint); +bool is_nfc_qc_no (uint32_t codepoint); -bool -is_nfc_qc_maybe (uint32_t codepoint); +bool is_nfc_qc_maybe (uint32_t codepoint); enum class QuickCheckResult { @@ -81,8 +76,7 @@ enum class QuickCheckResult MAYBE }; -QuickCheckResult -nfc_quick_check (const std::vector<Codepoint> &s); +QuickCheckResult nfc_quick_check (const std::vector<Codepoint> &s); } // namespace Rust @@ -90,14 +84,11 @@ nfc_quick_check (const std::vector<Codepoint> &s); namespace selftest { -void -rust_nfc_qc_test (); +void rust_nfc_qc_test (); -void -rust_utf8_normalize_test (); +void rust_utf8_normalize_test (); -void -rust_utf8_property_test (); +void rust_utf8_property_test (); } // namespace selftest diff --git a/gcc/rust/util/rust-unwrap-segment.h b/gcc/rust/util/rust-unwrap-segment.h index bebdc3a..af3a237 100644 --- a/gcc/rust/util/rust-unwrap-segment.h +++ b/gcc/rust/util/rust-unwrap-segment.h @@ -83,14 +83,11 @@ public: /* * Used to get the node id of a path segment object */ -NodeId -unwrap_segment_node_id (const AST::TypePathSegment &seg); +NodeId unwrap_segment_node_id (const AST::TypePathSegment &seg); -NodeId -unwrap_segment_node_id (const AST::SimplePathSegment &seg); +NodeId unwrap_segment_node_id (const AST::SimplePathSegment &seg); -NodeId -unwrap_segment_node_id (const AST::PathExprSegment &seg); +NodeId unwrap_segment_node_id (const AST::PathExprSegment &seg); template <class T> NodeId diff --git a/gcc/sarif-replay.cc b/gcc/sarif-replay.cc index a96c97b..c740c29 100644 --- a/gcc/sarif-replay.cc +++ b/gcc/sarif-replay.cc @@ -93,6 +93,11 @@ static const char *const usage_msg = ( "\n" " --usage\n" " Print this message and exit.\n" +"\n" +"Options for maintainers:\n" +"\n" +" -fdebug-physical-locations\n" +" Dump debugging information about physical locations to stderr.\n" "\n"); static void @@ -182,7 +187,11 @@ parse_options (int argc, char **argv, print_version (); exit (0); } - + else if (strcmp (option, "-fdebug-physical-locations") == 0) + { + opts.m_replay_opts.m_debug_physical_locations = true; + handled = true; + } if (!handled) { if (option[0] == '-') @@ -245,6 +254,8 @@ main (int argc, char **argv) note.finish ("about to replay %qs...", filename); } libgdiagnostics::manager playback_mgr; + playback_mgr.set_debug_physical_locations + (opts.m_replay_opts.m_debug_physical_locations); playback_mgr.add_text_sink (stderr, opts.m_replay_opts.m_diagnostics_colorize); for (auto spec : opts.m_extra_output_specs) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index db4d560..1ac6084 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,758 @@ +2025-08-05 Jason Merrill <jason@redhat.com> + + PR c++/121068 + * g++.dg/cpp26/constexpr-new5.C: New test. + +2025-08-05 Mikael Morin <morin-mikael@orange.fr> + + * gfortran.dg/pointer_assign_16.f90: New test. + +2025-08-05 H.J. Lu <hjl.tools@gmail.com> + + PR target/121410 + * gcc.target/i386/pr121410.c: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/offset_of1.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/execute/torture/const-generics-1.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/generics8.rs: extra error message + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3546.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3885.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/const_generics_3.rs: this works now + * rust/compile/const_generics_5.rs: likewise + * rust/compile/const_generics_8.rs: move the failure to another test case + * rust/compile/const_generics_10.rs: New test. + * rust/compile/const_generics_11.rs: New test. + * rust/compile/const_generics_12.rs: New test. + * rust/compile/const_generics_13.rs: New test. + * rust/compile/const_generics_14.rs: New test. + * rust/compile/const_generics_15.rs: New test. + * rust/compile/const_generics_16.rs: New test. + * rust/compile/const_generics_9.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3960.rs: New test. + +2025-08-05 Ryutaro Okada <1015ryu88@gmail.com> + + * rust/compile/auto_traits2.rs: + emove warning for unused `self` parameter + * rust/compile/derive-debug1.rs: + emove warning for unused `self` parameter + * rust/compile/derive_macro1.rs: + Remove warning for unused `self` parameter + * rust/compile/format_args_basic_expansion.rs: + Remove warning for unused `self` parameter + * rust/compile/format_args_extra_comma.rs: + Remove warning for unused `self` parameter + * rust/compile/issue-2043.rs: + Remove warning for unused `self` parameter + * rust/compile/issue-2166.rs: + Remove warning for unused `self` parameter + * rust/compile/issue-2238.rs: + Remove warning for unused `self` parameter + * rust/compile/issue-2907.rs: + Remove warning for unused `self` parameter + * rust/compile/min_specialization1.rs: + Remove warning for unused `self` parameter + * rust/compile/name_resolution2.rs: + Remove warning for unused `self` parameter + * rust/compile/name_resolution4.rs: + Remove warning for unused `self` parameter + * rust/compile/torture/generics29.rs: + Remove warning for unused `self` parameter + * rust/compile/torture/generics30.rs: + Remove warning for unused `self` parameter + * rust/compile/torture/traits3.rs: + Remove warning for unused `self` parameter + * rust/compile/torture/traits7.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/impl_trait3.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/min_specialization2.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/trait10.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/trait11.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/trait12.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/trait13.rs: + Remove warning for unused `self` parameter + * rust/execute/torture/trait9.rs: + Remove warning for unused `self` parameter + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/while_let1.rs: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/offset_of2.rs: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/offset_of1.rs: New test. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/compile/issue-4006.rs: New test. + +2025-08-05 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/execute/inline_asm_inout_ident.rs: New test. + * rust/execute/inline_asm_inout_var.rs: New test. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/match-slicepattern-slice.rs: New file. + * rust/execute/torture/match-slicepattern-slice-1.rs: New file. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/try_block1.rs: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/deferred_const_inference.rs: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/glob_import_enum.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3915.rs: New test. + * rust/execute/torture/sip-hasher.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3916.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3978.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/parse_simple_path_fail_1.rs: New test. + * rust/compile/parse_simple_path_fail_2.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3524.rs: New test. + +2025-08-05 lishin <lishin1008@gmail.com> + + * rust/compile/loop_constant_context.rs: New test. + * rust/compile/issue-3618.rs: + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/match-slicepattern-array.rs: New file. + * rust/execute/torture/match-slicepattern-array-1.rs: New file. + +2025-08-05 Yap Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/slicepattern-size-mismatch.rs: New file. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/execute/torture/issue-2005.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-1048.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3144.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3599.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3876.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-2680.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/derive_partial_ord1.rs: this is now fully supported + * rust/execute/torture/basic_partial_ord1.rs: add missing i32 impl + * rust/execute/torture/basic_partial_ord2.rs: likewise + * rust/compile/issue-3836.rs: New test. + * rust/execute/torture/issue-3836.rs: New test. + * rust/execute/torture/partial-ord-6.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3874.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/all-cast.rs: shows array capacity now + * rust/compile/arrays2.rs: likewise + * rust/compile/const3.rs: fix error message + * rust/compile/const_generics_3.rs: disable until typecheck we get proper errors now! + * rust/compile/usize1.rs: proper capacity error message + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/while_let_without_label.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/additional-trait-bounds2nr2.rs: Remove + -frust-name-resolution-2.0 usage. + * rust/compile/const_generics_3.rs: Likewise. + * rust/compile/enum_variant_name.rs: Likewise. + * rust/compile/generics9.rs: Likewise. + * rust/compile/invalid_label_name.rs: Likewise. + * rust/compile/issue-3304.rs: Likewise. + * rust/compile/macros/mbe/macro-issue3708.rs: Likewise. + * rust/compile/macros/mbe/macro-issue3709-2.rs: Likewise. + * rust/compile/name_resolution10.rs: Likewise. + * rust/compile/name_resolution11.rs: Likewise. + * rust/compile/name_resolution12.rs: Likewise. + * rust/compile/name_resolution13.rs: Likewise. + * rust/compile/name_resolution14.rs: Likewise. + * rust/compile/name_resolution15.rs: Likewise. + * rust/compile/name_resolution16.rs: Likewise. + * rust/compile/name_resolution17.rs: Likewise. + * rust/compile/name_resolution18.rs: Likewise. + * rust/compile/name_resolution20.rs: Likewise. + * rust/compile/name_resolution22.rs: Likewise. + * rust/compile/name_resolution23.rs: Likewise. + * rust/compile/name_resolution24.rs: Likewise. + * rust/compile/name_resolution25.rs: Likewise. + * rust/compile/name_resolution6.rs: Likewise. + * rust/compile/name_resolution7.rs: Likewise. + * rust/compile/name_resolution8.rs: Likewise. + * rust/compile/name_resolution9.rs: Likewise. + * rust/compile/nested_macro_definition.rs: Likewise. + * rust/compile/pub_restricted_1.rs: Likewise. + * rust/compile/pub_restricted_2.rs: Likewise. + * rust/compile/self-in-impl.rs: Likewise. + * rust/compile/self_import_namespace.rs: Likewise. + * rust/compile/use_1.rs: Likewise. + * rust/compile/xfail/name_resolution21.rs: Likewise. + * rust/execute/torture/name_resolution.rs: Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/compile.exp: Removed. + * rust/compile/nr2/exclude: Removed. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/match-restpattern-tuple-1.rs: New file. + * rust/compile/match-restpattern-tuple-2.rs: New file. + * rust/execute/torture/match-restpattern-tuple.rs: New file. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/tuple_mismatch.rs: Include RestPattern in test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove issue-3315-2.rs. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove torture/alt_patterns1.rs. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/macros/builtin/recurse2.rs: Match "abheyho\0" as + well as "abheyho", to handle slight differences in assembly + output for null-terminated strings. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3525.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-3551.rs: New test. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/match-tuplestructpattern.rs: New file. + * rust/execute/torture/match-tuplestructpattern.rs: New file. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove issue-3642.rs. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/silly-order-bug.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entries. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/execute/torture/issue-1481.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/nr2/exclude: nr2 puts out an extra error + * rust/compile/issue-3642.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/execute/black_box.rs: Return 0 from main. + * rust/execute/match-identifierpattern-enum.rs: Move to... + * rust/execute/xfail/match-identifierpattern-enum.rs: ...here. + * rust/execute/execute.exp: New file. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/bug-with-default-generic.rs: New test. + * rust/execute/torture/partial-eq-1.rs: New test. + * rust/execute/torture/partial-eq-2.rs: New test. + * rust/execute/torture/partial-eq-3.rs: New test. + * rust/execute/torture/partial-eq-4.rs: New test. + * rust/execute/torture/partial-ord-1.rs: New test. + * rust/execute/torture/partial-ord-2.rs: New test. + * rust/execute/torture/partial-ord-3.rs: New test. + * rust/execute/torture/partial-ord-4.rs: New test. + * rust/execute/torture/partial-ord-5.rs: New test. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/match-identifierpattern-enum.rs: New file. + * rust/execute/match-identifierpattern-enum.rs: New file. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entries. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/compile/derive_partial_ord1.rs: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/derive-partialeq2.rs: Add declaration for + discriminant_value. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/execute/torture/basic_partial_ord1.rs: New test. + * rust/execute/torture/basic_partial_ord2.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/const_generics_3.rs: + * rust/compile/issue-3660.rs: New test. + +2025-08-05 Zhi Heng <yapzhhg@gmail.com> + + * rust/compile/match-identifierpattern.rs: New file. + * rust/execute/torture/match-identifierpattern.rs: New file. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entries. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entries. + * rust/compile/pub_restricted_1.rs: Adjust expected error + messages and only run with name resolution 2.0 enabled. + * rust/compile/pub_restricted_2.rs: Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove canonical_paths1.rs. + +2025-08-05 Vishruth-Thimmaiah <vishruththimmaiah@gmail.com> + + * rust/compile/torture/unended-raw-byte-string.rs: + New test to ensure correct error message for unended raw byte string. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/issue-3671.rs: Remove usage of Self. + * rust/compile/nr2/exclude: Remove issue-3671.rs. + * rust/compile/self-in-impl.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entries. + +2025-08-05 Vishruth-Thimmaiah <vishruththimmaiah@gmail.com> + + * rust/compile/torture/extern_mod2.rs: + New test to ensure an error is emitted for empty path attributes. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/const_block1.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/traits9.rs: update errors + * rust/compile/unify-errors1.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/bad-rpit1.rs: New test. + * rust/execute/torture/impl_rpit1.rs: New test. + * rust/execute/torture/impl_rpit2.rs: New test. + * rust/execute/torture/impl_rpit3.rs: New test. + +2025-08-05 Parthib <parthibdutta02@gmail.com> + + * lib/rust.exp: Remove timeout. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/execute/torture/for-loop1.rs: Adjust paths. + * rust/execute/torture/for-loop2.rs: Likewise. + * rust/execute/torture/iter1.rs: Likewise. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/execute/torture/builtin_abort.rs: Fix path to + intrinsics::abort. + +2025-08-05 Tom Schollenberger <tss2344@g.rit.edu> + + * rust/compile/issue-3661.rs: Test NR2 has expected behavior + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/macros/mbe/meta-param.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/execute/same_field_name.rs: Move to... + * rust/compile/same_field_name.rs: ...here and adjust expected + errors. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/nr2/exclude: these are fixed now + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/compile/nr2/exclude: Remove entries. + +2025-08-05 Tom Schollenberger <tss2344@g.rit.edu> + + * rust/compile/issue-3618.rs: Test empty loops error properly. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/nr2/exclude: nr2 cant handle this + * rust/compile/impl_trait_generic_arg.rs: New test. + +2025-08-05 Owen Avery <powerboat9.gamer@gmail.com> + + * rust/execute/torture/struct-pattern-match.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/issue-2015.rs: fully supported now + * rust/compile/nr2/exclude: nr2 cant handle some of these + * rust/compile/issue-1487.rs: New test. + * rust/compile/issue-3454.rs: New test. + * rust/execute/torture/impl_desugar-2.rs: New test. + * rust/execute/torture/impl_desugar.rs: New test. + * rust/execute/torture/impl_trait1.rs: New test. + * rust/execute/torture/impl_trait2.rs: New test. + * rust/execute/torture/impl_trait3.rs: New test. + * rust/execute/torture/impl_trait4.rs: New test. + * rust/execute/torture/issue-1482.rs: New test. + +2025-08-05 Philip Herron <herron.philip@googlemail.com> + + * rust/compile/impl_trait_diag.rs: New test. + * rust/compile/issue-1485.rs: New test. + +2025-08-05 CohenArthur <cohenarthur.dev@gmail.com> + Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com> + + * rust/execute/torture/derive-partialeq2.rs: Add missing terminating nul char. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/derive-partialeq2.rs: New test. + +2025-08-05 Arthur Cohen <arthur.cohen@embecosm.com> + + * rust/execute/torture/struct_pattern1.rs: New test. + +2025-08-05 Georg-Johann Lay <avr@gjlay.de> + + PR target/121359 + * gcc.target/avr/torture/pr118591-1.c: Remove -mlra. + * gcc.target/avr/torture/pr118591-2.c: Same. + +2025-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121395 + * gcc.dg/vect/pr59984.c: Adjust. + +2025-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121382 + * gcc.dg/torture/pr121382.c: New testcase. + +2025-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121370 + * gcc.dg/torture/pr121370.c: New testcase. + +2025-08-05 Yang Yujie <yangyujie@loongson.cn> + + * gcc.dg/bitintext.h (S, CEIL, PROMOTED_SIZE): Define. + (BEXTC): Generalize to only check extension within PROMOTED_SIZE bits. + +2025-08-05 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * g++.dg/DRs/dr2579.C: New test. + * c-c++-common/cpp/va-opt-6.c: Expect ' rather than \" around + tokens in incorrect pasting diagnostics. + * gcc.dg/c23-attr-syntax-6.c: Likewise. + * gcc.dg/cpp/paste12.c: Likewise. + * gcc.dg/cpp/paste12-2.c: Likewise. + * gcc.dg/cpp/paste14.c: Likewise. + * gcc.dg/cpp/paste14-2.c: Likewise. + +2025-08-05 Pan Li <pan2.li@intel.com> + + * gcc.target/riscv/sat/sat_u_mul-1-u32-from-u64.c: Add mulhu + asm check. + * gcc.target/riscv/sat/sat_u_mul-1-u64-from-u128.c: Ditto. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/121351 + * g++.dg/cpp2a/concepts-using6.C: New test. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/121351 + PR c++/119859 + * g++.dg/cpp2a/concepts-using5.C: New test. + * g++.dg/cpp2a/concepts-using5a.C: New test. + +2025-08-04 Patrick Palka <ppalka@redhat.com> + + PR c++/120620 + * g++.dg/cpp2a/constexpr-dynamic19.C: New test. + * g++.dg/cpp2a/constexpr-dynamic1a.C: New test. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + PR diagnostics/116253 + * gcc.dg/plugin/diagnostic-test-nesting-html.c: New test. + * gcc.dg/plugin/diagnostic-test-nesting-html.py: New test script. + * gcc.dg/plugin/plugin.exp: Add it. + * libgdiagnostics.dg/test-multiple-lines.c: Update expected output + to show fix-it hint. + * sarif-replay.dg/2.1.0-valid/nested-diagnostics-1.sarif: New test. + +2025-08-04 David Malcolm <dmalcolm@redhat.com> + + PR diagnostics/116792 + * gcc.dg/plugin/diagnostic-test-graphs-html.py: Remove trailing + space from expected text of message. + * sarif-replay.dg/2.1.0-valid/embedded-links-check-html.py: + Likewise. + * sarif-replay.dg/2.1.0-valid/graphs-check-html.py: Likewise. + +2025-08-04 Konstantinos Eleftheriou <konstantinos.eleftheriou@vrull.eu> + + PR rtl-optimization/121303 + * gcc.target/i386/pr121303.c: New test. + +2025-08-04 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * g++.dg/DRs/dr2580.C: New test. + +2025-08-04 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * g++.dg/DRs/dr2578.C: New test. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/dupq_13.c: New test. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/dup_1.c: New test. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/pnext_3.c: New test. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve2/acle/general/match_4.c: New test. + * gcc.target/aarch64/sve2/acle/general/nmatch_1.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/acge_1.c: New test. + * gcc.target/aarch64/sve/acle/general/acgt_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/acle_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/aclt_1.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/cmpeq_6.c: New test. + * gcc.target/aarch64/sve/acle/general/cmpge_9.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_9.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_9.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_9.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpne_5.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpuo_1.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/cmpeq_5.c: New test. + * gcc.target/aarch64/sve/acle/general/cmpge_7.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpge_8.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_7.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_8.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_7.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_8.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_7.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_8.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpne_4.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/cmpeq_1.c: Check the number + of PTRUEs. + * gcc.target/aarch64/sve/acle/general/cmpge_5.c: New test. + * gcc.target/aarch64/sve/acle/general/cmpge_6.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_5.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_6.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_5.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_6.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_5.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_6.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpne_3.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/cmpeq_1.c: Add more tests. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/pred_clobber_1.c: Disable combine. + * gcc.target/aarch64/sve/pred_clobber_2.c: Likewise. + * gcc.target/aarch64/sve/pred_clobber_3.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpeq_2.c: Add more cases. + * gcc.target/aarch64/sve/acle/general/cmpeq_4.c: New test. + * gcc.target/aarch64/sve/acle/general/cmpge_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpge_2.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpge_3.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpge_4.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_2.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_3.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpgt_4.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_2.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_3.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmple_4.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_2.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_3.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmplt_4.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpne_1.c: Likewise. + * gcc.target/aarch64/sve/acle/general/cmpne_2.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + * gcc.target/aarch64/sve/acle/general/unpkhi_1.c: New test. + * gcc.target/aarch64/sve/acle/general/unpklo_1.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121294 + * gcc.target/aarch64/sve/acle/general/rev_2.c: New test. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121294 + * gcc.target/aarch64/sve/acle/general/perm_2.c: New test. + * gcc.target/aarch64/sve/acle/general/perm_3.c: Likewise. + * gcc.target/aarch64/sve/acle/general/perm_4.c: Likewise. + * gcc.target/aarch64/sve/acle/general/perm_5.c: Likewise. + * gcc.target/aarch64/sve/acle/general/perm_6.c: Likewise. + * gcc.target/aarch64/sve/acle/general/perm_7.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR testsuite/121118 + * gcc.target/aarch64/sve/acle/general/pr121118_1.c: New test. + * gcc.target/aarch64/sve/acle/general/whilele_13.c: Likewise. + * gcc.target/aarch64/sve/acle/general/whilelt_6.c: Likewise. + * gcc.target/aarch64/sve2/acle/general/whilege_1.c: Likewise. + * gcc.target/aarch64/sve2/acle/general/whilegt_1.c: Likewise. + * gcc.target/aarch64/sve2/acle/general/whilerw_5.c: Likewise. + * gcc.target/aarch64/sve2/acle/general/whilewr_5.c: Likewise. + +2025-08-04 Richard Sandiford <richard.sandiford@arm.com> + + PR target/121293 + * gcc.target/aarch64/sve/acle/general/dupq_lane_9.c: New test. + +2025-08-04 Richard Biener <rguenther@suse.de> + + PR tree-optimization/121362 + * gcc.dg/tree-ssa/ssa-fre-105.c: New testcase. + * gcc.dg/tree-ssa/ssa-fre-106.c: Likewise. + +2025-08-04 H.J. Lu <hjl.tools@gmail.com> + + PR target/120941 + * gcc.target/i386/pr120941-1.c: New test. + +2025-08-03 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * g++.dg/DRs/dr1709.C: New test. + +2025-08-03 Jakub Jelinek <jakub@redhat.com> + + PR c++/120845 + * g++.dg/modules/cpp-21.C: New test. + 2025-08-02 Martin Uecker <uecker@tugraz.at> * gcc.dg/Warray-parameter-11.c: Change Warray-parameter to diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-6.c b/gcc/testsuite/c-c++-common/cpp/va-opt-6.c index 8a7761b..9a92431 100644 --- a/gcc/testsuite/c-c++-common/cpp/va-opt-6.c +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-6.c @@ -3,15 +3,15 @@ /* { dg-options "-std=c++20" { target c++ } } */ #define a "" -#define b(...) a ## #__VA_OPT__(1) /* { dg-error "pasting \"a\" and \"\"\"\" does not give a valid preprocessing token" } */ -#define c(...) a ## #__VA_OPT__(1) /* { dg-error "pasting \"a\" and \"\"1\"\" does not give a valid preprocessing token" } */ +#define b(...) a ## #__VA_OPT__(1) /* { dg-error "pasting 'a' and '\"\"' does not give a valid preprocessing token" } */ +#define c(...) a ## #__VA_OPT__(1) /* { dg-error "pasting 'a' and '\"1\"' does not give a valid preprocessing token" } */ #define d(...) #__VA_OPT__(1) ## ! #define e(...) #__VA_OPT__(1) ## ! #define f(...) #__VA_OPT__(. ## !) #define g(...) #__VA_OPT__(. ## !) b() c(1) -d( ) /* { dg-error "pasting \"\"\"\" and \"!\" does not give a valid preprocessing token" } */ -e( 1 ) /* { dg-error "pasting \"\"1\"\" and \"!\" does not give a valid preprocessing token" } */ +d( ) /* { dg-error "pasting '\"\"' and '!' does not give a valid preprocessing token" } */ +e( 1 ) /* { dg-error "pasting '\"1\"' and '!' does not give a valid preprocessing token" } */ f() -g(0) /* { dg-error "pasting \".\" and \"!\" does not give a valid preprocessing token" } */ +g(0) /* { dg-error "pasting '.' and '!' does not give a valid preprocessing token" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c index 852839e..d76f9ae 100644 --- a/gcc/testsuite/c-c++-common/gomp/map-6.c +++ b/gcc/testsuite/c-c++-common/gomp/map-6.c @@ -13,20 +13,20 @@ foo (void) #pragma omp target map (to:a) ; - #pragma omp target map (a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present'" "" { target c++ } } */ - ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ + #pragma omp target map (a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present'" "" { target c++ } } */ + ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ - #pragma omp target map (close, a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present'" "" { target c++ } } */ - ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ + #pragma omp target map (close, a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present'" "" { target c++ } } */ + ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ - #pragma omp target enter data map(b7) map (close, a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present'" "" { target c++ } } */ - ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ + #pragma omp target enter data map(b7) map (close, a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present'" "" { target c++ } } */ + ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ - #pragma omp target exit data map(b7) map (close, a from: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present'" "" { target c++ } } */ - ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ + #pragma omp target exit data map(b7) map (close, a from: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present'" "" { target c++ } } */ + ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ - #pragma omp target data map(b7) map (close, a from: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present'" "" { target c++ } } */ - ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ + #pragma omp target data map(b7) map (close, a from: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present'" "" { target c++ } } */ + ; /* { dg-error "'map' clause with map-type modifier other than 'always', 'close', 'iterator', 'mapper' or 'present' before 'a'" "" { target c } .-1 } */ #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/target-map-iterators-1.c b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-1.c new file mode 100644 index 0000000..7d6c8dc --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +#define DIM1 17 +#define DIM2 39 + +void f (int **x, int **y) +{ + #pragma omp target map(iterator(i=0:DIM1), to: x[i][:DIM2]) + ; + + #pragma omp target map(iterator(i=0:DIM1), to: x[i][:DIM2], y[i][:DIM2]) + ; + + #pragma omp target map(iterator(i=0:DIM1), to: x[i][:DIM2] + 2) /* { dg-message "unsupported map expression" } */ + ; + + #pragma omp target map(iterator(i=0:DIM1), iterator(j=0:DIM2), to: x[i][j]) /* { dg-error "too many 'iterator' modifiers" } */ + ; + + #pragma omp target map(iterator(i=0:DIM1), to: (i % 2 == 0) ? x[i] : y[i]) /* { dg-message "unsupported map expression" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/target-map-iterators-2.c b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-2.c new file mode 100644 index 0000000..42c6d75 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-2.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +void f (int *x, float *y, double *z) +{ + #pragma omp target map(iterator(i=0:10), to: x) /* { dg-warning "iterator variable 'i' not used in clause expression" } */ + /* Add a reference to x to ensure that the 'to' clause does not get + dropped. */ + x[0] = 0; + + #pragma omp target map(iterator(i2=0:10, j2=0:20), from: x[i2]) /* { dg-warning "iterator variable 'j2' not used in clause expression" } */ + ; + + #pragma omp target map(iterator(i3=0:10, j3=0:20, k3=0:30), to: x[i3+j3], y[j3+k3], z[k3+i3]) + /* { dg-warning "iterator variable 'i3' not used in clause expression" "" { target *-*-* } .-1 } */ + /* { dg-warning "iterator variable 'j3' not used in clause expression" "" { target *-*-* } .-2 } */ + /* { dg-warning "iterator variable 'k3' not used in clause expression" "" { target *-*-* } .-3 } */ + ; + + /* Test iterator with zero iterations. */ + #pragma omp target map(iterator(i4=0:0), to: x[i4]) /* { dg-warning "iteration count is zero" } */ + ; + + /* Test iterator where the beginning is greater than the end. */ + #pragma omp target map(iterator(i5=10:0), to: x[i5]) /* { dg-warning "iteration count is zero" } */ + ; + + /* Test iterator where the beginning is greater than the end, but with a + negative step. */ + #pragma omp target map(iterator(i6=10:0:-1), to: x[i6]) + ; +} + +/* { dg-final { scan-tree-dump-times "map\\\(to:x" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i2=0:10:1, loop_label=\[^\\\)\]+\\\):from:" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i3=0:10:1, int j3=0:20:1, loop_label=\[^\\\)\]+\\\):to:" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int j3=0:20:1, int k3=0:30:1, loop_label=\[^\\\)\]+\\\):to:" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i3=0:10:1, int k3=0:30:1, loop_label=\[^\\\)\]+\\\):to:" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i4=0:0:1, loop_label=\[^\\\)\]+\\\):to:" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i5=10:0:1, loop_label=\[^\\\)\]+\\\):to:" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i6=10:0:-1, loop_label=\[^\\\)\]+\\\):to:" 1 "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/target-map-iterators-3.c b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-3.c new file mode 100644 index 0000000..62df42f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-3.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +#define DIM1 10 +#define DIM2 20 +#define DIM3 30 + +void f (int ***x, float ***y, double **z) +{ + #pragma omp target \ + map(to: x, y) \ + map(iterator(i=0:DIM1, j=0:DIM2), to: x[i][j][:DIM3], y[i][j][:DIM3]) \ + map(from: z) \ + map(iterator(i=0:DIM1), from: z[i][:DIM2]) + ; +} + +/* { dg-final { scan-tree-dump-times "if \\(i <= 9\\) goto <D\\\.\[0-9\]+>; else goto <D\\\.\[0-9\]+>;" 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "if \\(j <= 19\\) goto <D\\\.\[0-9\]+>; else goto <D\\\.\[0-9\]+>;" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\(iterator\\(int i=0:10:1, loop_label=<D\\\.\[0-9\]+>, elems=omp_iter_data\\\.\[0-9\]+, index=D\\\.\[0-9\]+\\):from:\\*D\\\.\[0-9\]+" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\(iterator\\(int i=0:10:1, loop_label=<D\\\.\[0-9\]+>, elems=omp_iter_data\\\.\[0-9\]+, index=D\\\.\[0-9\]+\\):attach:\\*D\\\.\[0-9\]+" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\(iterator\\(int i=0:10:1, int j=0:20:1, loop_label=<D\\\.\[0-9\]+>, elems=omp_iter_data\\\.\[0-9\]+, index=D\\\.\[0-9\]+\\):to:\\*D\\\.\[0-9\]+" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\(iterator\\(int i=0:10:1, int j=0:20:1, loop_label=<D\\\.\[0-9\]+>, elems=omp_iter_data\\\.\[0-9\]+, index=D\\\.\[0-9\]+\\):attach:\\*D\\\.\[0-9\]+" 4 "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/target-map-iterators-4.c b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-4.c new file mode 100644 index 0000000..5dc5ad5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-map-iterators-4.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ +/* { dg-additional-options "-std=c++98" { target c++ } } */ + +int bar (int, int); +void baz (int, int *); +#pragma omp declare target enter (baz) + +void +foo (int x, int *p) +{ + #pragma omp target map (iterator (i=0:4), to: p[bar (x, i)]) + baz (x, p); +} + +/* { dg-final { scan-tree-dump "firstprivate\\\(x\\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump-times "bar \\\(x, i\\\)" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\\(iterator\\\(int i=0:4:1, loop_label=" 2 "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/target-update-iterators-1.c b/gcc/testsuite/c-c++-common/gomp/target-update-iterators-1.c new file mode 100644 index 0000000..53b22f0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-update-iterators-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +#define DIM1 17 +#define DIM2 39 + +void f (int **x, float **y) +{ + #pragma omp target update to (iterator(i=0:DIM1): x[i][:DIM2]) + + #pragma omp target update to (iterator(i=0:DIM1): x[i][:DIM2], y[i][:DIM2]) + + #pragma omp target update to (iterator(i=0:DIM1), present: x[i][:DIM2]) + + #pragma omp target update to (iterator(i=0:DIM1), iterator(j=0:DIM2): x[i][j]) /* { dg-error "too many 'iterator' modifiers" } */ + /* { dg-error "'#pragma omp target update' must contain at least one 'from' or 'to' clauses" "" { target *-*-* } .-1 } */ + + #pragma omp target update from (iterator(i=0:DIM1), something: x[i][j]) /* { dg-error "'from' clause with modifier other than 'iterator' or 'present'" } */ + /* { dg-error "expected '\\)' before 'something'" "" { target c } .-1 } */ + /* { dg-error "'#pragma omp target update' must contain at least one 'from' or 'to' clauses" "" { target *-*-* } .-2 } */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/target-update-iterators-2.c b/gcc/testsuite/c-c++-common/gomp/target-update-iterators-2.c new file mode 100644 index 0000000..dbd43e0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-update-iterators-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +void f (int *x, float *y, double *z) +{ + #pragma omp target update to(iterator(i=0:10): x) /* { dg-warning "iterator variable 'i' not used in clause expression" }*/ + ; + + #pragma omp target update from(iterator(i2=0:10, j2=0:20): x[i2]) /* { dg-warning "iterator variable 'j2' not used in clause expression" }*/ + ; + + #pragma omp target update to(iterator(i3=0:10, j3=0:20, k3=0:30): x[i3+j3], y[j3+k3], z[k3+i3]) + /* { dg-warning "iterator variable 'i3' not used in clause expression" "" { target *-*-* } .-1 } */ + /* { dg-warning "iterator variable 'j3' not used in clause expression" "" { target *-*-* } .-2 } */ + /* { dg-warning "iterator variable 'k3' not used in clause expression" "" { target *-*-* } .-3 } */ + ; +} + +/* { dg-final { scan-tree-dump "update to\\\(x " "gimple" } } */ +/* { dg-final { scan-tree-dump "update from\\\(iterator\\\(int i2=0:10:1, loop_label=" "gimple" } } */ +/* { dg-final { scan-tree-dump "to\\\(iterator\\\(int i3=0:10:1, int k3=0:30:1, loop_label=" "gimple" } } */ +/* { dg-final { scan-tree-dump "to\\\(iterator\\\(int j3=0:20:1, int k3=0:30:1, loop_label=" "gimple" } } */ +/* { dg-final { scan-tree-dump "to\\\(iterator\\\(int i3=0:10:1, int j3=0:20:1, loop_label=" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/target-update-iterators-3.c b/gcc/testsuite/c-c++-common/gomp/target-update-iterators-3.c new file mode 100644 index 0000000..ef55216 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/target-update-iterators-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple" } */ + +#define DIM1 10 +#define DIM2 20 +#define DIM3 30 + +void f (int ***x, float ***y, double **z) +{ + #pragma omp target update to (iterator(i=0:DIM1, j=0:DIM2): x[i][j][:DIM3], y[i][j][:DIM3]) + #pragma omp target update from (iterator(i=0:DIM1): z[i][:DIM2]) +} + +/* { dg-final { scan-tree-dump-times "if \\(i <= 9\\) goto <D\.\[0-9\]+>; else goto <D\.\[0-9\]+>;" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "if \\(j <= 19\\) goto <D\.\[0-9\]+>; else goto <D\.\[0-9\]+>;" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "to\\(iterator\\(int i=0:10:1, int j=0:20:1, loop_label=<D\.\[0-9\]+>, elems=omp_iter_data\.\[0-9\]+, index=D\.\[0-9\]+\\):\\*D\.\[0-9\]+" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "from\\(iterator\\(int i=0:10:1, loop_label=<D\.\[0-9\]+>, elems=omp_iter_data\.\[0-9\]+, index=D\.\[0-9\]+\\):\\*D\.\[0-9\]+" 1 "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/DRs/dr1709.C b/gcc/testsuite/g++.dg/DRs/dr1709.C new file mode 100644 index 0000000..d3854d8 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr1709.C @@ -0,0 +1,18 @@ +// DR 1709 - Stringizing raw string literals containing newline +// { dg-do run { target c++26 } } + +#define A(a) #a +const char *a = A(a\f\\b"c"); +const char *b = A(R"abc(a\b + +)abc"); + +int +main () +{ + if (a[1] != '\f' || a[2] != '\\' || a[4] != '"' || a[6] != '"') + __builtin_abort (); + if (b[1] != '"' || b[7] != '\\' || b[9] != '\n' || b[10] != '\n' + || b[11] != ')' || b[15] != '"') + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/DRs/dr2578.C b/gcc/testsuite/g++.dg/DRs/dr2578.C new file mode 100644 index 0000000..0dce23b --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2578.C @@ -0,0 +1,10 @@ +// DR 2578 - Undefined behavior when creating an invalid string literal via stringizing +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A(a) #a +#define B(a) A(a) +#define C \\ + +const char *x = B(C); // { dg-warning "invalid string literal, ignoring final '\\\\'" "" { target c++23_down } } +// { dg-error "invalid string literal, ignoring final '\\\\'" "" { target c++26 } .-1 } diff --git a/gcc/testsuite/g++.dg/DRs/dr2579.C b/gcc/testsuite/g++.dg/DRs/dr2579.C new file mode 100644 index 0000000..dda3643 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2579.C @@ -0,0 +1,9 @@ +// DR 2579 - Undefined behavior when token pasting does not create a preprocessing token +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A(a, b) a ## b +A(5,6) +A(-,32) // { dg-error "pasting '-' and '32' does not give a valid preprocessing token" } +A("","") // { dg-error "pasting '\"\"' and '\"\"' does not give a valid preprocessing token" } +A(\,u0393) diff --git a/gcc/testsuite/g++.dg/DRs/dr2580.C b/gcc/testsuite/g++.dg/DRs/dr2580.C new file mode 100644 index 0000000..462f300 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2580.C @@ -0,0 +1,87 @@ +// DR 2580 - Undefined behavior with #line +// { dg-do preprocess } + +#line 630 "foobar.h" +#line 6 "dr2580.C" +#line 0 // { dg-error "line number out of range" } +#line 8 +#line 2147483648 // { dg-error "line number out of range" } +#line 10 +#line 4294967295 // { dg-error "line number out of range" } +#line 12 +#line 12345678912345 // { dg-error "line number out of range" } +#line 14 +#line 15 "" +#line 16 "foobar.h" +#line 17 "/a/b/c/baz.h" +#line 18 "dr2580.C" +#line 0 "dr2580.C" // { dg-error "line number out of range" } +#line 20 +#line 2147483648 "dr2580.C" // { dg-error "line number out of range" } +#line 22 +#line 4294967295 "dr2580.C" // { dg-error "line number out of range" } +#line 24 +#line 12345678912345 "dr2580.C" // { dg-error "line number out of range" } +#line 26 +#line 27 1 // { dg-error "'1' is not a valid filename" } +#line 28 +#line 29 foo bar baz // { dg-error "'foo' is not a valid filename" } +#line 30 +#line 31 "dr2580.C" 1 // { dg-error "extra tokens at end of '#line' directive" } +#line 32 +#line 33 "dr2580.C" foo bar baz // { dg-error "extra tokens at end of '#line' directive" } +#define A 35 +#line A +#define B 0 +#line B // { dg-error "line number out of range" } +#line 38 +#define C 2147483648 +#line C // { dg-error "line number out of range" } +#line 41 +#define D 4294967295 +#line D // { dg-error "line number out of range" } +#line 44 +#define E 12345678912345 +#line E // { dg-error "line number out of range" } +#line 47 +#define F 49 "dr2580.C" +#line F +#define G 0 "dr2580.C" +#line G // { dg-error "line number out of range" } +#line 52 "dr2580.C" +#define H 2147483647 "dr2580.C" +#line H // { dg-error "line number out of range" "" { target c++98_only } } +#line 55 +#define I 2147483648 "dr2580.C" +#line I // { dg-error "line number out of range" } +#line 58 +#define J 4294967295 "dr2580.C" +#line J // { dg-error "line number out of range" } +#line 61 +#define K 12345678912345 "dr2580.C" +#line K // { dg-error "line number out of range" } +#line 64 +#define M 7 0 +#line M // { dg-error "'0' is not a valid filename" } +#line 67 +#define N 90 foo bar baz +#line N // { dg-error "'foo' is not a valid filename" } +#line 70 +#define O 75 "dr2580.C" 2 +#line O // { dg-error "extra tokens at end of '#line' directive" } +#line 73 +#define P 90 "dr2580.C" foo bar baz +#line P // { dg-error "extra tokens at end of '#line' directive" } +#line 76 +#line -5 // { dg-error "'-' after '#line' is not a positive integer" } +#line 78 +#line -7 "dr2580.C" // { dg-error "'-' after '#line' is not a positive integer" } +#line 80 +#line 32767 +#line 82 +#line 32768 // { dg-error "line number out of range" "" { target c++98_only } } +#line 84 +#line 32767 "dr2580.C" +#line 86 +#line 32768 "dr2580.C" // { dg-error "line number out of range" "" { target c++98_only } } +#line 88 diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new5.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new5.C new file mode 100644 index 0000000..b98b9e9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new5.C @@ -0,0 +1,43 @@ +// PR c++/121068 +// { dg-do compile { target c++26 } } + +#include <new> + +struct S +{ + constexpr S() = default; + constexpr S(int x) : s(x) {} + constexpr S(S&& x) : s(x.s) {} + constexpr S& operator=(S&& x) { s = x.s; return *this; } + unsigned char s; +}; + +constexpr +int foo() +{ + union { S a[20]; }; + new (&a) S[20](); // OK + for (int i = 0; i < 20; ++i) + a[i].~S(); + + auto* sf = ::new(&a[2]) S(11); + return 1; +} + +static_assert(foo()); + +constexpr +int foo2() +{ + union { S a[20]; }; + new (&a) S[20]; // ILL-FORMED + for (int i = 0; i < 20; ++i) + a[i].~S(); + + auto* sf = ::new(&a[2]) S(11); + return 1; +} + +static_assert(foo2()); + +auto p = foo2; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using5.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using5.C new file mode 100644 index 0000000..d42b8a0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using5.C @@ -0,0 +1,19 @@ +// PR c++/121351 +// { dg-do compile { target c++20 } } + +template<class T> concept C = true; + +template<class T> +struct A { + template<class U> void f(U) requires C<T> = delete; // #1 +}; + +struct B : A<int> { + using A::f; + template<class U> void f(U) requires C<int>; // #2 +}; + +int main() { + B b; + b.f(42); // OK, #2 corresponds to and therefore hides #1 +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using5a.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using5a.C new file mode 100644 index 0000000..5d31948 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using5a.C @@ -0,0 +1,20 @@ +// PR c++/121351 +// { dg-do compile { target c++20 } } +// A version of concepts-using5a.C where B instead of A is a template. + +template<class T> concept C = true; + +struct A { + template<class U> void f(U) requires C<int> = delete; // #1 +}; + +template<class T> +struct B : A { + using A::f; + template<class U> void f(U) requires C<T>; // #2 +}; + +int main() { + B<int> b; + b.f(42); // OK, #2 corresponds to and therefore hides #1 +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-using6.C b/gcc/testsuite/g++.dg/cpp2a/concepts-using6.C new file mode 100644 index 0000000..a40519a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-using6.C @@ -0,0 +1,20 @@ +// PR c++/121351 +// { dg-do compile { target c++20 } } + +template<class T> concept C = true; + +template<class T> +struct A { + template<class U> void f(U) requires C<T>; // #1 +}; + +template<class T> +struct B : A<T*> { + using A<T*>::f; + template<class U> void f(U) requires C<T>; // #2 +}; + +int main() { + B<int> b; + b.f(42); // { dg-error "ambiguous" } #1 and #2 don't correspond +} diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic19.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic19.C new file mode 100644 index 0000000..27d167c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic19.C @@ -0,0 +1,10 @@ +// PR c++/120620 +// { dg-do compile } + +#include <cxxabi.h> + +struct A* a; + +void f() { + void* const p = abi::__dynamic_cast(&a, 0, 0, 42); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic1a.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic1a.C new file mode 100644 index 0000000..4077a47 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dynamic1a.C @@ -0,0 +1,6 @@ +// Test that including <cxxabi.h>, whence the actual abi:__dynamic_cast +// is declared, doesn't affect our constexpr dynamic_cast handling. +// { dg-do compile { target c++20 } } + +#include <cxxabi.h> +#include "constexpr-dynamic1.C" diff --git a/gcc/testsuite/g++.dg/modules/cpp-21.C b/gcc/testsuite/g++.dg/modules/cpp-21.C new file mode 100644 index 0000000..fdd0492 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/cpp-21.C @@ -0,0 +1,8 @@ +// PR c++/120845 +// { dg-do compile } +// { dg-additional-options "-fmodules" } + +export module pr120485 + [[foobarbaz]]; +// { dg-error "expected ';' before end of line" "" { target *-*-* } .-2 } +// { dg-warning "attribute ignored" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/gcc.dg/bitintext.h b/gcc/testsuite/gcc.dg/bitintext.h index 99fedb3..d5f2689d 100644 --- a/gcc/testsuite/gcc.dg/bitintext.h +++ b/gcc/testsuite/gcc.dg/bitintext.h @@ -4,6 +4,24 @@ do_copy (void *p, const void *q, __SIZE_TYPE__ r) __builtin_memcpy (p, q, r); } +/* Obtain the value of N from a _BitInt(N)-typed expression X + at compile time. */ +#define S(x) \ + ((typeof (x)) -1 < 0 \ + ? __builtin_clrsbg (__builtin_choose_expr ((typeof (x)) -1 < 0, \ + (typeof (x)) -1, -1)) + 1 \ + : __builtin_popcountg (__builtin_choose_expr ((typeof (x)) -1 < 0, \ + 0U, (typeof (x)) -1))) + +#define CEIL(x,y) (((x) + (y) - 1) / (y)) + +/* Promote a _BitInt type to include its padding bits. */ +#if defined (__s390x__) || defined(__arm__) +#define PROMOTED_SIZE(x) sizeof (x) +#elif defined(__loongarch__) +#define PROMOTED_SIZE(x) (sizeof (x) > 8 ? CEIL (S (x), 64) * 8 : sizeof (x)) +#endif + /* Macro to test whether (on targets where psABI requires it) _BitInt with padding bits have those filled with sign or zero extension. */ #if defined(__s390x__) || defined(__arm__) || defined(__loongarch__) @@ -11,14 +29,14 @@ do_copy (void *p, const void *q, __SIZE_TYPE__ r) do { \ if ((typeof (x)) -1 < 0) \ { \ - _BitInt(sizeof (x) * __CHAR_BIT__) __x; \ + _BitInt(PROMOTED_SIZE (x) * __CHAR_BIT__) __x; \ do_copy (&__x, &(x), sizeof (__x)); \ if (__x != (x)) \ __builtin_abort (); \ } \ else \ { \ - unsigned _BitInt(sizeof (x) * __CHAR_BIT__) __x; \ + unsigned _BitInt(PROMOTED_SIZE (x) * __CHAR_BIT__) __x; \ do_copy (&__x, &(x), sizeof (__x)); \ if (__x != (x)) \ __builtin_abort (); \ diff --git a/gcc/testsuite/gcc.dg/c23-attr-syntax-6.c b/gcc/testsuite/gcc.dg/c23-attr-syntax-6.c index f8c5b0f..4e6b80b 100644 --- a/gcc/testsuite/gcc.dg/c23-attr-syntax-6.c +++ b/gcc/testsuite/gcc.dg/c23-attr-syntax-6.c @@ -45,7 +45,7 @@ typedef int [[__extension__ __extension__]] b2; /* { dg-error {'extension' attri typedef int [[__extension__ unknown_attribute]] b3; /* { dg-error {'unknown_attribute' attribute ignored} } */ typedef int [[__extension__ gnu:vector_size(4)]] b4; /* { dg-error {expected '\]' before ':'} } */ /* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-1 } */ -typedef int [[__extension__ gnu JOIN2(:,:) vector_size (4)]] b5; /* { dg-error {pasting ":" and ":" does not give a valid preprocessing token} } */ +typedef int [[__extension__ gnu JOIN2(:,:) vector_size (4)]] b5; /* { dg-error {pasting ':' and ':' does not give a valid preprocessing token} } */ /* { dg-error {expected '\]' before ':'} "" { target *-*-* } .-1 } */ /* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-2 } */ typedef int [[__extension__ gnu : : vector_size (4)]] b6; /* { dg-error {expected '\]' before ':'} } */ @@ -81,7 +81,7 @@ typedef int [[gnu :: vector_size (4)]] b18; /* { dg-error {attributes before C23 typedef int [[gnu FOO vector_size (4)]] b19; /* { dg-error {attributes before C23} } */ typedef int [[gnu :: vector_size (sizeof (void (*)(...)))]] b20; /* { dg-error {attributes before C23} } */ /* { dg-error {requires a named argument before} "" { target *-*-* } .-1 } */ -typedef int [[gnu JOIN2(:,:) vector_size (4)]] b21; /* { dg-error {pasting ":" and ":" does not give a valid preprocessing token} } */ +typedef int [[gnu JOIN2(:,:) vector_size (4)]] b21; /* { dg-error {pasting ':' and ':' does not give a valid preprocessing token} } */ /* { dg-error {expected '\]' before ':'} "" { target *-*-* } .-1 } */ /* { dg-error {'gnu' attribute ignored} "" { target *-*-* } .-2 } */ /* { dg-error {attributes before C23} "" { target *-*-* } .-3 } */ diff --git a/gcc/testsuite/gcc.dg/cpp/paste12-2.c b/gcc/testsuite/gcc.dg/cpp/paste12-2.c index 6e2e4f1..f46645a 100644 --- a/gcc/testsuite/gcc.dg/cpp/paste12-2.c +++ b/gcc/testsuite/gcc.dg/cpp/paste12-2.c @@ -6,6 +6,6 @@ /* Test correct diagnostics when pasting in #include. Source: PR preprocessor/6780. */ -#define inc2(a,b) <##a.b> /* { dg-error "pasting \"<\" and \"stdio\" does not" } */ +#define inc2(a,b) <##a.b> /* { dg-error "pasting '<' and 'stdio' does not" } */ #define INC(X) inc2(X,h) #include INC(stdio) diff --git a/gcc/testsuite/gcc.dg/cpp/paste12.c b/gcc/testsuite/gcc.dg/cpp/paste12.c index 3e0f7b9..f6b3696 100644 --- a/gcc/testsuite/gcc.dg/cpp/paste12.c +++ b/gcc/testsuite/gcc.dg/cpp/paste12.c @@ -8,4 +8,4 @@ #define inc2(a,b) <##a.b> #define INC(X) inc2(X,h) -#include INC(stdio) /* { dg-error "pasting \"<\" and \"stdio\" does not" } */ +#include INC(stdio) /* { dg-error "pasting '<' and 'stdio' does not" } */ diff --git a/gcc/testsuite/gcc.dg/cpp/paste14-2.c b/gcc/testsuite/gcc.dg/cpp/paste14-2.c index 3b23ada..bb51999 100644 --- a/gcc/testsuite/gcc.dg/cpp/paste14-2.c +++ b/gcc/testsuite/gcc.dg/cpp/paste14-2.c @@ -4,8 +4,8 @@ { dg-do preprocess } */ -#define foo - ## >> /* { dg-error "pasting \"-\" and \">>\"" } */ +#define foo - ## >> /* { dg-error "pasting '-' and '>>'" } */ foo -#define bar = ## == /* { dg-error "pasting \"=\" and \"==\"" } */ +#define bar = ## == /* { dg-error "pasting '=' and '=='" } */ bar diff --git a/gcc/testsuite/gcc.dg/cpp/paste14.c b/gcc/testsuite/gcc.dg/cpp/paste14.c index 043d5e5..d60b328 100644 --- a/gcc/testsuite/gcc.dg/cpp/paste14.c +++ b/gcc/testsuite/gcc.dg/cpp/paste14.c @@ -5,6 +5,6 @@ */ #define foo - ## >> -foo /* { dg-error "pasting \"-\" and \">>\"" } */ +foo /* { dg-error "pasting '-' and '>>'" } */ #define bar = ## == -bar /* { dg-error "pasting \"=\" and \"==\"" } */ +bar /* { dg-error "pasting '=' and '=='" } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py index 11e5fd1..9ff4645 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py @@ -26,7 +26,7 @@ def test_result_graph(html_tree): assert message.attrib['id'] == 'gcc-diag-0-message' assert message[0].tag == make_tag('strong') - assert message[0].tail == ' this is a placeholder error, with graphs ' + assert message[0].tail == ' this is a placeholder error, with graphs' graph = diag.find("./xhtml:div[@class='gcc-directed-graph']", ns) assert graph is not None diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.c new file mode 100644 index 0000000..8ff7b35 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */ + +extern void foo (void); + +void test_nesting (void) +{ + foo (); /* { dg-error "top-level error" } */ +} + +/* Use a Python script to verify various properties about the generated + .html file: + { dg-final { run-html-pytest diagnostic-test-nesting-html.c "diagnostic-test-nesting-html.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.py new file mode 100644 index 0000000..3899ba5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.py @@ -0,0 +1,69 @@ +# Verify that nesting works in HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +def test_nesting(html_tree): + root = html_tree.getroot () + assert root.tag == make_tag('html') + + body = root.find('xhtml:body', ns) + assert body is not None + + diag_list = body.find('xhtml:div', ns) + assert diag_list is not None + assert diag_list.attrib['class'] == 'gcc-diagnostic-list' + + diag = diag_list.find('xhtml:div', ns) + assert diag is not None + + message = diag.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-0-message' + + assert message[0].tag == make_tag('strong') + assert message[0].tail == ' top-level error' + + # We expect 12 messages, with the given IDs and text: + for i in range(12): + child = diag.find(".//xhtml:div[@id='gcc-diag-%i']" % (i + 1), + ns) + assert child is not None + + message = child.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-%i-message' % (i + 1) + + if i % 4 == 0: + assert message.text == 'child %i' % (i / 4) + else: + assert message.text == 'grandchild %i %i' % ((i / 4), (i % 4) - 1) + + # We expect the messages to be organized into nested <ul> with + # "nesting-level" set, all below a <ul> + child_ul = diag.find("./xhtml:ul[@nesting-level='1']", ns) + assert child_ul is not None + msg_id = 1 + for i in range(3): + child_li = child_ul.find("./xhtml:li[@nesting-level='1'][%i]" % (i + 1), ns) + assert child_li is not None + child = child_li.find("./xhtml:div[@id='gcc-diag-%i']" % msg_id, ns) + assert child is not None + message = child.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-%i-message' % msg_id + assert message.text == 'child %i' % i + msg_id += 1 + grandchild_ul = child_ul.find("./xhtml:ul[@nesting-level='2'][%i]" % (i + 1), ns) + assert grandchild_ul is not None + for j in range(3): + grandchild_li = grandchild_ul.find("./xhtml:li[@nesting-level='2'][%i]" % (j + 1), ns) + assert grandchild_li is not None + grandchild = grandchild_li.find("./xhtml:div[@id='gcc-diag-%i']" % msg_id, ns) + assert grandchild is not None + message = grandchild.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-%i-message' % msg_id + assert message.text == 'grandchild %i %i' % (i, j) + msg_id += 1 diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index ce25c0a..3bb6063 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -116,6 +116,7 @@ set plugin_test_list [list \ diagnostic-test-nesting-text-indented.c \ diagnostic-test-nesting-text-indented-show-levels.c \ diagnostic-test-nesting-text-indented-unicode.c \ + diagnostic-test-nesting-html.c \ diagnostic-test-nesting-sarif.c } \ { diagnostic_plugin_test_paths.cc \ diagnostic-test-paths-1.c \ diff --git a/gcc/testsuite/gcc.dg/torture/pr121370.c b/gcc/testsuite/gcc.dg/torture/pr121370.c new file mode 100644 index 0000000..d40f3b2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr121370.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ + +int a; +int main() +{ + int c = -2147483647; + int d = -2147483647; + int e = 2147483647; + if (0) + f: + e = d + e - 2; +g: + if (d - c - e > 0) { + a = -c; + if (a + d) { + d = 1; + goto g; + } + return 0; + } + if (e) + goto f; + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr121382.c b/gcc/testsuite/gcc.dg/torture/pr121382.c new file mode 100644 index 0000000..20b49b1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr121382.c @@ -0,0 +1,23 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ + +int a, b, c; +__attribute__((noipa)) +static void d(int e, int f) +{ + if (e != 5 && e != 2147483647) + __builtin_abort(); + f = 2147483647; + do { + f = f - e; + if (c - 9 * f) { + __builtin_abort(); + } + } while (c); +} +__attribute__((noipa)) +int main(void) +{ + d(2147483647, 2147483647); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c new file mode 100644 index 0000000..61b93c0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */ + +struct s1 +{ + int t, t1; +}; + +struct s3 +{ + struct s1 t; +}; + +struct s2 +{ + struct s3 t; +}; + +void f(int, int); +void l(); +void g(int a, int b, int *p) +{ + struct s2 c; + { + struct s1 tmp = {a,b}; + struct s3 *t = &c.t; + t->t = tmp; + } + f(c.t.t.t, c.t.t.t1); +} + +/* { dg-final { scan-tree-dump "Replaced c.t.t.t1 with b" "fre1" } } */ +/* { dg-final { scan-tree-dump "Replaced c.t.t.t with a" "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c new file mode 100644 index 0000000..6da4201 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */ + +struct s1 +{ + int t, t1; +}; + +struct s3 +{ + struct s1 t; +}; + +struct s2 +{ + struct s3 t; +}; + +void f(int, int); +void l(); +void g(int a, int b, int *p) +{ + struct s2 c; + { + struct s1 tmp = {a,b}; + c.t.t = tmp; + } + struct s1 *t = &c.t.t; + f(t->t, t->t1); +} + +/* { dg-final { scan-tree-dump "Replaced \[^\r\n\]*.t1 with b" "fre1" } } */ +/* { dg-final { scan-tree-dump "Replaced \[^\r\n\]*.t with a" "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr59984.c b/gcc/testsuite/gcc.dg/vect/pr59984.c index c00c2267..8ca446e 100644 --- a/gcc/testsuite/gcc.dg/vect/pr59984.c +++ b/gcc/testsuite/gcc.dg/vect/pr59984.c @@ -64,3 +64,7 @@ main () return 0; } +/* { dg-final { scan-tree-dump "31:17: optimized: loop vectorized" "vect" } } */ +/* { dg-final { scan-tree-dump "37:7: optimized: loop vectorized" "vect" } } */ +/* { dg-final { scan-tree-dump "44:17: optimized: loop vectorized" "vect" } } */ +/* { dg-final { scan-tree-dump "50:7: optimized: loop vectorized" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acge_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acge_1.c new file mode 100644 index 0000000..37428a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acge_1.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** facge p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svacge (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** facge p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svacge (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** facge p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svacge (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** facge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svacge (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** facge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svacge (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** facge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svacge (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** facge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svacge (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acgt_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acgt_1.c new file mode 100644 index 0000000..5829369 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acgt_1.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** facgt p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svacgt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** facgt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svacgt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** facgt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svacgt (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** facgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svacgt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** facgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svacgt (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** facgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svacgt (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** facgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svacgt (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acle_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acle_1.c new file mode 100644 index 0000000..bd5200e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/acle_1.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** facle p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svacle (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** facle p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svacle (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** facle p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svacle (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** facle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svacle (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** facle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svacle (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** facle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svacle (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** facle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svacle (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/aclt_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/aclt_1.c new file mode 100644 index 0000000..876aba9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/aclt_1.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** faclt p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svaclt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** faclt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svaclt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** faclt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svaclt (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** faclt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svaclt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** faclt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svaclt (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** faclt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svaclt (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** faclt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svaclt (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c index dd8f6c4..d6aabc8 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_1.c @@ -18,5 +18,57 @@ test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) return svptest_any (pg, res); } -/* { dg-final { scan-assembler-times {\tcmpeq\t} 2 } } */ +void +test3 (svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpeq_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svint8_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpeq_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpeq_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpeq_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint32_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpeq_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint32_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpeq_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpeq\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ /* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c index 028d375..df98d27 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_2.c @@ -33,6 +33,108 @@ test4 (svbool_t pg, svint8_t x, int *any) return svptest_any (pg, res); } -/* { dg-final { scan-assembler-times {\tcmpeq\t} 4 } } */ -/* { dg-final { scan-assembler-times {\tcmpeq\t[^\n]*, #10} 2 } } */ +void +test5 (svint16_t x, svint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpeq (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpeq (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpeq (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpeq (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svint32_t x, svint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpeq (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpeq (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpeq (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpeq (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svint64_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpeq (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpeq (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpeq (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpeq (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpeq\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmpeq\t[^\n]*, #10} 8 } } */ /* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_4.c new file mode 100644 index 0000000..8e4b931 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_4.c @@ -0,0 +1,157 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpeq p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpeq (pg, x, y), p0); +} + +/* +** test2: +** cmpeq p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpeq (pg, x, y), p0); +} + +/* +** test3: +** cmpeq p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpeq (pg, x, y), pg); +} + +/* +** test4: +** cmpeq p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test4 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpeq (pg, x, 10), p0); +} + +/* +** test5: +** cmpeq p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test5 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpeq (pg, x, 10), p0); +} + +/* +** test6: +** cmpeq p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test6 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpeq (pg, x, 10), pg); +} + +/* +** test7: +** cmpeq p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpeq (pg, x, y), p0); +} + +/* +** test8: +** cmpeq p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpeq (pg, x, 10), p0); +} + +/* +** test9: +** cmpeq p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpeq (pg, x, y), p0); +} + +/* +** test10: +** cmpeq p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpeq (pg, x, 10), p0); +} + +/* +** test11: +** cmpeq p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpeq (pg, x, y), p0); +} + +/* +** test12: +** cmpeq p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpeq (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_5.c new file mode 100644 index 0000000..2958bc2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_5.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpeq p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svint16_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmpeq p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmpeq p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_6.c new file mode 100644 index 0000000..9233de9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpeq_6.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmeq p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmeq p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmeq p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmeq p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmeq p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpeq (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmeq p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpeq (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmeq p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpeq (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_1.c new file mode 100644 index 0000000..f6bb3c8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_1.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint8_t y, int *any) +{ + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svint8_t x, int *any) +{ + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svint32_t x, svint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svint64_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpge\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmpge\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_2.c new file mode 100644 index 0000000..fc92291 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_2.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint8_t y, int *any) +{ + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svuint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svuint8_t x, int *any) +{ + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svuint32_t x, svuint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svuint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svuint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svuint64_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svuint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svuint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpge (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmphs\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmphs\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_3.c new file mode 100644 index 0000000..6d50df5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_3.c @@ -0,0 +1,169 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpge p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test2: +** cmpge p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, y), p0); +} + +/* +** test3: +** cmpge p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, y), pg); +} + +/* +** test4: +** ( +** cmpge p0\.b, p0/z, z0\.b, #10 +** | +** cmpgt p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test4 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +/* +** test5: +** ( +** cmpge p0\.b, p0/z, z0\.b, #10 +** | +** cmpgt p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test5 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, 10), p0); +} + +/* +** test6: +** ( +** cmpge p0\.b, p0/z, z0\.b, #10 +** | +** cmpgt p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test6 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, 10), pg); +} + +/* +** test7: +** cmpge p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test8: +** cmpge p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +/* +** test9: +** cmpge p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test10: +** cmpge p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +/* +** test11: +** cmpge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test12: +** cmpge p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_4.c new file mode 100644 index 0000000..2430e80 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_4.c @@ -0,0 +1,169 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmphs p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test2: +** cmphs p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, y), p0); +} + +/* +** test3: +** cmphs p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, y), pg); +} + +/* +** test4: +** ( +** cmphs p0\.b, p0/z, z0\.b, #10 +** | +** cmphi p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test4 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +/* +** test5: +** ( +** cmphs p0\.b, p0/z, z0\.b, #10 +** | +** cmphi p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test5 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, 10), p0); +} + +/* +** test6: +** ( +** cmphs p0\.b, p0/z, z0\.b, #10 +** | +** cmphi p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test6 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpge (pg, x, 10), pg); +} + +/* +** test7: +** cmphs p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test8: +** cmphs p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +/* +** test9: +** cmphs p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test10: +** cmphs p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svuint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +/* +** test11: +** cmphs p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpge (pg, x, y), p0); +} + +/* +** test12: +** cmphs p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svuint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpge (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_5.c new file mode 100644 index 0000000..f4fa758 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_5.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) +{ + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svint8_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint32_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint32_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpge\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_6.c new file mode 100644 index 0000000..979db4c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_6.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint64_t y, int *any) +{ + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svuint8_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint32_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint32_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpge_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmphs\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_7.c new file mode 100644 index 0000000..d6abab0 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_7.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpge p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svint16_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmpge p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmpge p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_8.c new file mode 100644 index 0000000..70be917 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_8.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmphs p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svuint16_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmphs p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmphs p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_9.c new file mode 100644 index 0000000..0d4140e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpge_9.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmge p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmge p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmge p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpge (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpge (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmge p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpge (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_1.c new file mode 100644 index 0000000..6c28d6f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_1.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint8_t y, int *any) +{ + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svint8_t x, int *any) +{ + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svint32_t x, svint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svint64_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpgt\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmpgt\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_2.c new file mode 100644 index 0000000..2160484 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_2.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint8_t y, int *any) +{ + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svuint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svuint8_t x, int *any) +{ + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svuint32_t x, svuint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svuint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svuint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svuint64_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svuint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svuint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpgt (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmphi\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmphi\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_3.c new file mode 100644 index 0000000..cc48b7e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_3.c @@ -0,0 +1,157 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpgt p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test2: +** cmpgt p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, y), p0); +} + +/* +** test3: +** cmpgt p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, y), pg); +} + +/* +** test4: +** cmpgt p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test4 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +/* +** test5: +** cmpgt p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test5 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, 10), p0); +} + +/* +** test6: +** cmpgt p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test6 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, 10), pg); +} + +/* +** test7: +** cmpgt p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test8: +** cmpgt p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +/* +** test9: +** cmpgt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test10: +** cmpgt p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +/* +** test11: +** cmpgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test12: +** cmpgt p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_4.c new file mode 100644 index 0000000..bd49fe8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_4.c @@ -0,0 +1,157 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmphi p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test2: +** cmphi p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, y), p0); +} + +/* +** test3: +** cmphi p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, y), pg); +} + +/* +** test4: +** cmphi p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test4 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +/* +** test5: +** cmphi p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test5 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, 10), p0); +} + +/* +** test6: +** cmphi p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test6 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpgt (pg, x, 10), pg); +} + +/* +** test7: +** cmphi p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test8: +** cmphi p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +/* +** test9: +** cmphi p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test10: +** cmphi p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svuint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +/* +** test11: +** cmphi p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpgt (pg, x, y), p0); +} + +/* +** test12: +** cmphi p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svuint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpgt (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_5.c new file mode 100644 index 0000000..f9f4c7d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_5.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) +{ + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svint8_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint32_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint32_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpgt\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_6.c new file mode 100644 index 0000000..6df15b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_6.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint64_t y, int *any) +{ + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svuint8_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint32_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint32_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpgt_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmphi\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_7.c new file mode 100644 index 0000000..0656b29 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_7.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpgt p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svint16_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmpgt p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmpgt p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_8.c new file mode 100644 index 0000000..b0a9ac8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_8.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmphi p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svuint16_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmphi p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmphi p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_9.c new file mode 100644 index 0000000..dcd84f7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpgt_9.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmgt p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmgt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmgt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpgt (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpgt (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmgt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpgt (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_1.c new file mode 100644 index 0000000..f2d7d2b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_1.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint8_t y, int *any) +{ + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svint8_t x, int *any) +{ + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svint32_t x, svint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svint64_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmple\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmple\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_2.c new file mode 100644 index 0000000..9d13d7a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_2.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint8_t y, int *any) +{ + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svuint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svuint8_t x, int *any) +{ + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svuint32_t x, svuint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svuint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svuint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svuint64_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svuint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svuint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmple (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpls\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmpls\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_3.c new file mode 100644 index 0000000..7a9326c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_3.c @@ -0,0 +1,157 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmple p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test2: +** cmple p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, y), p0); +} + +/* +** test3: +** cmple p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, y), pg); +} + +/* +** test4: +** cmple p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test4 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +/* +** test5: +** cmple p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test5 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, 10), p0); +} + +/* +** test6: +** cmple p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test6 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, 10), pg); +} + +/* +** test7: +** cmple p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test8: +** cmple p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +/* +** test9: +** cmple p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test10: +** cmple p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +/* +** test11: +** cmple p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test12: +** cmple p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_4.c new file mode 100644 index 0000000..aca4385 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_4.c @@ -0,0 +1,157 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpls p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test2: +** cmpls p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, y), p0); +} + +/* +** test3: +** cmpls p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, y), pg); +} + +/* +** test4: +** cmpls p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test4 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +/* +** test5: +** cmpls p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test5 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, 10), p0); +} + +/* +** test6: +** cmpls p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test6 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmple (pg, x, 10), pg); +} + +/* +** test7: +** cmpls p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test8: +** cmpls p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +/* +** test9: +** cmpls p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test10: +** cmpls p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svuint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +/* +** test11: +** cmpls p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmple (pg, x, y), p0); +} + +/* +** test12: +** cmpls p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svuint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmple (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_5.c new file mode 100644 index 0000000..1caf496 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_5.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) +{ + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svint8_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint32_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint32_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmple\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_6.c new file mode 100644 index 0000000..ae85e89 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_6.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint64_t y, int *any) +{ + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svuint8_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint32_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint32_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmple_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpls\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_7.c new file mode 100644 index 0000000..3f3ea53 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_7.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmple p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svint16_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmple p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmple p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_8.c new file mode 100644 index 0000000..01281ca --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_8.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpls p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svuint16_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmpls p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmpls p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_9.c new file mode 100644 index 0000000..8d008b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmple_9.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmle p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmple (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmle p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmple (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmle p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmple (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmple (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmple (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmle p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmple (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_1.c new file mode 100644 index 0000000..a15bb4a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_1.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint8_t y, int *any) +{ + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svint8_t x, int *any) +{ + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svint32_t x, svint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svint64_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmplt\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmplt\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_2.c new file mode 100644 index 0000000..43c53a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_2.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint8_t y, int *any) +{ + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svuint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svuint8_t x, int *any) +{ + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svuint32_t x, svuint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svuint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svuint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svuint64_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svuint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svuint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmplt (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmplo\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmplo\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_3.c new file mode 100644 index 0000000..bddbbeb --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_3.c @@ -0,0 +1,169 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmplt p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test2: +** cmplt p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, y), p0); +} + +/* +** test3: +** cmplt p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, y), pg); +} + +/* +** test4: +** ( +** cmplt p0\.b, p0/z, z0\.b, #10 +** | +** cmple p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test4 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +/* +** test5: +** ( +** cmplt p0\.b, p0/z, z0\.b, #10 +** | +** cmple p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test5 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, 10), p0); +} + +/* +** test6: +** ( +** cmplt p0\.b, p0/z, z0\.b, #10 +** | +** cmple p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test6 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, 10), pg); +} + +/* +** test7: +** cmplt p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test8: +** cmplt p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +/* +** test9: +** cmplt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test10: +** cmplt p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +/* +** test11: +** cmplt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test12: +** cmplt p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_4.c new file mode 100644 index 0000000..b71c8e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_4.c @@ -0,0 +1,169 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmplo p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test2: +** cmplo p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, y), p0); +} + +/* +** test3: +** cmplo p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svuint8_t x, svuint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, y), pg); +} + +/* +** test4: +** ( +** cmplo p0\.b, p0/z, z0\.b, #10 +** | +** cmpls p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test4 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +/* +** test5: +** ( +** cmplo p0\.b, p0/z, z0\.b, #10 +** | +** cmpls p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test5 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, 10), p0); +} + +/* +** test6: +** ( +** cmplo p0\.b, p0/z, z0\.b, #10 +** | +** cmpls p0\.b, p0/z, z0\.b, #9 +** ) +** ret +*/ +svbool_t +test6 (svbool_t p0, svuint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmplt (pg, x, 10), pg); +} + +/* +** test7: +** cmplo p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svuint16_t x, svuint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test8: +** cmplo p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svuint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +/* +** test9: +** cmplo p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svuint32_t x, svuint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test10: +** cmplo p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svuint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +/* +** test11: +** cmplo p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svuint64_t x, svuint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmplt (pg, x, y), p0); +} + +/* +** test12: +** cmplo p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svuint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmplt (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_5.c new file mode 100644 index 0000000..6885e4d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_5.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) +{ + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svint8_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint32_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint32_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmplt\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_6.c new file mode 100644 index 0000000..e9be9e8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_6.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svuint8_t x, svuint64_t y, int *any) +{ + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svuint8_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svuint8_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svuint16_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svuint16_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svuint32_t x, svuint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svuint32_t x, svuint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmplt_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmplo\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_7.c new file mode 100644 index 0000000..a4de6ab --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_7.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmplt p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svint16_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmplt p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmplt p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_8.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_8.c new file mode 100644 index 0000000..0a095eb --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_8.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmplo p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svuint16_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmplo p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmplo p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svuint32_t x, svuint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_9.c new file mode 100644 index 0000000..4f4b7b4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmplt_9.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmlt p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmlt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmlt p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmlt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmlt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmplt (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmlt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmplt (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmlt p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmplt (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_1.c new file mode 100644 index 0000000..61f7718 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_1.c @@ -0,0 +1,140 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint8_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpne (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint8_t y, int *any) +{ + svbool_t res = svcmpne (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svbool_t pg, svint8_t x, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpne (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svbool_t pg, svint8_t x, int *any) +{ + svbool_t res = svcmpne (pg, x, 10); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint16_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpne (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpne (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint16_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpne (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpne (pg, x, 10); + return svptest_any (pg, res); +} + +void +test9 (svint32_t x, svint32_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpne (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test10 (svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpne (pg, x, y); + return svptest_any (pg, res); +} + +void +test11 (svint32_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpne (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test12 (svint32_t x) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpne (pg, x, 10); + return svptest_any (pg, res); +} + +void +test13 (svint64_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpne (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test14 (svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpne (pg, x, y); + return svptest_any (pg, res); +} + +void +test15 (svint64_t x, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpne (pg, x, 10); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test16 (svint64_t x) +{ + svbool_t pg = svptrue_b64 (); + svbool_t res = svcmpne (pg, x, 10); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpne\t} 16 } } */ +/* { dg-final { scan-assembler-times {\tcmpne\t[^\n]*, #10} 8 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_2.c new file mode 100644 index 0000000..53cedb3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_2.c @@ -0,0 +1,157 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpne p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test1 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpne (pg, x, y), p0); +} + +/* +** test2: +** cmpne p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test2 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpne (pg, x, y), p0); +} + +/* +** test3: +** cmpne p0\.b, p0/z, z0\.b, z1\.b +** ret +*/ +svbool_t +test3 (svbool_t p0, svint8_t x, svint8_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpne (pg, x, y), pg); +} + +/* +** test4: +** cmpne p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test4 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpne (pg, x, 10), p0); +} + +/* +** test5: +** cmpne p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test5 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpne (pg, x, 10), p0); +} + +/* +** test6: +** cmpne p0\.b, p0/z, z0\.b, #10 +** ret +*/ +svbool_t +test6 (svbool_t p0, svint8_t x) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (p0, svcmpne (pg, x, 10), pg); +} + +/* +** test7: +** cmpne p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test7 (svbool_t p0, svint16_t x, svint16_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpne (pg, x, y), p0); +} + +/* +** test8: +** cmpne p0\.h, p0/z, z0\.h, #10 +** ret +*/ +svbool_t +test8 (svbool_t p0, svint16_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpne (pg, x, 10), p0); +} + +/* +** test9: +** cmpne p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test9 (svbool_t p0, svint32_t x, svint32_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpne (pg, x, y), p0); +} + +/* +** test10: +** cmpne p0\.s, p0/z, z0\.s, #10 +** ret +*/ +svbool_t +test10 (svbool_t p0, svint32_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpne (pg, x, 10), p0); +} + +/* +** test11: +** cmpne p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test11 (svbool_t p0, svint64_t x, svint64_t y) +{ + svbool_t pg = svptrue_b8 (); + return svand_z (pg, svcmpne (pg, x, y), p0); +} + +/* +** test12: +** cmpne p0\.d, p0/z, z0\.d, #10 +** ret +*/ +svbool_t +test12 (svbool_t p0, svint64_t x) +{ + svbool_t pg = svptrue_b16 (); + return svand_z (pg, svcmpne (pg, x, 10), p0); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_3.c new file mode 100644 index 0000000..c5c3936 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_3.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +void +test1 (svbool_t pg, svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t res = svcmpne_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test2 (svbool_t pg, svint8_t x, svint64_t y, int *any) +{ + svbool_t res = svcmpne_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test3 (svint8_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpne_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test4 (svint8_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b8 (); + svbool_t res = svcmpne_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test5 (svint16_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpne_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test6 (svint16_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b16 (); + svbool_t res = svcmpne_wide (pg, x, y); + return svptest_any (pg, res); +} + +void +test7 (svint32_t x, svint64_t y, int *any, svbool_t *ptr) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpne_wide (pg, x, y); + *any = svptest_any (pg, res); + *ptr = res; +} + +int +test8 (svint32_t x, svint64_t y, int *any) +{ + svbool_t pg = svptrue_b32 (); + svbool_t res = svcmpne_wide (pg, x, y); + return svptest_any (pg, res); +} + +/* { dg-final { scan-assembler-times {\tcmpne\t} 8 } } */ +/* { dg-final { scan-assembler-times {\tptrue\t} 6 } } */ +/* { dg-final { scan-assembler-not {\tptest\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_4.c new file mode 100644 index 0000000..595e024 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_4.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** cmpne p0\.h, p0/z, z0\.h, z1\.d +** ret +*/ +svbool_t +test1 (svbool_t pg, svint16_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** cmpne p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test2 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne_wide (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** cmpne p0\.s, p0/z, z0\.s, z1\.d +** ret +*/ +svbool_t +test3 (svbool_t pg, svint32_t x, svint64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne_wide (pg, x, y), + svptrue_b32 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_5.c new file mode 100644 index 0000000..94fecd8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpne_5.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmne p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmne p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmne p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmne p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmne p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpne (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmne p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpne (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmne p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpne (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpuo_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpuo_1.c new file mode 100644 index 0000000..4b124b3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cmpuo_1.c @@ -0,0 +1,104 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** fcmuo p0\.h, p0/z, z0\.h, z1\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svfloat16_t x, svfloat16_t y) +{ + return svand_z (svptrue_b8 (), + svcmpuo (pg, x, y), + svptrue_b16 ()); +} + +/* +** test2: +** fcmuo p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test2 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpuo (pg, x, y), + svptrue_b16 ()); +} + +/* +** test3: +** fcmuo p0\.s, p0/z, z0\.s, z1\.s +** ret +*/ +svbool_t +test3 (svbool_t pg, svfloat32_t x, svfloat32_t y) +{ + return svand_z (svptrue_b8 (), + svcmpuo (pg, x, y), + svptrue_b32 ()); +} + +/* +** test4: +** fcmuo p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test4 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpuo (pg, x, y), + svptrue_b16 ()); +} + +/* +** test5: +** fcmuo p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test5 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpuo (pg, x, y), + svptrue_b8 ()); +} + +/* +** test6: +** fcmuo p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test6 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b8 (), + svcmpuo (pg, x, y), + svptrue_b64 ()); +} + +/* +** test7: +** fcmuo p0\.d, p0/z, z0\.d, z1\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svfloat64_t x, svfloat64_t y) +{ + return svand_z (svptrue_b32 (), + svcmpuo (pg, x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dup_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dup_1.c new file mode 100644 index 0000000..c3c4e2d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dup_1.c @@ -0,0 +1,47 @@ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t +test1 (int x) +{ + return svand_z (svptrue_b16 (), svdup_b16 (x), svptrue_b16 ()); +} + +svbool_t +test2 (int x) +{ + return svand_z (svptrue_b8 (), svdup_b32 (x), svptrue_b16 ()); +} + +svbool_t +test3 (int x) +{ + return svand_z (svptrue_b32 (), svdup_b32 (x), svptrue_b16 ()); +} + +svbool_t +test4 (int x) +{ + return svand_z (svptrue_b32 (), svdup_b32 (x), svptrue_b32 ()); +} + +svbool_t +test5 (int x) +{ + return svand_z (svptrue_b8 (), svdup_b64 (x), svptrue_b32 ()); +} + +svbool_t +test6 (int x) +{ + return svand_z (svptrue_b16 (), svdup_b64 (x), svptrue_b8 ()); +} + +svbool_t +test7 (int x) +{ + return svand_z (svptrue_b16 (), svdup_b64 (x), svptrue_b64 ()); +} + +/* { dg-final { scan-assembler-not {\tand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_13.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_13.c new file mode 100644 index 0000000..6d702b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_13.c @@ -0,0 +1,45 @@ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t +test1 (int x0, int x1) +{ + return svand_z (svptrue_b8 (), svdupq_b64 (x0, x1), svptrue_b16 ()); +} + +svbool_t +test2 (int x0, int x1, int x2, int x3) +{ + return svand_z (svptrue_b8 (), svdupq_b32 (x0, x1, x2, x3), svptrue_b16 ()); +} + +svbool_t +test3 (int x0, int x1, int x2, int x3) +{ + return svand_z (svptrue_b32 (), svdupq_b32 (x0, x1, x2, x3), svptrue_b16 ()); +} + +svbool_t +test4 (int x0, int x1, int x2, int x3) +{ + return svand_z (svptrue_b32 (), svdupq_b32 (x0, x1, x2, x3), svptrue_b32 ()); +} + +svbool_t +test5 (int x0, int x1, int x2, int x3) +{ + return svand_z (svptrue_b8 (), + svdupq_b16 (x0, x1, x2, x3, x2, x0, x1, x3), + svptrue_b32 ()); +} + +svbool_t +test6 (int x0, int x1, int x2, int x3) +{ + return svand_z (svptrue_b64 (), + svdupq_b16 (x0, x1, x2, x3, x2, x0, x1, x3), + svptrue_b16 ()); +} + +/* { dg-final { scan-assembler-not {\tand\tp} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_9.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_9.c new file mode 100644 index 0000000..e3f352b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/dupq_lane_9.c @@ -0,0 +1,8 @@ +/* { dg-options "-O2 -mbig-endian" } */ + +#pragma GCC aarch64 "arm_sve.h" + +svint32_t f(svint32_t x) { return svdupq_lane (x, 17); } +void g(svint32_t *a, svint32_t *b) { *a = svdupq_lane (*b, 17); } + +/* { dg-final { scan-assembler-not {\trevw\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_2.c new file mode 100644 index 0000000..9b3daaa --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_2.c @@ -0,0 +1,96 @@ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** ... +** ptrue (p[0-3])\.h, all +** ... +** trn1 p0\.h, p[0-3]\.h, \1\.h +** ret +*/ +svbool_t +test1 () +{ + return svtrn1_b16 (svptrue_b8 (), svptrue_b16 ()); +} + +/* +** test2: +** ... +** ptrue (p[0-3])\.h, all +** ... +** trn1 p0\.h, \1\.h, p[0-3]\.h +** ret +*/ +svbool_t +test2 () +{ + return svtrn1_b16 (svptrue_b16 (), svptrue_b8 ()); +} + +/* +** test3: +** ... +** ptrue (p[0-3])\.s, all +** ... +** trn1 p0\.s, p[0-3]\.s, \1\.s +** ret +*/ +svbool_t +test3 () +{ + return svtrn1_b32 (svptrue_b8 (), svptrue_b32 ()); +} + +/* +** test4: +** ... +** ptrue (p[0-3])\.s, all +** ... +** trn1 p0\.s, \1\.s, p[0-3]\.s +** ret +*/ +svbool_t +test4 () +{ + return svtrn1_b32 (svptrue_b32 (), svptrue_b8 ()); +} + +/* +** test5: +** ... +** ptrue (p[0-3])\.d, all +** ... +** trn1 p0\.d, p[0-3]\.d, \1\.d +** ret +*/ +svbool_t +test5 () +{ + return svtrn1_b64 (svptrue_b8 (), svptrue_b64 ()); +} + +/* +** test6: +** ... +** ptrue (p[0-3])\.d, all +** ... +** trn1 p0\.d, \1\.d, p[0-3]\.d +** ret +*/ +svbool_t +test6 () +{ + return svtrn1_b64 (svptrue_b64 (), svptrue_b8 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_3.c new file mode 100644 index 0000000..678c541 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_3.c @@ -0,0 +1,96 @@ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** ... +** ptrue (p[0-3])\.h, all +** ... +** trn2 p0\.h, p[0-3]\.h, \1\.h +** ret +*/ +svbool_t +test1 () +{ + return svtrn2_b16 (svptrue_b8 (), svptrue_b16 ()); +} + +/* +** test2: +** ... +** ptrue (p[0-3])\.h, all +** ... +** trn2 p0\.h, \1\.h, p[0-3]\.h +** ret +*/ +svbool_t +test2 () +{ + return svtrn2_b16 (svptrue_b16 (), svptrue_b8 ()); +} + +/* +** test3: +** ... +** ptrue (p[0-3])\.s, all +** ... +** trn2 p0\.s, p[0-3]\.s, \1\.s +** ret +*/ +svbool_t +test3 () +{ + return svtrn2_b32 (svptrue_b8 (), svptrue_b32 ()); +} + +/* +** test4: +** ... +** ptrue (p[0-3])\.s, all +** ... +** trn2 p0\.s, \1\.s, p[0-3]\.s +** ret +*/ +svbool_t +test4 () +{ + return svtrn2_b32 (svptrue_b32 (), svptrue_b8 ()); +} + +/* +** test5: +** ... +** ptrue (p[0-3])\.d, all +** ... +** trn2 p0\.d, p[0-3]\.d, \1\.d +** ret +*/ +svbool_t +test5 () +{ + return svtrn2_b64 (svptrue_b8 (), svptrue_b64 ()); +} + +/* +** test6: +** ... +** ptrue (p[0-3])\.d, all +** ... +** trn2 p0\.d, \1\.d, p[0-3]\.d +** ret +*/ +svbool_t +test6 () +{ + return svtrn2_b64 (svptrue_b64 (), svptrue_b8 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_4.c new file mode 100644 index 0000000..28c6018 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_4.c @@ -0,0 +1,96 @@ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** ... +** ptrue (p[0-3])\.h, all +** ... +** zip1 p0\.h, p[0-3]\.h, \1\.h +** ret +*/ +svbool_t +test1 () +{ + return svzip1_b16 (svptrue_b8 (), svptrue_b16 ()); +} + +/* +** test2: +** ... +** ptrue (p[0-3])\.h, all +** ... +** zip1 p0\.h, \1\.h, p[0-3]\.h +** ret +*/ +svbool_t +test2 () +{ + return svzip1_b16 (svptrue_b16 (), svptrue_b8 ()); +} + +/* +** test3: +** ... +** ptrue (p[0-3])\.s, all +** ... +** zip1 p0\.s, p[0-3]\.s, \1\.s +** ret +*/ +svbool_t +test3 () +{ + return svzip1_b32 (svptrue_b8 (), svptrue_b32 ()); +} + +/* +** test4: +** ... +** ptrue (p[0-3])\.s, all +** ... +** zip1 p0\.s, \1\.s, p[0-3]\.s +** ret +*/ +svbool_t +test4 () +{ + return svzip1_b32 (svptrue_b32 (), svptrue_b8 ()); +} + +/* +** test5: +** ... +** ptrue (p[0-3])\.d, all +** ... +** zip1 p0\.d, p[0-3]\.d, \1\.d +** ret +*/ +svbool_t +test5 () +{ + return svzip1_b64 (svptrue_b8 (), svptrue_b64 ()); +} + +/* +** test6: +** ... +** ptrue (p[0-3])\.d, all +** ... +** zip1 p0\.d, \1\.d, p[0-3]\.d +** ret +*/ +svbool_t +test6 () +{ + return svzip1_b64 (svptrue_b64 (), svptrue_b8 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_5.c new file mode 100644 index 0000000..a8aec2b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_5.c @@ -0,0 +1,96 @@ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** ... +** ptrue (p[0-3])\.h, all +** ... +** zip2 p0\.h, p[0-3]\.h, \1\.h +** ret +*/ +svbool_t +test1 () +{ + return svzip2_b16 (svptrue_b8 (), svptrue_b16 ()); +} + +/* +** test2: +** ... +** ptrue (p[0-3])\.h, all +** ... +** zip2 p0\.h, \1\.h, p[0-3]\.h +** ret +*/ +svbool_t +test2 () +{ + return svzip2_b16 (svptrue_b16 (), svptrue_b8 ()); +} + +/* +** test3: +** ... +** ptrue (p[0-3])\.s, all +** ... +** zip2 p0\.s, p[0-3]\.s, \1\.s +** ret +*/ +svbool_t +test3 () +{ + return svzip2_b32 (svptrue_b8 (), svptrue_b32 ()); +} + +/* +** test4: +** ... +** ptrue (p[0-3])\.s, all +** ... +** zip2 p0\.s, \1\.s, p[0-3]\.s +** ret +*/ +svbool_t +test4 () +{ + return svzip2_b32 (svptrue_b32 (), svptrue_b8 ()); +} + +/* +** test5: +** ... +** ptrue (p[0-3])\.d, all +** ... +** zip2 p0\.d, p[0-3]\.d, \1\.d +** ret +*/ +svbool_t +test5 () +{ + return svzip2_b64 (svptrue_b8 (), svptrue_b64 ()); +} + +/* +** test6: +** ... +** ptrue (p[0-3])\.d, all +** ... +** zip2 p0\.d, \1\.d, p[0-3]\.d +** ret +*/ +svbool_t +test6 () +{ + return svzip2_b64 (svptrue_b64 (), svptrue_b8 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_6.c new file mode 100644 index 0000000..3405004 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_6.c @@ -0,0 +1,96 @@ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** ... +** ptrue (p[0-3])\.h, all +** ... +** uzp1 p0\.h, p[0-3]\.h, \1\.h +** ret +*/ +svbool_t +test1 () +{ + return svuzp1_b16 (svptrue_b8 (), svptrue_b16 ()); +} + +/* +** test2: +** ... +** ptrue (p[0-3])\.h, all +** ... +** uzp1 p0\.h, \1\.h, p[0-3]\.h +** ret +*/ +svbool_t +test2 () +{ + return svuzp1_b16 (svptrue_b16 (), svptrue_b8 ()); +} + +/* +** test3: +** ... +** ptrue (p[0-3])\.s, all +** ... +** uzp1 p0\.s, p[0-3]\.s, \1\.s +** ret +*/ +svbool_t +test3 () +{ + return svuzp1_b32 (svptrue_b8 (), svptrue_b32 ()); +} + +/* +** test4: +** ... +** ptrue (p[0-3])\.s, all +** ... +** uzp1 p0\.s, \1\.s, p[0-3]\.s +** ret +*/ +svbool_t +test4 () +{ + return svuzp1_b32 (svptrue_b32 (), svptrue_b8 ()); +} + +/* +** test5: +** ... +** ptrue (p[0-3])\.d, all +** ... +** uzp1 p0\.d, p[0-3]\.d, \1\.d +** ret +*/ +svbool_t +test5 () +{ + return svuzp1_b64 (svptrue_b8 (), svptrue_b64 ()); +} + +/* +** test6: +** ... +** ptrue (p[0-3])\.d, all +** ... +** uzp1 p0\.d, \1\.d, p[0-3]\.d +** ret +*/ +svbool_t +test6 () +{ + return svuzp1_b64 (svptrue_b64 (), svptrue_b8 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_7.c new file mode 100644 index 0000000..1758d00 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/perm_7.c @@ -0,0 +1,96 @@ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** ... +** ptrue (p[0-3])\.h, all +** ... +** uzp2 p0\.h, p[0-3]\.h, \1\.h +** ret +*/ +svbool_t +test1 () +{ + return svuzp2_b16 (svptrue_b8 (), svptrue_b16 ()); +} + +/* +** test2: +** ... +** ptrue (p[0-3])\.h, all +** ... +** uzp2 p0\.h, \1\.h, p[0-3]\.h +** ret +*/ +svbool_t +test2 () +{ + return svuzp2_b16 (svptrue_b16 (), svptrue_b8 ()); +} + +/* +** test3: +** ... +** ptrue (p[0-3])\.s, all +** ... +** uzp2 p0\.s, p[0-3]\.s, \1\.s +** ret +*/ +svbool_t +test3 () +{ + return svuzp2_b32 (svptrue_b8 (), svptrue_b32 ()); +} + +/* +** test4: +** ... +** ptrue (p[0-3])\.s, all +** ... +** uzp2 p0\.s, \1\.s, p[0-3]\.s +** ret +*/ +svbool_t +test4 () +{ + return svuzp2_b32 (svptrue_b32 (), svptrue_b8 ()); +} + +/* +** test5: +** ... +** ptrue (p[0-3])\.d, all +** ... +** uzp2 p0\.d, p[0-3]\.d, \1\.d +** ret +*/ +svbool_t +test5 () +{ + return svuzp2_b64 (svptrue_b8 (), svptrue_b64 ()); +} + +/* +** test6: +** ... +** ptrue (p[0-3])\.d, all +** ... +** uzp2 p0\.d, \1\.d, p[0-3]\.d +** ret +*/ +svbool_t +test6 () +{ + return svuzp2_b64 (svptrue_b64 (), svptrue_b8 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_3.c new file mode 100644 index 0000000..d9c0090 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pnext_3.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** pnext p0\.h, p1, p0\.h +** ret +*/ +svbool_t +test1 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b8 (), + svpnext_b16 (prev, pg), + svptrue_b16 ()); +} + +/* +** test2: +** pnext p0\.h, p1, p0\.h +** ret +*/ +svbool_t +test2 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b16 (), + svpnext_b16 (prev, pg), + svptrue_b8 ()); +} + +/* +** test3: +** pnext p0\.h, p1, p0\.h +** ret +*/ +svbool_t +test3 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b16 (), + svpnext_b16 (prev, pg), + svptrue_b16 ()); +} + +/* +** test4: +** pnext p0\.s, p1, p0\.s +** ret +*/ +svbool_t +test4 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b32 (), + svpnext_b32 (prev, pg), + svptrue_b8 ()); +} + +/* +** test5: +** pnext p0\.s, p1, p0\.s +** ret +*/ +svbool_t +test5 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b16 (), + svpnext_b32 (prev, pg), + svptrue_b8 ()); +} + +/* +** test6: +** pnext p0\.s, p1, p0\.s +** ret +*/ +svbool_t +test6 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b8 (), + svpnext_b32 (prev, pg), + svptrue_b32 ()); +} + +/* +** test7: +** pnext p0\.d, p1, p0\.d +** ret +*/ +svbool_t +test7 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b16 (), + svpnext_b64 (prev, pg), + svptrue_b8 ()); +} + +/* +** test8: +** pnext p0\.d, p1, p0\.d +** ret +*/ +svbool_t +test8 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b32 (), + svpnext_b64 (prev, pg), + svptrue_b8 ()); +} + +/* +** test9: +** pnext p0\.d, p1, p0\.d +** ret +*/ +svbool_t +test9 (svbool_t pg, svbool_t prev) +{ + return svand_z (svptrue_b8 (), + svpnext_b64 (prev, pg), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr121118_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr121118_1.c new file mode 100644 index 0000000..b59a972 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr121118_1.c @@ -0,0 +1,16 @@ +/* { dg-options "-O2 -msve-vector-bits=512" } */ + +typedef __SVBool_t fixed_bool __attribute__((arm_sve_vector_bits(512))); + +#define TEST_CONST(NAME, CONST) \ + fixed_bool \ + NAME () \ + { \ + union { unsigned long long i; fixed_bool pg; } u = { CONST }; \ + return u.pg; \ + } + +TEST_CONST (test1, 0x02aaaaaaaa) +TEST_CONST (test2, 0x0155555557) +TEST_CONST (test3, 0x0013333333333333ULL) +TEST_CONST (test4, 0x0011111111111113ULL) diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/rev_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/rev_2.c new file mode 100644 index 0000000..3dc4eb9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/rev_2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t test1() +{ + return svrev_b16 (svptrue_b16 ()); +} + +svbool_t test2() +{ + return svrev_b32 (svptrue_b32 ()); +} + +svbool_t test3() +{ + return svrev_b64 (svptrue_b64 ()); +} + +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.h} } } */ +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.s} } } */ +/* { dg-final { scan-assembler {\tptrue\tp[0-7]\.d} } } */ +/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.b} } } */ +/* { dg-final { scan-assembler {\trev\tp0\.h} } } */ +/* { dg-final { scan-assembler {\trev\tp0\.s} } } */ +/* { dg-final { scan-assembler {\trev\tp0\.d} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/unpkhi_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/unpkhi_1.c new file mode 100644 index 0000000..9c7b4bc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/unpkhi_1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t +test1 (svbool_t p) +{ + return svand_z (svptrue_b8 (), svunpkhi (p), svptrue_b16 ()); +} + +svbool_t +test2 (svbool_t p) +{ + return svand_z (svptrue_b16 (), svunpkhi (p), svptrue_b8 ()); +} + +svbool_t +test3 (svbool_t p) +{ + return svand_z (svptrue_b16 (), svunpkhi (p), svptrue_b16 ()); +} + +/* { dg-final { scan-assembler-not {\tand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/unpklo_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/unpklo_1.c new file mode 100644 index 0000000..f072a2f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/unpklo_1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t +test1 (svbool_t p) +{ + return svand_z (svptrue_b8 (), svunpklo (p), svptrue_b16 ()); +} + +svbool_t +test2 (svbool_t p) +{ + return svand_z (svptrue_b16 (), svunpklo (p), svptrue_b8 ()); +} + +svbool_t +test3 (svbool_t p) +{ + return svand_z (svptrue_b16 (), svunpklo (p), svptrue_b16 ()); +} + +/* { dg-final { scan-assembler-not {\tand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_13.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_13.c new file mode 100644 index 0000000..cf50dc1 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilele_13.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** whilele p0\.h, w0, w1 +** ret +*/ +svbool_t +test1 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilele_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test2: +** whilele p0\.h, x0, x1 +** ret +*/ +svbool_t +test2 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilele_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test3: +** whilels p0\.s, w0, w1 +** ret +*/ +svbool_t +test3 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilele_b32 (x, y), + svptrue_b16 ()); +} + +/* +** test4: +** whilels p0\.s, x0, x1 +** ret +*/ +svbool_t +test4 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b8 (), + svwhilele_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test5: +** whilele p0\.s, w0, w1 +** ret +*/ +svbool_t +test5 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b16 (), + svwhilele_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test6: +** whilels p0\.s, w0, w1 +** ret +*/ +svbool_t +test6 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b32 (), + svwhilele_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test7: +** whilels p0\.d, w0, w1 +** ret +*/ +svbool_t +test7 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilele_b64 (x, y), + svptrue_b64 ()); +} + +/* +** test8: +** whilele p0\.d, x0, x1 +** ret +*/ +svbool_t +test8 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilele_b64 (x, y), + svptrue_b32 ()); +} + +/* +** test9: +** whilels p0\.d, x0, x1 +** ret +*/ +svbool_t +test9 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b64 (), + svwhilele_b64 (x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_6.c new file mode 100644 index 0000000..27bf0c2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_6.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** whilelt p0\.h, w0, w1 +** ret +*/ +svbool_t +test1 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilelt_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test2: +** whilelt p0\.h, x0, x1 +** ret +*/ +svbool_t +test2 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilelt_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test3: +** whilelo p0\.s, w0, w1 +** ret +*/ +svbool_t +test3 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilelt_b32 (x, y), + svptrue_b16 ()); +} + +/* +** test4: +** whilelo p0\.s, x0, x1 +** ret +*/ +svbool_t +test4 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b8 (), + svwhilelt_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test5: +** whilelt p0\.s, w0, w1 +** ret +*/ +svbool_t +test5 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b16 (), + svwhilelt_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test6: +** whilelo p0\.s, w0, w1 +** ret +*/ +svbool_t +test6 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b32 (), + svwhilelt_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test7: +** whilelo p0\.d, w0, w1 +** ret +*/ +svbool_t +test7 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilelt_b64 (x, y), + svptrue_b64 ()); +} + +/* +** test8: +** whilelt p0\.d, x0, x1 +** ret +*/ +svbool_t +test8 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilelt_b64 (x, y), + svptrue_b32 ()); +} + +/* +** test9: +** whilelo p0\.d, x0, x1 +** ret +*/ +svbool_t +test9 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b64 (), + svwhilelt_b64 (x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_1.c b/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_1.c index 38dfdd4..e777f03 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_1.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mcpu=neoverse-n2" } */ +/* { dg-options "-O2 -mcpu=neoverse-n2 -fdisable-rtl-combine" } */ /* { dg-final { check-function-bodies "**" "" } } */ #pragma GCC target "+sve" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_2.c b/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_2.c index 45363cc..41182e1 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_2.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mcpu=neoverse-v2" } */ +/* { dg-options "-O2 -mcpu=neoverse-v2 -fdisable-rtl-combine" } */ /* { dg-final { check-function-bodies "**" "" } } */ #pragma GCC target "+sve" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_3.c b/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_3.c index c50a581..04a9023 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_3.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/pred_clobber_3.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -mcpu=neoverse-v1" } */ +/* { dg-options "-O2 -mcpu=neoverse-v1 -fdisable-rtl-combine" } */ /* { dg-final { check-function-bodies "**" "" } } */ #pragma GCC target "+sve" diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/match_4.c b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/match_4.c new file mode 100644 index 0000000..57f625b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/match_4.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t +test1 (svbool_t pg, svint16_t x, svint16_t y) +{ + return svand_z (svptrue_b8 (), + svmatch (pg, x, y), + svptrue_b16 ()); +} + +svbool_t +test2 (svbool_t pg, svint16_t x, svint16_t y) +{ + return svand_z (svptrue_b16 (), + svmatch (pg, x, y), + svptrue_b8 ()); +} + +svbool_t +test3 (svbool_t pg, svint16_t x, svint16_t y) +{ + return svand_z (svptrue_b16 (), + svmatch (pg, x, y), + svptrue_b16 ()); +} + +/* { dg-final { scan-assembler-not {\tand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/nmatch_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/nmatch_1.c new file mode 100644 index 0000000..a3b1e2d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/nmatch_1.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#include <arm_sve.h> + +svbool_t +test1 (svbool_t pg, svint16_t x, svint16_t y) +{ + return svand_z (svptrue_b8 (), + svnmatch (pg, x, y), + svptrue_b16 ()); +} + +svbool_t +test2 (svbool_t pg, svint16_t x, svint16_t y) +{ + return svand_z (svptrue_b16 (), + svnmatch (pg, x, y), + svptrue_b8 ()); +} + +svbool_t +test3 (svbool_t pg, svint16_t x, svint16_t y) +{ + return svand_z (svptrue_b16 (), + svnmatch (pg, x, y), + svptrue_b16 ()); +} + +/* { dg-final { scan-assembler-not {\tand\t} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilege_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilege_1.c new file mode 100644 index 0000000..07b56a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilege_1.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** whilege p0\.h, w0, w1 +** ret +*/ +svbool_t +test1 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilege_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test2: +** whilege p0\.h, x0, x1 +** ret +*/ +svbool_t +test2 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilege_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test3: +** whilehs p0\.s, w0, w1 +** ret +*/ +svbool_t +test3 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilege_b32 (x, y), + svptrue_b16 ()); +} + +/* +** test4: +** whilehs p0\.s, x0, x1 +** ret +*/ +svbool_t +test4 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b8 (), + svwhilege_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test5: +** whilege p0\.s, w0, w1 +** ret +*/ +svbool_t +test5 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b16 (), + svwhilege_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test6: +** whilehs p0\.s, w0, w1 +** ret +*/ +svbool_t +test6 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b32 (), + svwhilege_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test7: +** whilehs p0\.d, w0, w1 +** ret +*/ +svbool_t +test7 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilege_b64 (x, y), + svptrue_b64 ()); +} + +/* +** test8: +** whilege p0\.d, x0, x1 +** ret +*/ +svbool_t +test8 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilege_b64 (x, y), + svptrue_b32 ()); +} + +/* +** test9: +** whilehs p0\.d, x0, x1 +** ret +*/ +svbool_t +test9 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b64 (), + svwhilege_b64 (x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilegt_1.c b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilegt_1.c new file mode 100644 index 0000000..df707c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilegt_1.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** whilegt p0\.h, w0, w1 +** ret +*/ +svbool_t +test1 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilegt_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test2: +** whilegt p0\.h, x0, x1 +** ret +*/ +svbool_t +test2 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilegt_b16 (x, y), + svptrue_b16 ()); +} + +/* +** test3: +** whilehi p0\.s, w0, w1 +** ret +*/ +svbool_t +test3 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilegt_b32 (x, y), + svptrue_b16 ()); +} + +/* +** test4: +** whilehi p0\.s, x0, x1 +** ret +*/ +svbool_t +test4 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b8 (), + svwhilegt_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test5: +** whilegt p0\.s, w0, w1 +** ret +*/ +svbool_t +test5 (int32_t x, int32_t y) +{ + return svand_z (svptrue_b16 (), + svwhilegt_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test6: +** whilehi p0\.s, w0, w1 +** ret +*/ +svbool_t +test6 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b32 (), + svwhilegt_b32 (x, y), + svptrue_b32 ()); +} + +/* +** test7: +** whilehi p0\.d, w0, w1 +** ret +*/ +svbool_t +test7 (uint32_t x, uint32_t y) +{ + return svand_z (svptrue_b8 (), + svwhilegt_b64 (x, y), + svptrue_b64 ()); +} + +/* +** test8: +** whilegt p0\.d, x0, x1 +** ret +*/ +svbool_t +test8 (int64_t x, int64_t y) +{ + return svand_z (svptrue_b16 (), + svwhilegt_b64 (x, y), + svptrue_b32 ()); +} + +/* +** test9: +** whilehi p0\.d, x0, x1 +** ret +*/ +svbool_t +test9 (uint64_t x, uint64_t y) +{ + return svand_z (svptrue_b64 (), + svwhilegt_b64 (x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilerw_5.c b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilerw_5.c new file mode 100644 index 0000000..0c24199 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilerw_5.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** whilerw p0\.h, x0, x1 +** ret +*/ +svbool_t +test1 (int16_t *x, int16_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilerw (x, y), + svptrue_b16 ()); +} + +/* +** test2: +** whilerw p0\.h, x0, x1 +** ret +*/ +svbool_t +test2 (uint16_t *x, uint16_t *y) +{ + return svand_z (svptrue_b16 (), + svwhilerw (x, y), + svptrue_b16 ()); +} + +/* +** test3: +** whilerw p0\.s, x0, x1 +** ret +*/ +svbool_t +test3 (int32_t *x, int32_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilerw (x, y), + svptrue_b16 ()); +} + +/* +** test4: +** whilerw p0\.s, x0, x1 +** ret +*/ +svbool_t +test4 (uint32_t *x, uint32_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilerw (x, y), + svptrue_b32 ()); +} + +/* +** test5: +** whilerw p0\.s, x0, x1 +** ret +*/ +svbool_t +test5 (float32_t *x, float32_t *y) +{ + return svand_z (svptrue_b16 (), + svwhilerw (x, y), + svptrue_b32 ()); +} + +/* +** test6: +** whilerw p0\.s, x0, x1 +** ret +*/ +svbool_t +test6 (int32_t *x, int32_t *y) +{ + return svand_z (svptrue_b32 (), + svwhilerw (x, y), + svptrue_b32 ()); +} + +/* +** test7: +** whilerw p0\.d, x0, x1 +** ret +*/ +svbool_t +test7 (int64_t *x, int64_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilerw (x, y), + svptrue_b64 ()); +} + +/* +** test8: +** whilerw p0\.d, x0, x1 +** ret +*/ +svbool_t +test8 (uint64_t *x, uint64_t *y) +{ + return svand_z (svptrue_b16 (), + svwhilerw (x, y), + svptrue_b32 ()); +} + +/* +** test9: +** whilerw p0\.d, x0, x1 +** ret +*/ +svbool_t +test9 (float64_t *x, float64_t *y) +{ + return svand_z (svptrue_b64 (), + svwhilerw (x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilewr_5.c b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilewr_5.c new file mode 100644 index 0000000..38db9af --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/general/whilewr_5.c @@ -0,0 +1,130 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include <arm_sve.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** test1: +** whilewr p0\.h, x0, x1 +** ret +*/ +svbool_t +test1 (int16_t *x, int16_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilewr (x, y), + svptrue_b16 ()); +} + +/* +** test2: +** whilewr p0\.h, x0, x1 +** ret +*/ +svbool_t +test2 (uint16_t *x, uint16_t *y) +{ + return svand_z (svptrue_b16 (), + svwhilewr (x, y), + svptrue_b16 ()); +} + +/* +** test3: +** whilewr p0\.s, x0, x1 +** ret +*/ +svbool_t +test3 (int32_t *x, int32_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilewr (x, y), + svptrue_b16 ()); +} + +/* +** test4: +** whilewr p0\.s, x0, x1 +** ret +*/ +svbool_t +test4 (uint32_t *x, uint32_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilewr (x, y), + svptrue_b32 ()); +} + +/* +** test5: +** whilewr p0\.s, x0, x1 +** ret +*/ +svbool_t +test5 (float32_t *x, float32_t *y) +{ + return svand_z (svptrue_b16 (), + svwhilewr (x, y), + svptrue_b32 ()); +} + +/* +** test6: +** whilewr p0\.s, x0, x1 +** ret +*/ +svbool_t +test6 (int32_t *x, int32_t *y) +{ + return svand_z (svptrue_b32 (), + svwhilewr (x, y), + svptrue_b32 ()); +} + +/* +** test7: +** whilewr p0\.d, x0, x1 +** ret +*/ +svbool_t +test7 (int64_t *x, int64_t *y) +{ + return svand_z (svptrue_b8 (), + svwhilewr (x, y), + svptrue_b64 ()); +} + +/* +** test8: +** whilewr p0\.d, x0, x1 +** ret +*/ +svbool_t +test8 (uint64_t *x, uint64_t *y) +{ + return svand_z (svptrue_b16 (), + svwhilewr (x, y), + svptrue_b32 ()); +} + +/* +** test9: +** whilewr p0\.d, x0, x1 +** ret +*/ +svbool_t +test9 (float64_t *x, float64_t *y) +{ + return svand_z (svptrue_b64 (), + svwhilewr (x, y), + svptrue_b64 ()); +} + +#ifdef __cplusplus +} +#endif diff --git a/gcc/testsuite/gcc.target/avr/torture/pr118591-1.c b/gcc/testsuite/gcc.target/avr/torture/pr118591-1.c index 814f041..6f54c63 100644 --- a/gcc/testsuite/gcc.target/avr/torture/pr118591-1.c +++ b/gcc/testsuite/gcc.target/avr/torture/pr118591-1.c @@ -1,5 +1,5 @@ /* { dg-do run { target { ! avr_tiny } } } */ -/* { dg-additional-options "-std=c99 -mlra" } */ +/* { dg-additional-options "-std=c99" } */ __attribute__((noipa)) void func2 (long long a1, long long a2, long b) diff --git a/gcc/testsuite/gcc.target/avr/torture/pr118591-2.c b/gcc/testsuite/gcc.target/avr/torture/pr118591-2.c index 83d3606..222af09 100644 --- a/gcc/testsuite/gcc.target/avr/torture/pr118591-2.c +++ b/gcc/testsuite/gcc.target/avr/torture/pr118591-2.c @@ -1,6 +1,6 @@ /* Test case failed on avrtiny. */ /* { dg-do run } */ -/* { dg-additional-options "-std=c99 -mlra" } */ +/* { dg-additional-options "-std=c99" } */ __attribute__((noipa)) void func2 (long a, long b) diff --git a/gcc/testsuite/gcc.target/i386/pr120941-1.c b/gcc/testsuite/gcc.target/i386/pr120941-1.c new file mode 100644 index 0000000..b4fc6ac --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr120941-1.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -march=x86-64-v3" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target lp64 } {^\t?\.} } } */ + +/* +**bar: +**.LFB[0-9]+: +**... +** vbroadcastsd .LC4\(%rip\), %ymm2 +** leal 2\(%rbx\), %eax +** vbroadcastsd .LC2\(%rip\), %ymm4 +** negl %eax +**... +*/ + +extern void foo (int); + +enum { N_CELL_ENTRIES1 = 2 } +typedef LBM_Grid1[64]; +enum { N_CELL_ENTRIES2 = 2 } +typedef LBM_Grid2[64]; +LBM_Grid1 grid1; +LBM_Grid2 grid2; +extern int n; + +void +LBM_handleInOutFlow() +{ + int i, j; + for (; i; i += 2) + { + for (j = 0; j < n; j++) + { + grid1[i] = 1.0 / 36.0 * i; + grid2[i] = 1.0 / 36.0 * i; + } + } +} + +int main_t; +void +bar (void) +{ + for (; main_t; main_t++) { + LBM_handleInOutFlow(); + foo (main_t); + } +} diff --git a/gcc/testsuite/gcc.target/i386/pr121303.c b/gcc/testsuite/gcc.target/i386/pr121303.c new file mode 100644 index 0000000..7900bce --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr121303.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -favoid-store-forwarding" } */ + +typedef struct { + bool is_ssa; +} nir_src; + +nir_src nir_src_init; + +typedef struct { + nir_src src; + char swizzle[6]; +} nir_alu_src; + +void nir_src_bit_size(nir_src); + +void nir_lower_fb_read_instr() { + { + nir_alu_src alu_src = {nir_src_init}, src = alu_src; + nir_src_bit_size(src.src); + } + { + nir_alu_src alu_src = {nir_src_init}, src = alu_src; + nir_src_bit_size(src.src); + } +} diff --git a/gcc/testsuite/gcc.target/i386/pr121410.c b/gcc/testsuite/gcc.target/i386/pr121410.c new file mode 100644 index 0000000..04bab91 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr121410.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=x86-64 -mavx512f -mstore-max=128" } */ + +extern unsigned _BitInt(3719) a; +extern _BitInt(465) g; +void +foo(void) +{ + _BitInt(465) b = a >> 1860; + g = b + b; +} diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u32-from-u64.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u32-from-u64.c index 8d5449b..fa3758a 100644 --- a/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u32-from-u64.c +++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u32-from-u64.c @@ -9,3 +9,5 @@ DEF_SAT_U_MUL_FMT_1_WRAP(NT, WT) /* { dg-final { scan-tree-dump-times ".SAT_MUL" 1 "optimized" } } */ +/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */ +/* { dg-final { scan-assembler-times "mulhu" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u64-from-u128.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u64-from-u128.c index d8a01d1..b1bf4fa 100644 --- a/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u64-from-u128.c +++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_mul-1-u64-from-u128.c @@ -10,3 +10,4 @@ DEF_SAT_U_MUL_FMT_1_WRAP(NT, WT) /* { dg-final { scan-tree-dump-times ".SAT_MUL" 1 "optimized" } } */ /* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */ +/* { dg-final { scan-assembler-times "mulhu" 1 } } */ diff --git a/gcc/testsuite/gfortran.dg/pointer_assign_16.f90 b/gcc/testsuite/gfortran.dg/pointer_assign_16.f90 new file mode 100644 index 0000000..9282283 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pointer_assign_16.f90 @@ -0,0 +1,25 @@ +! { dg-do run } +! +! Check the span of the descriptor of an array pointer after it has been +! assigned to from a polymorphic function result. + +program test + implicit none + type t + integer :: c + end type t + type, extends(t) :: u + integer :: d + end type u + type(t), pointer :: p(:) + class(t), allocatable, target :: a(:) + p => f() + ! print *, p%c + if (any(p%c /= [2,5,11,17,23])) error stop 1 +contains + function f() + class(t), pointer :: f(:) + a = [ u(2,3), u(5,7), u(11,13), u(17,19), u(23,29) ] + f => a + end function +end program diff --git a/gcc/testsuite/gfortran.dg/pr121234.f90 b/gcc/testsuite/gfortran.dg/pr121234.f90 new file mode 100644 index 0000000..8eb1af53 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr121234.f90 @@ -0,0 +1,28 @@ +! { dg-do run } +! PR121234 Bogus diagnostic on READ of string with semicolon. + character(12) buffer,a + a = 'xxxxxxxxxx' + buffer="33;44" + read(buffer,*) a + if (a .ne. "33;44") stop 1 + a = 'xxxxxxxxxx' + buffer=" ;;33 ,44 " + read(buffer,*,decimal="comma") a + if (a .ne. 'xxxxxxxxxx') stop 2 ! A null read + a = 'xxxxxxxxxx' + buffer=" ;;33 ,44 " + read(buffer,*,decimal="point") a + if (a .ne. ';;33') stop 3 ! Spaces are delimiting + a = 'xxxxxxxxxx' + buffer=";;33;,44 " + read(buffer,*) a + if (a .ne. ';;33;') stop 4 ! Comma is delimiting + a = 'xxxxxxxxxx' + buffer=";;33;44;; " + read(buffer,*) a + if (a .ne. ';;33;44;;') stop 5 ! Space is delimiting + a = 'xxxxxxxxxx' + buffer=";;33;44;;;.7" + read(buffer,*) a + if (a .ne. ';;33;44;;;.7') stop 6 ! Space is delimiting +end diff --git a/gcc/testsuite/lib/rust.exp b/gcc/testsuite/lib/rust.exp index 9513e1c..692030c 100644 --- a/gcc/testsuite/lib/rust.exp +++ b/gcc/testsuite/lib/rust.exp @@ -168,10 +168,7 @@ proc rust_target_compile { source dest type options } { global gluefile wrap_flags global ALWAYS_RUSTFLAGS global RUST_UNDER_TEST - global individual_timeout - - # HACK: guard against infinite loops in the compiler - set individual_timeout 10 + if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { lappend options "libs=${gluefile}" diff --git a/gcc/testsuite/libgdiagnostics.dg/test-multiple-lines.c b/gcc/testsuite/libgdiagnostics.dg/test-multiple-lines.c index e761110..39af810 100644 --- a/gcc/testsuite/libgdiagnostics.dg/test-multiple-lines.c +++ b/gcc/testsuite/libgdiagnostics.dg/test-multiple-lines.c @@ -66,6 +66,7 @@ main () | ~~~~~ 23 | "bar" | ~~~~~^ + | , 24 | "baz"}; | ~~~~~ { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs b/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs index 6764f6e..1c49b75 100644 --- a/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs +++ b/gcc/testsuite/rust/compile/additional-trait-bounds2nr2.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - #![feature(optin_builtin_traits)] pub unsafe auto trait Send {} diff --git a/gcc/testsuite/rust/compile/all-cast.rs b/gcc/testsuite/rust/compile/all-cast.rs index fa24373..6d8576c 100644 --- a/gcc/testsuite/rust/compile/all-cast.rs +++ b/gcc/testsuite/rust/compile/all-cast.rs @@ -4,7 +4,7 @@ fn main() { 0u32 as char; // { dg-error "cannot cast .u32. as .char., only .u8. can be cast as .char." } - let x = &[1_usize, 2] as [usize]; // { dg-error "cast to unsized type: .& .usize:CAPACITY.. as ..usize.." } + let x = &[1_usize, 2] as [usize]; // { dg-error "cast to unsized type: .& .usize; 2.. as ..usize.." } let a = &0u8; // Here, `x` is a `&u8`. let y: u32 = a as u32; // { dg-error "casting .& u8. as .u32. is invalid" } diff --git a/gcc/testsuite/rust/compile/arrays2.rs b/gcc/testsuite/rust/compile/arrays2.rs index 668bcf0..1090059 100644 --- a/gcc/testsuite/rust/compile/arrays2.rs +++ b/gcc/testsuite/rust/compile/arrays2.rs @@ -1,5 +1,4 @@ -// { dg-additional-options "-w" } fn main() { let array: [i32; 5] = [1, 2, 3]; - // { dg-error "mismatched types, expected an array with a fixed size of 5 elements, found one with 3 elements" "" { target *-*-* } .-1 } + // { dg-error "mismatched types, expected ..i32; 5.. but got ...integer.; 3.. .E0308." "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/auto_traits2.rs b/gcc/testsuite/rust/compile/auto_traits2.rs index 382d446..7004761 100644 --- a/gcc/testsuite/rust/compile/auto_traits2.rs +++ b/gcc/testsuite/rust/compile/auto_traits2.rs @@ -15,7 +15,7 @@ fn foo(a: &(dyn A + Send + Sync)) { struct S; impl A for S { - fn a_method(&self) {} // { dg-warning "unused name" } + fn a_method(&self) {} } fn main() { diff --git a/gcc/testsuite/rust/compile/bad-rpit1.rs b/gcc/testsuite/rust/compile/bad-rpit1.rs new file mode 100644 index 0000000..d8c21b1 --- /dev/null +++ b/gcc/testsuite/rust/compile/bad-rpit1.rs @@ -0,0 +1,26 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct A; +struct B; + +impl Foo for A { + fn id(&self) -> i32 { + 1 + } +} + +impl Foo for B { + fn id(&self) -> i32 { + 2 + } +} + +fn make_foo(cond: bool) -> impl Foo { + if cond { A } else { B } + // { dg-error "mismatched types, expected .A. but got .B. .E0308." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/bug-with-default-generic.rs b/gcc/testsuite/rust/compile/bug-with-default-generic.rs new file mode 100644 index 0000000..25f46a0 --- /dev/null +++ b/gcc/testsuite/rust/compile/bug-with-default-generic.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +pub trait Sized {} + +pub trait MyBinaryTrait<Rhs = Self> { + fn do_something(&self, rhs: &Rhs); +} + +struct Foo<T> { + // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + value: T, +} + +impl<T> MyBinaryTrait for Foo<T> { + fn do_something(&self, _rhs: &Self) {} +} diff --git a/gcc/testsuite/rust/compile/const3.rs b/gcc/testsuite/rust/compile/const3.rs index 22dc3d3..c1d0f29 100644 --- a/gcc/testsuite/rust/compile/const3.rs +++ b/gcc/testsuite/rust/compile/const3.rs @@ -3,5 +3,5 @@ fn size() -> usize { } fn main() { - let a = [15; size()]; // { dg-error "only functions marked as .const. are allowed to be called from constant contexts" } + let a = [15; size()]; // { dg-error "calls in constants are limited to constant functions, tuple structs and tuple variants" } } diff --git a/gcc/testsuite/rust/compile/const_generics_10.rs b/gcc/testsuite/rust/compile/const_generics_10.rs new file mode 100644 index 0000000..7e3bc86 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_10.rs @@ -0,0 +1,32 @@ +#[lang = "sized"] +trait Sized {} + +const M: usize = 4; + +struct Foo<T, const N: usize = 1> { + value: [T; N], +} + +fn main() { + let foo = Foo::<i32> { value: [15] }; + let foo = Foo::<i32, 2> { value: [15, 13] }; + let foo: Foo<i32, 2> = Foo { value: [15, 13] }; + let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; + let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; + let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let foo: Foo<i32, M> = Foo::<i32, 4> { + value: [15, 13, 11, 9], + }; + + let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] }; + // { dg-error {mismatched types, expected ..T=i32; 3.. but got ...integer.; 2.. .E0308.} "" { target *-*-* } .-1 } + // { dg-error {mismatched types, expected ..T=i32; 2.. but got ..T=i32; 3.. .E0308.} "" { target *-*-* } .-2 } + + let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] }; + // { dg-error {mismatched types, expected ..T=i32; 4.. but got ...integer.; 2.. .E0308.} "" { target *-*-* } .-1 } + // { dg-error {mismatched types, expected ..T=i32; 2.. but got ..T=i32; 4.. .E0308.} "" { target *-*-* } .-2 } + + let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] }; + // { dg-error {mismatched types, expected ..T=i32; 1.. but got ..T=i32; 2.. .E0308.} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/const_generics_11.rs b/gcc/testsuite/rust/compile/const_generics_11.rs new file mode 100644 index 0000000..de902ee --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_11.rs @@ -0,0 +1,14 @@ +// { dg-options "-w" } + +#[lang = "sized"] +trait Sized {} + +struct Matrix<T, const ROWS: usize, const COLS: usize> { + data: [[T; COLS]; ROWS], +} + +fn main() { + let _: Matrix<u8, 2, 3> = Matrix { + data: [[1, 2, 3], [4, 5, 6]], + }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_12.rs b/gcc/testsuite/rust/compile/const_generics_12.rs new file mode 100644 index 0000000..a17c525 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_12.rs @@ -0,0 +1,14 @@ +// { dg-options "-w" } + +#[lang = "sized"] +trait Sized {} + +const BASE: usize = 2; + +struct Foo<T, const N: usize> { + data: [T; N], +} + +fn main() { + let _ = Foo::<u8, { BASE + 1 * 2 }> { data: [0; 4] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_13.rs b/gcc/testsuite/rust/compile/const_generics_13.rs new file mode 100644 index 0000000..20dd0b90 --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_13.rs @@ -0,0 +1,11 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<T, const N: usize> { + value: [T; N], +} + +fn main() { + let foo: Foo<_, _>; + // { dg-error {type provided when a constant was expected .E0747.} "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/const_generics_14.rs b/gcc/testsuite/rust/compile/const_generics_14.rs new file mode 100644 index 0000000..4d52efb --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_14.rs @@ -0,0 +1,13 @@ +#[lang = "sized"] +trait Sized {} + +type MyLen = usize; +struct Foo<T, const N: usize> { + data: [T; N], +} + +fn main() { + let _ = Foo::<u8, MyLen> { data: [1, 2, 3] }; + // { dg-error {type provided when a constant was expected .E0747.} "" { target *-*-* } .-1 } + // { dg-error {expected an ADT type for constructor} "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/rust/compile/const_generics_15.rs b/gcc/testsuite/rust/compile/const_generics_15.rs new file mode 100644 index 0000000..a160abf --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_15.rs @@ -0,0 +1,16 @@ +#[lang = "sized"] +trait Sized {} + +enum Foo<const N: usize> { + A([u8; N]), +} + +union Bar<const N: usize> { + a: [i32; N], + b: [u8; N], +} + +fn main() { + let _ = Foo::<4>::A([1, 2, 3, 4]); + let _ = Bar::<4> { a: [0; 4] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_16.rs b/gcc/testsuite/rust/compile/const_generics_16.rs new file mode 100644 index 0000000..060dbda --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_16.rs @@ -0,0 +1,10 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<T = u8, const N: usize = 4> { + data: [T; N], // { dg-warning "field is never read: .data." } +} + +fn main() { + let _x = Foo { data: [1, 2, 3, 4] }; +} diff --git a/gcc/testsuite/rust/compile/const_generics_3.rs b/gcc/testsuite/rust/compile/const_generics_3.rs index 524d48d..3415f17 100644 --- a/gcc/testsuite/rust/compile/const_generics_3.rs +++ b/gcc/testsuite/rust/compile/const_generics_3.rs @@ -1,28 +1,21 @@ -// { dg-additional-options "-w -frust-name-resolution-2.0" } - #[lang = "sized"] trait Sized {} const M: usize = 4; struct Foo<T, const N: usize = 1> { - value: [T; N], + value: [T; N], // { dg-warning "field is never read: .value." } } fn main() { - let foo = Foo::<i32> { value: [15] }; - let foo = Foo::<i32, 2> { value: [15, 13] }; - let foo: Foo<i32, 2> = Foo { value: [15, 13] }; - let foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; - let foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; - let foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; - let foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; - let foo: Foo<i32, M> = Foo::<i32, 4> { + let _foo = Foo::<i32> { value: [15] }; + let _foo = Foo::<i32, 2> { value: [15, 13] }; + let _foo: Foo<i32, 2> = Foo { value: [15, 13] }; + let _foo: Foo<i32, 2> = Foo::<i32, 2> { value: [15, 13] }; + let _foo: Foo<i32, { 1 + 1 }> = Foo { value: [15, 13] }; + let _foo = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let _foo: Foo<i32, { 1 + 1 }> = Foo::<i32, { 1 + 1 }> { value: [15, 13] }; + let _foo: Foo<i32, M> = Foo::<i32, 4> { value: [15, 13, 11, 9], }; - - // FIXME: Add proper const typecheck errors here - let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, 3> { value: [15, 13] }; - let invalid_foo: Foo<i32, { 1 + 1 }> = Foo::<i32, M> { value: [15, 13] }; - let invalid_foo: Foo<i32> = Foo::<i32, 2> { value: [15, 13] }; } diff --git a/gcc/testsuite/rust/compile/const_generics_5.rs b/gcc/testsuite/rust/compile/const_generics_5.rs index 685229e..4d05569 100644 --- a/gcc/testsuite/rust/compile/const_generics_5.rs +++ b/gcc/testsuite/rust/compile/const_generics_5.rs @@ -1,4 +1,3 @@ -// { dg-options "-w" } struct Foo<const N: usize = { 14 }>; const M: usize = 15; @@ -8,5 +7,6 @@ fn main() { let _: Foo<15> = Foo; let _: Foo<{ M }> = Foo; let _: Foo<M> = Foo; - // let _: Foo<N> = Foo; this causes an ICE we need to do const generics + let _: Foo<N> = Foo; + // { dg-error {type provided when a constant was expected .E0747.} "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/const_generics_8.rs b/gcc/testsuite/rust/compile/const_generics_8.rs index bb34652..ce5e1b5 100644 --- a/gcc/testsuite/rust/compile/const_generics_8.rs +++ b/gcc/testsuite/rust/compile/const_generics_8.rs @@ -9,12 +9,13 @@ type Bipboupe<const N: i32 = 15> = Bidule; trait Fooable<const N: i32 = 15> {} union Bidoulepe<const N: i32 = 15> { - // { dg-error "default values for const generic parameters are not allowed in .union. items" "" {target *-*-* } .-1 } int: i32, float: f32, } -fn const_default<const N: i32 = 15>() {} // { dg-error "default values for const generic parameters are not allowed in .function. items" } +fn const_default<const N: i32 = 15>() {} // { dg-error "default values for const generic parameters are not allowed here" } // Note - missing generic parameter - needs name resolution on const generics -impl<const N: i32 = 15> Bidule {} // { dg-error "default values for const generic parameters are not allowed in .impl. items" } +impl<const N: i32 = 15> Bidule {} +// { dg-error "default values for const generic parameters are not allowed here" "" {target *-*-* } .-1 } +// { dg-error "unconstrained type parameter" "" {target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/const_generics_9.rs b/gcc/testsuite/rust/compile/const_generics_9.rs new file mode 100644 index 0000000..98e2d3f --- /dev/null +++ b/gcc/testsuite/rust/compile/const_generics_9.rs @@ -0,0 +1,13 @@ +// { dg-options "-w" } + +#[lang = "sized"] +trait Sized {} + +struct ArrayWrapper<T, const N: usize> { + data: [T; N], +} + +pub fn test() -> [u8; 4] { + let a = ArrayWrapper { data: [1u8; 4] }; + a.data +} diff --git a/gcc/testsuite/rust/compile/deferred_const_inference.rs b/gcc/testsuite/rust/compile/deferred_const_inference.rs new file mode 100644 index 0000000..25a3b17 --- /dev/null +++ b/gcc/testsuite/rust/compile/deferred_const_inference.rs @@ -0,0 +1,7 @@ +// { dg-additional-options "-frust-compile-until=typecheck" } + +// #![feature(generic_arg_infer)] + +fn main() { + let a: [u32; _] = [15u32]; +} diff --git a/gcc/testsuite/rust/compile/derive-debug1.rs b/gcc/testsuite/rust/compile/derive-debug1.rs index cf2187d..5927374 100644 --- a/gcc/testsuite/rust/compile/derive-debug1.rs +++ b/gcc/testsuite/rust/compile/derive-debug1.rs @@ -23,15 +23,15 @@ mod core { } } -#[derive(Debug)] // { dg-warning "unused name" } +#[derive(Debug)] // { dg-warning "stub implementation" "" { target *-*-* } .-1 } struct Foo { a: i32, b: i64 } // { dg-warning "is never constructed" } -#[derive(Debug)] // { dg-warning "unused name" } +#[derive(Debug)] // { dg-warning "stub implementation" "" { target *-*-* } .-1 } struct Bar(i32, i32); // { dg-warning "is never constructed" } -#[derive(Debug)] // { dg-warning "unused name" } +#[derive(Debug)] // { dg-warning "stub implementation" "" { target *-*-* } .-1 } enum Baz { A, diff --git a/gcc/testsuite/rust/compile/derive_macro1.rs b/gcc/testsuite/rust/compile/derive_macro1.rs index bc10d60..8c42aba 100644 --- a/gcc/testsuite/rust/compile/derive_macro1.rs +++ b/gcc/testsuite/rust/compile/derive_macro1.rs @@ -7,7 +7,7 @@ pub trait Clone { } // This warning can be removed once we properly handle implems with #[automatically_derived] -#[derive(Clone)] // { dg-warning "unused name .self." } +#[derive(Clone)] pub struct S; fn main() { diff --git a/gcc/testsuite/rust/compile/derive_partial_ord1.rs b/gcc/testsuite/rust/compile/derive_partial_ord1.rs new file mode 100644 index 0000000..eeca62d --- /dev/null +++ b/gcc/testsuite/rust/compile/derive_partial_ord1.rs @@ -0,0 +1,464 @@ +// { dg-additional-options "-w" } + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +impl Eq for i32 {} + +#[derive(PartialEq, PartialOrd)] +enum Foo { + A, + B(i32, i32, i32), + C { inner: i32, outer: i32 }, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Bar { + a: i32, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct BarFull { + a: i32, + b: i32, + c: i32, + d: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() { + let a = Foo::A; + let b = Foo::B(15, 14, 13); + + match a.partial_cmp(&b) { + Option::Some(Ordering::Less) => print("less"), + Option::Some(Ordering::Greater) => print("greater"), + Option::Some(Ordering::Equal) => print("equal"), + _ => print("uuuuh woops lol"), + } +} diff --git a/gcc/testsuite/rust/compile/enum_variant_name.rs b/gcc/testsuite/rust/compile/enum_variant_name.rs index 671fced..965acd1 100644 --- a/gcc/testsuite/rust/compile/enum_variant_name.rs +++ b/gcc/testsuite/rust/compile/enum_variant_name.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-w -frust-name-resolution-2.0" } +// { dg-additional-options "-w" } struct E1; enum Test { diff --git a/gcc/testsuite/rust/compile/format_args_basic_expansion.rs b/gcc/testsuite/rust/compile/format_args_basic_expansion.rs index 40bcd3c..cedb62c 100644 --- a/gcc/testsuite/rust/compile/format_args_basic_expansion.rs +++ b/gcc/testsuite/rust/compile/format_args_basic_expansion.rs @@ -35,7 +35,6 @@ pub mod core { impl Display for i32 { fn fmt(&self, _: &mut Formatter) -> Result { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } Result } } diff --git a/gcc/testsuite/rust/compile/format_args_extra_comma.rs b/gcc/testsuite/rust/compile/format_args_extra_comma.rs index fcc435c..dc48a3a 100644 --- a/gcc/testsuite/rust/compile/format_args_extra_comma.rs +++ b/gcc/testsuite/rust/compile/format_args_extra_comma.rs @@ -35,7 +35,6 @@ pub mod core { impl Display for i32 { fn fmt(&self, _: &mut Formatter) -> Result { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } Result } } diff --git a/gcc/testsuite/rust/compile/generics8.rs b/gcc/testsuite/rust/compile/generics8.rs index 88c4bac..2d30a9e 100644 --- a/gcc/testsuite/rust/compile/generics8.rs +++ b/gcc/testsuite/rust/compile/generics8.rs @@ -4,7 +4,7 @@ pub trait Sized {} struct Foo<A, B>(A, B); impl<T> Foo<i32, T> { - fn test(a: T) -> T { + fn test(a: T) -> T { // { dg-error "duplicate definitions with name .test." } a } } diff --git a/gcc/testsuite/rust/compile/generics9.rs b/gcc/testsuite/rust/compile/generics9.rs index 56c6198..949fbb1 100644 --- a/gcc/testsuite/rust/compile/generics9.rs +++ b/gcc/testsuite/rust/compile/generics9.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } struct Foo<A, B = (A, B)>(A, B); // { dg-error "type parameters with a default cannot use forward declared identifiers" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/glob_import_enum.rs b/gcc/testsuite/rust/compile/glob_import_enum.rs new file mode 100644 index 0000000..032a1db --- /dev/null +++ b/gcc/testsuite/rust/compile/glob_import_enum.rs @@ -0,0 +1,16 @@ +use self::Ordering::*; +use Ordering::*; + +enum Ordering { + A, + B, +} + +fn foo(_: Ordering) {} + +fn main() { + let a = A; + + foo(a); + foo(B); +} diff --git a/gcc/testsuite/rust/compile/impl_trait_diag.rs b/gcc/testsuite/rust/compile/impl_trait_diag.rs new file mode 100644 index 0000000..54a0cd2 --- /dev/null +++ b/gcc/testsuite/rust/compile/impl_trait_diag.rs @@ -0,0 +1,17 @@ +#[lang = "sized"] +pub trait Sized {} + +trait Foo { + fn method(&self); +} + +struct Bar; +impl Foo for Bar {} + +fn main() { + let x: impl Foo = Bar; // { dg-error ".impl Trait. not allowed outside of function and inherent method return types .E0562." } + + struct Wrapper { + field: impl Foo, // { dg-error ".impl Trait. not allowed outside of function and inherent method return types .E0562." } + } +} diff --git a/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs b/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs new file mode 100644 index 0000000..ecdb088 --- /dev/null +++ b/gcc/testsuite/rust/compile/impl_trait_generic_arg.rs @@ -0,0 +1,24 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> u8; +} + +struct Bar; + +impl Foo for Bar { + fn id(&self) -> u8 { + 1 + } +} + +fn takes(val: impl Foo) -> u8 { + val.id() +} + +fn main() { + let b = Bar; + let x = takes::<Bar>(b); + // { dg-error "cannot provide explicit generic arguments when .impl Trait. is used in argument position .E0632." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/invalid_label_name.rs b/gcc/testsuite/rust/compile/invalid_label_name.rs index 66e40a6..d1c5a33 100644 --- a/gcc/testsuite/rust/compile/invalid_label_name.rs +++ b/gcc/testsuite/rust/compile/invalid_label_name.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } pub fn function() { 'continue: loop { // { dg-error "invalid label name .'continue." "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-1048.rs b/gcc/testsuite/rust/compile/issue-1048.rs new file mode 100644 index 0000000..8d4053a --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1048.rs @@ -0,0 +1,8 @@ +macro_rules! maybe_return { ($e:expr) => ($e); } + +fn frob(x: i32) -> i32{ + maybe_return! {x} + // { dg-error "mismatched types. expected .... but got .i32. .E0308." "" { target *-*-* } .-1 } + // should return -1 + -1 +} diff --git a/gcc/testsuite/rust/compile/issue-1485.rs b/gcc/testsuite/rust/compile/issue-1485.rs new file mode 100644 index 0000000..a0cd5a0 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1485.rs @@ -0,0 +1,16 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct BinOpInvalid { + lhs: i32, + rhs: i32, + f: impl FnOnce(i32) -> i32, // { dg-error ".impl Trait. not allowed outside of function and inherent method return types .E0562." } +} diff --git a/gcc/testsuite/rust/compile/issue-1487.rs b/gcc/testsuite/rust/compile/issue-1487.rs new file mode 100644 index 0000000..4a4d759 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1487.rs @@ -0,0 +1,15 @@ +// { dg-options "-w" } +#[lang = "sized"] +trait Sized {} + +trait Printable { + fn print(&self); +} + +struct Foo; + +impl Printable for Foo { + fn print(&self) {} +} + +fn take_printable(_: impl Printable) {} diff --git a/gcc/testsuite/rust/compile/issue-2015.rs b/gcc/testsuite/rust/compile/issue-2015.rs index 7789ecd..7e03651 100644 --- a/gcc/testsuite/rust/compile/issue-2015.rs +++ b/gcc/testsuite/rust/compile/issue-2015.rs @@ -1,4 +1,5 @@ -// { dg-additional-options "-frust-compile-until=lowering" } +#[lang = "sized"] +trait Sized {} macro_rules! impl_foo { () => { impl Foo } diff --git a/gcc/testsuite/rust/compile/issue-2043.rs b/gcc/testsuite/rust/compile/issue-2043.rs index efa1ded..92532b7 100644 --- a/gcc/testsuite/rust/compile/issue-2043.rs +++ b/gcc/testsuite/rust/compile/issue-2043.rs @@ -6,7 +6,6 @@ struct Foo<'a> { impl<'a> Foo<'a> { fn bar(self: &mut Foo<'a>) {} // { dg-warning "associated function is never used: .bar." "" { target *-*-* } .-1 } - // { dg-warning "unused name .self." "" { target *-*-* } .-2 } } fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-2166.rs b/gcc/testsuite/rust/compile/issue-2166.rs index 318f0a6..142ed17 100644 --- a/gcc/testsuite/rust/compile/issue-2166.rs +++ b/gcc/testsuite/rust/compile/issue-2166.rs @@ -11,7 +11,6 @@ impl Add for u32 { type Output = u32; fn add(self) -> u32 { - // { dg-warning "unused name" "" { target *-*-* } .-1 } 0 } } @@ -20,7 +19,6 @@ impl<'a> Add for &'a u32 { type Output = u32; fn add(self) -> <u32 as Add>::Output { - // { dg-warning "unused name" "" { target *-*-* } .-1 } 0 } } diff --git a/gcc/testsuite/rust/compile/issue-2238.rs b/gcc/testsuite/rust/compile/issue-2238.rs index 38871b3..6a43a13 100644 --- a/gcc/testsuite/rust/compile/issue-2238.rs +++ b/gcc/testsuite/rust/compile/issue-2238.rs @@ -10,7 +10,6 @@ fn main() { impl Bar for Foo { fn foo(&self) {} - // { dg-warning "unused name" "" { target *-*-* } .-1 } } let s = Foo; diff --git a/gcc/testsuite/rust/compile/issue-2680.rs b/gcc/testsuite/rust/compile/issue-2680.rs new file mode 100644 index 0000000..d5ae2ff44 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-2680.rs @@ -0,0 +1,6 @@ +// { dg-additional-options "-fdump-tree-gimple" } +pub fn test_cast() { + let i = 1; + // { dg-final { scan-tree-dump-times {const i32 i;} 1 gimple } } + let _j = i as i64; +} diff --git a/gcc/testsuite/rust/compile/issue-2907.rs b/gcc/testsuite/rust/compile/issue-2907.rs index 1af843f..fdf1953 100644 --- a/gcc/testsuite/rust/compile/issue-2907.rs +++ b/gcc/testsuite/rust/compile/issue-2907.rs @@ -15,7 +15,6 @@ impl<B: Bar> Foo for B { type Ty = u32; fn foo(self) -> Self::Ty { - // { dg-warning "unused name" "" { target *-*-* } .-1 } 14 } } diff --git a/gcc/testsuite/rust/compile/issue-3144.rs b/gcc/testsuite/rust/compile/issue-3144.rs new file mode 100644 index 0000000..4e61078 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3144.rs @@ -0,0 +1,29 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "clone"] +pub trait Clone { + fn clone(&self) -> Self; +} + +impl Clone for i32 { + fn clone(&self) -> i32 { + *self + } +} + +struct S {} + +#[derive(Clone, Copy)] +// { dg-error {bounds not satisfied for S .Clone. is not satisfied .E0277.} "" { target *-*-* } .-1 } +struct S2 { + a: i32, + s: S, +} + +fn main() -> i32 { + 0 +} diff --git a/gcc/testsuite/rust/compile/issue-3304.rs b/gcc/testsuite/rust/compile/issue-3304.rs index 6ab614f..cc376fa 100644 --- a/gcc/testsuite/rust/compile/issue-3304.rs +++ b/gcc/testsuite/rust/compile/issue-3304.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } #[lang = "sized"] trait Sized {} diff --git a/gcc/testsuite/rust/compile/issue-3454.rs b/gcc/testsuite/rust/compile/issue-3454.rs new file mode 100644 index 0000000..2a3c0c7 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3454.rs @@ -0,0 +1,20 @@ +#[lang = "sized"] +pub trait Sized {} + +macro_rules! impl_foo { + () => { impl Foo } +} + +pub trait Foo {} + +pub trait Bar { + type Baz; +} + +pub fn foo(_value: impl Bar<Baz = impl_foo!()>) -> i32 { + 15 +} + +pub fn bar(_value: impl Bar<Baz = impl Foo>) -> i32 { + 16 +} diff --git a/gcc/testsuite/rust/compile/issue-3524.rs b/gcc/testsuite/rust/compile/issue-3524.rs new file mode 100644 index 0000000..62c8c35 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3524.rs @@ -0,0 +1,9 @@ +struct A {} +// { dg-warning "struct is never constructed" "" { target *-*-* } .-1 } + +impl A { + fn main() {} + // { dg-warning "associated function is never used: .main." "" { target *-*-* } .-1 } +} + +fn main() {} diff --git a/gcc/testsuite/rust/compile/issue-3525.rs b/gcc/testsuite/rust/compile/issue-3525.rs new file mode 100644 index 0000000..84a7ebe --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3525.rs @@ -0,0 +1,6 @@ +// { dg-options "-w" } + +struct Foo(usize); + +const B: usize = A.0; +const A: Foo = Foo(123); diff --git a/gcc/testsuite/rust/compile/issue-3546.rs b/gcc/testsuite/rust/compile/issue-3546.rs new file mode 100644 index 0000000..d4ec0bb --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3546.rs @@ -0,0 +1,16 @@ +const L: usize = 3; + +fn main() { + let p = Printer {}; + p.print(); +} + +trait Print<const N: usize> { + fn print(&self) -> usize { + 3 + } +} + +struct Printer {} +impl Print<L> for Printer {} +// { dg-error "generic item takes at most 1 type arguments but 1 were supplied" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-3551.rs b/gcc/testsuite/rust/compile/issue-3551.rs new file mode 100644 index 0000000..6d6a812 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3551.rs @@ -0,0 +1,15 @@ +#[lang = "sized"] +pub trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct Bug { + a: [(); (|| 0)()], + // { dg-error "calls in constants are limited to constant functions, tuple structs and tuple variants" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3599.rs b/gcc/testsuite/rust/compile/issue-3599.rs new file mode 100644 index 0000000..1d29fac --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3599.rs @@ -0,0 +1,8 @@ +#[lang = "sized"] +trait Sized {} + +trait Bar {} + +struct S; // { dg-warning "struct is never constructed" } + +pub fn test(foo: impl Bar) {} diff --git a/gcc/testsuite/rust/compile/issue-3618.rs b/gcc/testsuite/rust/compile/issue-3618.rs new file mode 100644 index 0000000..3bf2c7e --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3618.rs @@ -0,0 +1,2 @@ +static _X : () + = loop{}; // { dg-error "'loop' is not allowed in const context" } diff --git a/gcc/testsuite/rust/compile/issue-3642.rs b/gcc/testsuite/rust/compile/issue-3642.rs new file mode 100644 index 0000000..6d9decc --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3642.rs @@ -0,0 +1,9 @@ +#[lang = "sized"] +trait Sized {} + +pub trait T<X> { + const D: i32 = { + // { dg-error "mismatched types, expected .i32. but got .()." "" { target *-*-* } .-1 } + const C: X; + }; +} diff --git a/gcc/testsuite/rust/compile/issue-3660.rs b/gcc/testsuite/rust/compile/issue-3660.rs new file mode 100644 index 0000000..1f1c583 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3660.rs @@ -0,0 +1,3 @@ +pub static A: [u32; 2] = [1, 2]; + +pub static B: [u8; 2] = [3, 4]; diff --git a/gcc/testsuite/rust/compile/issue-3661.rs b/gcc/testsuite/rust/compile/issue-3661.rs new file mode 100644 index 0000000..8d03c36 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3661.rs @@ -0,0 +1,10 @@ +pub macro m($inner_str:expr) { + #[m = $inner_str] + // { dg-error "macro not found" "" { target *-*-* } .-1 } + + struct S; +} + +fn main() { + m!(stringify!(foo)); +} diff --git a/gcc/testsuite/rust/compile/issue-3671.rs b/gcc/testsuite/rust/compile/issue-3671.rs index e800d53..8015653 100644 --- a/gcc/testsuite/rust/compile/issue-3671.rs +++ b/gcc/testsuite/rust/compile/issue-3671.rs @@ -1,2 +1,2 @@ -impl Self<0> {} +impl Foo<0> {} // { dg-error "could not resolve type path" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/issue-3836.rs b/gcc/testsuite/rust/compile/issue-3836.rs new file mode 100644 index 0000000..a228795 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3836.rs @@ -0,0 +1,67 @@ +// { dg-options "-w" } +mod core { + mod option { + pub enum Option<T> { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } + } + + mod marker { + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[lang = "partial_ord"] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + } + } +} + +use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + false + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Option::Some(Ordering::Equal) + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + ::core::cmp::PartialEq::eq(&self.a, &other.a) + } +} diff --git a/gcc/testsuite/rust/compile/issue-3874.rs b/gcc/testsuite/rust/compile/issue-3874.rs new file mode 100644 index 0000000..ebce4b6 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3874.rs @@ -0,0 +1,4 @@ +fn wow(){ + &#[serde] + // { dg-error "found unexpected token .#. in null denotation" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3876.rs b/gcc/testsuite/rust/compile/issue-3876.rs new file mode 100644 index 0000000..17b1590 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3876.rs @@ -0,0 +1,8 @@ +enum test { + A(i32), +} + +fn fun(x: i32) { + test::A { x } + // { dg-error "unknown field" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3885.rs b/gcc/testsuite/rust/compile/issue-3885.rs new file mode 100644 index 0000000..050a59c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3885.rs @@ -0,0 +1,7 @@ +pub fn test() { + let _u: [_; _] = [15u32]; + let _v: [u8; _] = [1, 2, 3]; + let _w: [_; 2] = [1.0, 2.0]; + let _x = [42; 5]; + let _y: [_; _] = _x; +} diff --git a/gcc/testsuite/rust/compile/issue-3915.rs b/gcc/testsuite/rust/compile/issue-3915.rs new file mode 100644 index 0000000..7132036 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3915.rs @@ -0,0 +1,28 @@ +// { dg-options "-w" } +#[lang = "sized"] +trait Sized {} + +trait Trait { + fn do_thing(); +} + +struct MyType; + +impl Trait for MyType { + fn do_thing() {} +} + +struct Wrapper<T: Trait> { + value: T, +} + +impl<T: Trait> Wrapper<T> { + fn call_it() { + T::do_thing(); + } +} + +fn main() { + let _ = Wrapper::<MyType> { value: MyType }; + Wrapper::<MyType>::call_it(); +} diff --git a/gcc/testsuite/rust/compile/issue-3916.rs b/gcc/testsuite/rust/compile/issue-3916.rs new file mode 100644 index 0000000..59b522b --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3916.rs @@ -0,0 +1,36 @@ +#![feature(rustc_attrs)] + +#[lang = "sized"] +trait Sized {} + +#[lang = "add"] +trait Add<Rhs = Self> { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +macro_rules! add_impl { + ($($t:ty)*) => ($( + impl Add for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn add(self, other: $t) -> $t { self + other } + } + )*) +} + +add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +pub fn test(len: usize) -> u64 { + let mut i = 0; + let mut out = 0; + if i + 3 < len { + out = 123; + } else { + out = 456; + } + out +} diff --git a/gcc/testsuite/rust/compile/issue-3960.rs b/gcc/testsuite/rust/compile/issue-3960.rs new file mode 100644 index 0000000..57329f0 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3960.rs @@ -0,0 +1,7 @@ +fn main() { + struct G { + g: (), + } + let g = [0; G { g: () }]; + // { dg-error "mismatched types, expected .usize. but got .G. .E0308." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-3978.rs b/gcc/testsuite/rust/compile/issue-3978.rs new file mode 100644 index 0000000..4f17d3d --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3978.rs @@ -0,0 +1,8 @@ +type Dimension = usize; + +pub fn main() {} + +mod m2 { + fn main() {} + // { dg-warning "function is never used" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/issue-4006.rs b/gcc/testsuite/rust/compile/issue-4006.rs new file mode 100644 index 0000000..328c7b6 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-4006.rs @@ -0,0 +1,13 @@ +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +pub fn main() { + asm!( + "xor eax, eax" + "xor eax, eax"); + // { dg-error "expected token .;." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/loop_constant_context.rs b/gcc/testsuite/rust/compile/loop_constant_context.rs new file mode 100644 index 0000000..ed0782b --- /dev/null +++ b/gcc/testsuite/rust/compile/loop_constant_context.rs @@ -0,0 +1,5 @@ +// { dg-error "'loop' is not allowed in const context" "" { target *-*-* } .+1 } +const CONST_LOOP : () = loop{}; + +// { dg-error "'loop' is not allowed in const context" "" { target *-*-* } .+1 } +static STATIC_LOOP : () = loop{};
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs b/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs index 73e6ab4..fbb4b10 100644 --- a/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs +++ b/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs @@ -34,7 +34,7 @@ fn print_str(s: &str) { } } -// { dg-final { scan-assembler {"abheyho"} } } +// { dg-final { scan-assembler {"abheyho(\\0)?"} } } static S: &str = concat!("a", 'b', a!(), a!(b c d e f a!()), '\0'); fn main() { diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs index e5b38bb..bcbc8dd 100644 --- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3708.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } macro_rules! impl_fn_for_zst { ($( diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs index cfc8ab4..47514f1 100644 --- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs +++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue3709-2.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } macro_rules! impl_fn_for_zst { ($( diff --git a/gcc/testsuite/rust/compile/macros/mbe/meta-param.rs b/gcc/testsuite/rust/compile/macros/mbe/meta-param.rs new file mode 100644 index 0000000..ed6e100 --- /dev/null +++ b/gcc/testsuite/rust/compile/macros/mbe/meta-param.rs @@ -0,0 +1,7 @@ +macro_rules! foo { + ($x:meta) => {0} +} + +pub fn main() -> i32 { + foo!(Clone) +} diff --git a/gcc/testsuite/rust/compile/match-identifierpattern-enum.rs b/gcc/testsuite/rust/compile/match-identifierpattern-enum.rs new file mode 100644 index 0000000..c712667 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-identifierpattern-enum.rs @@ -0,0 +1,12 @@ +enum Foo { + I(i32), +} + +fn main() { + let x = Foo::I(1); + + match x { + a @ Foo::I(b) => {}, + _ => {}, + }; +} diff --git a/gcc/testsuite/rust/compile/match-identifierpattern.rs b/gcc/testsuite/rust/compile/match-identifierpattern.rs new file mode 100644 index 0000000..6c558ac --- /dev/null +++ b/gcc/testsuite/rust/compile/match-identifierpattern.rs @@ -0,0 +1,9 @@ +fn main() { + let x = 1; + + match x { + 2 => {}, + a @ 3 => {}, + _ => {}, + } +} diff --git a/gcc/testsuite/rust/compile/match-restpattern-tuple-1.rs b/gcc/testsuite/rust/compile/match-restpattern-tuple-1.rs new file mode 100644 index 0000000..5cce3c4 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-restpattern-tuple-1.rs @@ -0,0 +1,8 @@ +fn main() { + let x = (1, 2, 3, 4); + + match x { + (1, .., 4) => {}, + _ => {} + } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match-restpattern-tuple-2.rs b/gcc/testsuite/rust/compile/match-restpattern-tuple-2.rs new file mode 100644 index 0000000..40900a3 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-restpattern-tuple-2.rs @@ -0,0 +1,8 @@ +fn main() { + let x = (1, 2, 3, 4); + + match x { + (1, .., 2, 3, 4, 5) => {}, // { dg-error "expected a tuple with 4 elements, found one with 5 elements" } + _ => {} + } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match-slicepattern-array.rs b/gcc/testsuite/rust/compile/match-slicepattern-array.rs new file mode 100644 index 0000000..e48ca75 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-slicepattern-array.rs @@ -0,0 +1,8 @@ +fn main() { + let a = [0, 1]; + + match a { + [0, 1] => {}, + _ => {} + } +} diff --git a/gcc/testsuite/rust/compile/match-slicepattern-slice.rs b/gcc/testsuite/rust/compile/match-slicepattern-slice.rs new file mode 100644 index 0000000..cc33d93 --- /dev/null +++ b/gcc/testsuite/rust/compile/match-slicepattern-slice.rs @@ -0,0 +1,10 @@ +fn main() { + let arr = [1, 2]; + let slice: &[i32] = &arr; + + match slice { + [1] => {}, + [_, 2] => {}, + _ => {} + } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/match-tuplestructpattern.rs b/gcc/testsuite/rust/compile/match-tuplestructpattern.rs new file mode 100644 index 0000000..0dae71e --- /dev/null +++ b/gcc/testsuite/rust/compile/match-tuplestructpattern.rs @@ -0,0 +1,9 @@ +fn main() { + struct A (i32, i32); + let a = A (0, 1); + + match a { + A (0, 1) => {}, + _ => {} + } +} diff --git a/gcc/testsuite/rust/compile/min_specialization1.rs b/gcc/testsuite/rust/compile/min_specialization1.rs index d38167e..ba97f87 100644 --- a/gcc/testsuite/rust/compile/min_specialization1.rs +++ b/gcc/testsuite/rust/compile/min_specialization1.rs @@ -9,7 +9,7 @@ pub trait Foo { pub struct Bar; impl Foo for Bar { - default fn foo(&self) -> bool { // { dg-warning "unused" } + default fn foo(&self) -> bool { true } } diff --git a/gcc/testsuite/rust/compile/name_resolution10.rs b/gcc/testsuite/rust/compile/name_resolution10.rs index 33643bd..f156f98 100644 --- a/gcc/testsuite/rust/compile/name_resolution10.rs +++ b/gcc/testsuite/rust/compile/name_resolution10.rs @@ -1,4 +1,4 @@ -// { dg-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-options "-frust-compile-until=lowering" } #![feature(decl_macro)] diff --git a/gcc/testsuite/rust/compile/name_resolution11.rs b/gcc/testsuite/rust/compile/name_resolution11.rs index a464d2a..329567a 100644 --- a/gcc/testsuite/rust/compile/name_resolution11.rs +++ b/gcc/testsuite/rust/compile/name_resolution11.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } fn foo() { let b = 10; fn bar() { diff --git a/gcc/testsuite/rust/compile/name_resolution12.rs b/gcc/testsuite/rust/compile/name_resolution12.rs index 9cce31c..0f217aa 100644 --- a/gcc/testsuite/rust/compile/name_resolution12.rs +++ b/gcc/testsuite/rust/compile/name_resolution12.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-additional-options "-frust-compile-until=lowering" } const TOTO: i32 = 10; diff --git a/gcc/testsuite/rust/compile/name_resolution13.rs b/gcc/testsuite/rust/compile/name_resolution13.rs index 33edbf9..8356cf6 100644 --- a/gcc/testsuite/rust/compile/name_resolution13.rs +++ b/gcc/testsuite/rust/compile/name_resolution13.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/compile/name_resolution14.rs b/gcc/testsuite/rust/compile/name_resolution14.rs index eaef6a5..44c43aa 100644 --- a/gcc/testsuite/rust/compile/name_resolution14.rs +++ b/gcc/testsuite/rust/compile/name_resolution14.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/compile/name_resolution15.rs b/gcc/testsuite/rust/compile/name_resolution15.rs index 45f38da..e82c90e 100644 --- a/gcc/testsuite/rust/compile/name_resolution15.rs +++ b/gcc/testsuite/rust/compile/name_resolution15.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } #![feature(decl_macro)] pub mod foo { diff --git a/gcc/testsuite/rust/compile/name_resolution16.rs b/gcc/testsuite/rust/compile/name_resolution16.rs index 230722e..4db7b2e 100644 --- a/gcc/testsuite/rust/compile/name_resolution16.rs +++ b/gcc/testsuite/rust/compile/name_resolution16.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } #![feature(decl_macro)] pub mod foo { diff --git a/gcc/testsuite/rust/compile/name_resolution17.rs b/gcc/testsuite/rust/compile/name_resolution17.rs index 4859476..84ad380 100644 --- a/gcc/testsuite/rust/compile/name_resolution17.rs +++ b/gcc/testsuite/rust/compile/name_resolution17.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - struct Foo; fn Foo() {} // { dg-error ".Foo. defined multiple times" } diff --git a/gcc/testsuite/rust/compile/name_resolution18.rs b/gcc/testsuite/rust/compile/name_resolution18.rs index 5940149..17a3352 100644 --- a/gcc/testsuite/rust/compile/name_resolution18.rs +++ b/gcc/testsuite/rust/compile/name_resolution18.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - struct Marker; struct Foo { diff --git a/gcc/testsuite/rust/compile/name_resolution2.rs b/gcc/testsuite/rust/compile/name_resolution2.rs index 7e4f5a1..564c5d2 100644 --- a/gcc/testsuite/rust/compile/name_resolution2.rs +++ b/gcc/testsuite/rust/compile/name_resolution2.rs @@ -4,7 +4,7 @@ pub trait Sized {} struct Bar; trait Foo { - fn bar(&self) {} // { dg-warning "unused name" } + fn bar(&self) {} } pub fn outer() { diff --git a/gcc/testsuite/rust/compile/name_resolution20.rs b/gcc/testsuite/rust/compile/name_resolution20.rs index e6c2dd5..f131bb4 100644 --- a/gcc/testsuite/rust/compile/name_resolution20.rs +++ b/gcc/testsuite/rust/compile/name_resolution20.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/compile/name_resolution22.rs b/gcc/testsuite/rust/compile/name_resolution22.rs index c49331e..bb5edda 100644 --- a/gcc/testsuite/rust/compile/name_resolution22.rs +++ b/gcc/testsuite/rust/compile/name_resolution22.rs @@ -1,4 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } struct Marker; struct Foo(Marker); diff --git a/gcc/testsuite/rust/compile/name_resolution23.rs b/gcc/testsuite/rust/compile/name_resolution23.rs index 50b8e81..843be2a 100644 --- a/gcc/testsuite/rust/compile/name_resolution23.rs +++ b/gcc/testsuite/rust/compile/name_resolution23.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - mod a { pub mod b { pub fn foo() {} diff --git a/gcc/testsuite/rust/compile/name_resolution24.rs b/gcc/testsuite/rust/compile/name_resolution24.rs index f4eb7b2..4350cd8 100644 --- a/gcc/testsuite/rust/compile/name_resolution24.rs +++ b/gcc/testsuite/rust/compile/name_resolution24.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - mod a { pub mod b { pub fn baz() {} diff --git a/gcc/testsuite/rust/compile/name_resolution25.rs b/gcc/testsuite/rust/compile/name_resolution25.rs index 3cacac7..0cadd9e 100644 --- a/gcc/testsuite/rust/compile/name_resolution25.rs +++ b/gcc/testsuite/rust/compile/name_resolution25.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - struct Test; // { dg-warning "struct is never constructed: .Test." } impl Test {} diff --git a/gcc/testsuite/rust/compile/name_resolution4.rs b/gcc/testsuite/rust/compile/name_resolution4.rs index b2eadbe..0fc72f6 100644 --- a/gcc/testsuite/rust/compile/name_resolution4.rs +++ b/gcc/testsuite/rust/compile/name_resolution4.rs @@ -2,7 +2,7 @@ pub trait Sized {} trait Foo { - fn foo(&self) {} // { dg-warning "unused name" } + fn foo(&self) {} } struct Bar; diff --git a/gcc/testsuite/rust/compile/name_resolution6.rs b/gcc/testsuite/rust/compile/name_resolution6.rs index e4087e6..b2b5f6b 100644 --- a/gcc/testsuite/rust/compile/name_resolution6.rs +++ b/gcc/testsuite/rust/compile/name_resolution6.rs @@ -1,4 +1,4 @@ -// { dg-options "-frust-name-resolution-2.0 -frust-compile-until=lowering" } +// { dg-options "-frust-compile-until=lowering" } pub mod foo { pub mod bar { diff --git a/gcc/testsuite/rust/compile/name_resolution7.rs b/gcc/testsuite/rust/compile/name_resolution7.rs index fa84e2f..78cb0b2 100644 --- a/gcc/testsuite/rust/compile/name_resolution7.rs +++ b/gcc/testsuite/rust/compile/name_resolution7.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - // check that macros by example do not get inserted in ribs like regular items pub mod foo { pub mod bar { diff --git a/gcc/testsuite/rust/compile/name_resolution8.rs b/gcc/testsuite/rust/compile/name_resolution8.rs index 6fb5170..aca1945 100644 --- a/gcc/testsuite/rust/compile/name_resolution8.rs +++ b/gcc/testsuite/rust/compile/name_resolution8.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - // check that macros by example get exported to the crate's root with #[macro_export] pub mod foo { pub mod bar { diff --git a/gcc/testsuite/rust/compile/name_resolution9.rs b/gcc/testsuite/rust/compile/name_resolution9.rs index 792b3bd..84ba3c5 100644 --- a/gcc/testsuite/rust/compile/name_resolution9.rs +++ b/gcc/testsuite/rust/compile/name_resolution9.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - pub mod foo { pub mod bar { fn f() { diff --git a/gcc/testsuite/rust/compile/nested_macro_definition.rs b/gcc/testsuite/rust/compile/nested_macro_definition.rs index c0b7250..b71afbd 100644 --- a/gcc/testsuite/rust/compile/nested_macro_definition.rs +++ b/gcc/testsuite/rust/compile/nested_macro_definition.rs @@ -1,5 +1,3 @@ -// { dg-options "-frust-name-resolution-2.0" } - macro_rules! toto { () => { macro_rules! tata { diff --git a/gcc/testsuite/rust/compile/nr2/compile.exp b/gcc/testsuite/rust/compile/nr2/compile.exp deleted file mode 100644 index 9e15cdd..0000000 --- a/gcc/testsuite/rust/compile/nr2/compile.exp +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright (C) 2021-2024 Free Software Foundation, Inc. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GCC; see the file COPYING3. If not see -# <http://www.gnu.org/licenses/>. - -# Run compile tests with name resolution 2.0 enabled - -# Load support procs. -load_lib rust-dg.exp - -# These tests don't run runtest_file_p consistently if it -# doesn't return the same values, so disable parallelization -# of this *.exp file. The first parallel runtest to reach -# this will run all the tests serially. -if ![gcc_parallel_test_run_p compile] { - return -} -gcc_parallel_test_enable 0 - -# Initialize `dg'. -dg-init - -namespace eval rust-nr2-ns { - # Exclude tests which aren't passing yet - # These should be removed from the exclude file over time - - set exclude_fh [open $srcdir/$subdir/exclude r] - set exclude_raw [lsort [split [read $exclude_fh] "\n"]] - close $exclude_fh - unset exclude_fh - - set exclude "" - foreach ent $exclude_raw { - if [regexp {^[^#].*} $ent] { - lappend exclude $ent - } - } - unset exclude_raw - - # Run tests in directories - # Manually specifying these, in case some other test file - # does something weird - set test_dirs {{} {macros builtin} {macros mbe} {macros proc} {torture}} - - set tests_expect_ok "" - set tests_expect_err "" - - set compile_dir [list {*}[file split $srcdir] {*}[file split $subdir]] - set compile_dir [lreplace $compile_dir end end] - - foreach test_dir $test_dirs { - foreach test [lsort [glob -nocomplain -tails -directory [file join {*}$compile_dir {*}$test_dir] *.rs]] { - # use '/' as the path seperator for entries in the exclude file - set test_lbl [join [list {*}$test_dir $test] "/"] - set idx [lsearch -exact -sorted $exclude $test_lbl] - if {$idx == -1} { - if {[runtest_file_p $runtests [file join {*}$compile_dir {*}$test_dir $test]]} { - lappend tests_expect_ok [list {*}$test_dir $test] - } - } else { - if {[runtest_file_p $runtests [file join {*}$compile_dir {*}$test_dir $test]]} { - lappend tests_expect_err [list {*}$test_dir $test] - } - set exclude [lreplace $exclude $idx $idx] - } - } - } - - # Generate failures for unmatched tests in the exclude list - foreach ent $exclude { - fail "$ent: could not exclude test" - } - unset exclude - - # run a test while catching record_test calls - set record_test_out "" - proc try_test { test } { - variable record_test_out - rename ::record_test record_test_old - - proc ::record_test { type msg args } { - namespace eval ::rust-nr2-ns { - set type [uplevel 1 {set type}] - set msg [uplevel 1 {set msg}] - variable record_test_out - switch $type { - FAIL { - lappend record_test_out [list $type $msg] - } - XPASS { - lappend record_test_out [list $type $msg] - } - } - } - } - - namespace eval :: { - set saved-dg-do-what-default ${dg-do-what-default} - set dg-do-what-default "compile" - dg-runtest [list [uplevel 1 {set test}]] "-frust-name-resolution-2.0" "" - set dg-do-what-default ${saved-dg-do-what-default} - } - - rename ::record_test "" - rename record_test_old ::record_test - - set record_test_cache $record_test_out - set record_test_out "" - return $record_test_cache - } - - # check for unexpected failures - foreach test $tests_expect_ok { - set fails [try_test [file join {*}$compile_dir {*}$test]] - if {[llength $fails] != 0} { - foreach ent $fails { - record_test [lindex $ent 0] "on nr2: [lindex $ent 1]" - } - } else { - record_test PASS "[file join {*}$test] on nr2" - } - } - - #check for unexpected successes - foreach test $tests_expect_err { - set fails [try_test [file join {*}$compile_dir {*}$test]] - if {[llength $fails] == 0} { - record_test XPASS "[file join {*}$test] on nr2" - } else { - record_test XFAIL "[file join {*}$test] on nr2 was rightfully excluded" - } - } -} - -# All done. -dg-finish - -gcc_parallel_test_enable 1 diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude deleted file mode 100644 index c020e36..0000000 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ /dev/null @@ -1,17 +0,0 @@ -canonical_paths1.rs -issue-3315-2.rs -privacy5.rs -privacy8.rs -pub_restricted_1.rs -pub_restricted_2.rs -pub_restricted_3.rs -issue-2905-2.rs -derive-default1.rs -derive-eq-invalid.rs -torture/alt_patterns1.rs -torture/name_resolve1.rs -issue-3663.rs -issue-3671.rs -issue-3652.rs -issue-3649.rs -# please don't delete the trailing newline diff --git a/gcc/testsuite/rust/compile/offset_of1.rs b/gcc/testsuite/rust/compile/offset_of1.rs new file mode 100644 index 0000000..5b79699 --- /dev/null +++ b/gcc/testsuite/rust/compile/offset_of1.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-frust-compile-until=lowering -frust-assume-builtin-offset-of" } + +pub struct Foo { + a: i32, +} + +fn main() { + let _ = offset_of!(Foo, a); // valid + let _ = offset_of!("bloop", a); // { dg-error "could not parse type" } + let _ = offset_of!(Foo, 15); // { dg-error "could not parse field" } +} diff --git a/gcc/testsuite/rust/compile/offset_of2.rs b/gcc/testsuite/rust/compile/offset_of2.rs new file mode 100644 index 0000000..d4ad9c2 --- /dev/null +++ b/gcc/testsuite/rust/compile/offset_of2.rs @@ -0,0 +1,9 @@ +// { dg-additional-options "-frust-compile-until=compilation -frust-assume-builtin-offset-of" } + +pub struct Foo { + a: i32, +} + +fn main() { + let _ = offset_of!(Foo, a); // valid +} diff --git a/gcc/testsuite/rust/compile/parse_simple_path_fail_1.rs b/gcc/testsuite/rust/compile/parse_simple_path_fail_1.rs new file mode 100644 index 0000000..c112e40 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_simple_path_fail_1.rs @@ -0,0 +1,3 @@ +pub(in crate::) struct S; +// { dg-error "expecting ... but .::. found" "" { target *-*-* } .-1 } +// { dg-error "failed to parse item in crate" "" { target *-*-* } .-2 } diff --git a/gcc/testsuite/rust/compile/parse_simple_path_fail_2.rs b/gcc/testsuite/rust/compile/parse_simple_path_fail_2.rs new file mode 100644 index 0000000..94c49c3 --- /dev/null +++ b/gcc/testsuite/rust/compile/parse_simple_path_fail_2.rs @@ -0,0 +1,9 @@ +mod A { + struct B; +} + +use A{B}; +// { dg-error "unexpected token" "" { target *-*-* } .-1 } +// { dg-error "could not parse use tree" "" { target *-*-* } .-2 } +// { dg-error "failed to parse item in crate" "" { target *-*-* } 10 } +// ^^^ TODO: should the above error happen at line 10? diff --git a/gcc/testsuite/rust/compile/pub_restricted_1.rs b/gcc/testsuite/rust/compile/pub_restricted_1.rs index 9bda968..2afbeb4 100644 --- a/gcc/testsuite/rust/compile/pub_restricted_1.rs +++ b/gcc/testsuite/rust/compile/pub_restricted_1.rs @@ -6,8 +6,8 @@ pub mod foo { } } -pub(in foo::fah::baz) struct A1; // { dg-error "cannot find simple path segment .fah." } -pub(in fro::bulator::saindoux) struct A2; // { dg-error "cannot find simple path segment .fro." } -pub(in foo::bar::saindoux) struct A3; // { dg-error "cannot find simple path segment .saindoux." } +pub(in foo::fah::baz) struct A1; // { dg-error "could not resolve path .foo::fah::baz." } +pub(in fro::bulator::saindoux) struct A2; // { dg-error "could not resolve path .fro::bulator::saindoux." } +pub(in foo::bar::saindoux) struct A3; // { dg-error "could not resolve path .foo::bar::saindoux." } fn main() {} diff --git a/gcc/testsuite/rust/compile/pub_restricted_2.rs b/gcc/testsuite/rust/compile/pub_restricted_2.rs index 8588f27..fea9379 100644 --- a/gcc/testsuite/rust/compile/pub_restricted_2.rs +++ b/gcc/testsuite/rust/compile/pub_restricted_2.rs @@ -3,16 +3,16 @@ mod foo { mod bar { mod baz { - pub(in baz) struct A0; - pub(in bar::baz) struct A1; + pub(in super::baz) struct A0; + pub(in super::super::bar::baz) struct A1; pub(in foo::bar::baz) struct A2; mod sain { mod doux {} } - pub(in sain) struct A3; // { dg-error "restricted path is not an ancestor of the current module" } - pub(in sain::doux) struct A4; // { dg-error "restricted path is not an ancestor of the current module" } + pub(in self::sain) struct A3; // { dg-error "restricted path is not an ancestor of the current module" } + pub(in self::sain::doux) struct A4; // { dg-error "restricted path is not an ancestor of the current module" } } } } diff --git a/gcc/testsuite/rust/execute/same_field_name.rs b/gcc/testsuite/rust/compile/same_field_name.rs index d57562b..8e5b78c 100644 --- a/gcc/testsuite/rust/execute/same_field_name.rs +++ b/gcc/testsuite/rust/compile/same_field_name.rs @@ -1,7 +1,7 @@ // https://doc.rust-lang.org/error_codes/E0124.html fn main() { struct Foo { - field1: i32, // { dg-error "field .field1. is already declared" } + field1: i32, field1: i32, // { dg-error "field .field1. is already declared" } field1: i32, // { dg-error "field .field1. is already declared" } } diff --git a/gcc/testsuite/rust/compile/self-in-impl.rs b/gcc/testsuite/rust/compile/self-in-impl.rs new file mode 100644 index 0000000..a567897 --- /dev/null +++ b/gcc/testsuite/rust/compile/self-in-impl.rs @@ -0,0 +1,15 @@ +// the error message here is what rustc >=1.66 emits +// rustc <1.66 emits a "cycle detected" error when +// trying to calculate the impl type +// +// since we aren't trying to match error messages too closely +// and the >=1.66 error message is nicer +// we may as well mimic that + +impl ((Self, i32)) {} +// { dg-error ".Self. is not valid in the self" "" { target *-*-* } .-1 } + +trait Foo {} + +impl Foo for ((Self, i32)) {} +// { dg-error ".Self. is not valid in the self" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/rust/compile/self_import_namespace.rs b/gcc/testsuite/rust/compile/self_import_namespace.rs index 2d9b2ed..a63c1d7 100644 --- a/gcc/testsuite/rust/compile/self_import_namespace.rs +++ b/gcc/testsuite/rust/compile/self_import_namespace.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - mod bar { pub mod foo {} pub fn foo() {} diff --git a/gcc/testsuite/rust/compile/silly-order-bug.rs b/gcc/testsuite/rust/compile/silly-order-bug.rs new file mode 100644 index 0000000..0d9cf1d --- /dev/null +++ b/gcc/testsuite/rust/compile/silly-order-bug.rs @@ -0,0 +1,8 @@ +#[lang = "sized"] +trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; + type Output; +} diff --git a/gcc/testsuite/rust/compile/slicepattern-size-mismatch.rs b/gcc/testsuite/rust/compile/slicepattern-size-mismatch.rs new file mode 100644 index 0000000..b54b532 --- /dev/null +++ b/gcc/testsuite/rust/compile/slicepattern-size-mismatch.rs @@ -0,0 +1,8 @@ +fn main() { + let arr = [0, 1]; + + match arr { + [0, 1, 2] => {} // { dg-error "pattern requires 3 elements but array has 2 .E0527." } + _ => {} + } +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/compile/torture/extern_mod2.rs b/gcc/testsuite/rust/compile/torture/extern_mod2.rs index 4984d5d..f3a4f79 100644 --- a/gcc/testsuite/rust/compile/torture/extern_mod2.rs +++ b/gcc/testsuite/rust/compile/torture/extern_mod2.rs @@ -12,6 +12,12 @@ mod no_leading_equal; #[path = "modules/valid_path.rs"] mod extra_spaces; +#[path = ""] // { dg-error "path attributes must contain a filename" } +mod empty_path; // { dg-error "no candidate found" } + +#[path = " "] // { dg-error "path attributes must contain a filename" } +mod path_with_spaces; // { dg-error "no candidate found" } + #[path] // { dg-error "path attributes must contain a filename" } mod error; // { dg-error "no candidate found" } diff --git a/gcc/testsuite/rust/compile/torture/generics29.rs b/gcc/testsuite/rust/compile/torture/generics29.rs index e9c693e..baf53e4 100644 --- a/gcc/testsuite/rust/compile/torture/generics29.rs +++ b/gcc/testsuite/rust/compile/torture/generics29.rs @@ -5,7 +5,6 @@ struct Foo<A, B>(A, B); impl Foo<i32, f32> { fn test<X>(self, a: X) -> X { - // { dg-warning "unused name" "" { target *-*-* } .-1 } a } } diff --git a/gcc/testsuite/rust/compile/torture/generics30.rs b/gcc/testsuite/rust/compile/torture/generics30.rs index 24ae58f..a84f140 100644 --- a/gcc/testsuite/rust/compile/torture/generics30.rs +++ b/gcc/testsuite/rust/compile/torture/generics30.rs @@ -5,7 +5,6 @@ struct Foo<A, B>(A, B); impl<T> Foo<T, f32> { fn test<X>(self, a: X) -> X { - // { dg-warning "unused name" "" { target *-*-* } .-1 } a } } diff --git a/gcc/testsuite/rust/compile/torture/traits3.rs b/gcc/testsuite/rust/compile/torture/traits3.rs index d805da5..dad6dda 100644 --- a/gcc/testsuite/rust/compile/torture/traits3.rs +++ b/gcc/testsuite/rust/compile/torture/traits3.rs @@ -10,7 +10,6 @@ struct Baz; impl Foo for Baz { fn Bar(self) -> i32 { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } 123 } } diff --git a/gcc/testsuite/rust/compile/torture/traits7.rs b/gcc/testsuite/rust/compile/torture/traits7.rs index 8e4472d..545fd39 100644 --- a/gcc/testsuite/rust/compile/torture/traits7.rs +++ b/gcc/testsuite/rust/compile/torture/traits7.rs @@ -13,7 +13,6 @@ impl Foo for Bar { // { dg-warning "unused name" "" { target *-*-* } .-1 } fn test(self) {} - // { dg-warning "unused name" "" { target *-*-* } .-1 } } fn main() { diff --git a/gcc/testsuite/rust/compile/torture/unended-raw-byte-string.rs b/gcc/testsuite/rust/compile/torture/unended-raw-byte-string.rs new file mode 100644 index 0000000..91a3c9a --- /dev/null +++ b/gcc/testsuite/rust/compile/torture/unended-raw-byte-string.rs @@ -0,0 +1,6 @@ +// { dg-excess-errors "...." } +fn main() { + // { dg-error "unended raw byte string literal" "" { target *-*-* } .+1 } + let s = br##"123"# +} + diff --git a/gcc/testsuite/rust/compile/traits9.rs b/gcc/testsuite/rust/compile/traits9.rs index bb3034d..f4308e8 100644 --- a/gcc/testsuite/rust/compile/traits9.rs +++ b/gcc/testsuite/rust/compile/traits9.rs @@ -11,6 +11,5 @@ fn main() { a = Foo(123); let b: &dyn Bar = &a; - // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied" "" { target *-*-* } .-1 } - // { dg-error "expected" "" { target *-*-* } .-2 } + // { dg-error "bounds not satisfied for Foo .Bar. is not satisfied .E0277." "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/compile/try_block1.rs b/gcc/testsuite/rust/compile/try_block1.rs new file mode 100644 index 0000000..7ae0536 --- /dev/null +++ b/gcc/testsuite/rust/compile/try_block1.rs @@ -0,0 +1,89 @@ +// { dg-additional-options "-frust-edition=2018" } + +#[lang = "sized"] +trait Sized {} + +enum Result<T, E> { + Ok(T), + Err(E) +} + +pub trait Try { + /// The type of this value when viewed as successful. + #[unstable(feature = "try_trait", issue = "42327")] + type Ok; + /// The type of this value when viewed as failed. + #[unstable(feature = "try_trait", issue = "42327")] + type Error; + + /// Applies the "?" operator. A return of `Ok(t)` means that the + /// execution should continue normally, and the result of `?` is the + /// value `t`. A return of `Err(e)` means that execution should branch + /// to the innermost enclosing `catch`, or return from the function. + /// + /// If an `Err(e)` result is returned, the value `e` will be "wrapped" + /// in the return type of the enclosing scope (which must itself implement + /// `Try`). Specifically, the value `X::from_error(From::from(e))` + /// is returned, where `X` is the return type of the enclosing function. + #[lang = "into_result"] + #[unstable(feature = "try_trait", issue = "42327")] + fn into_result(self) -> Result<Self::Ok, Self::Error>; + + /// Wrap an error value to construct the composite result. For example, + /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. + #[lang = "from_error"] + #[unstable(feature = "try_trait", issue = "42327")] + fn from_error(v: Self::Error) -> Self; + + /// Wrap an OK value to construct the composite result. For example, + /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. + #[lang = "from_ok"] + #[unstable(feature = "try_trait", issue = "42327")] + fn from_ok(v: Self::Ok) -> Self; +} + +pub struct NoneError; + + +pub enum Option<T> { + /// No value + None, + /// Some value `T` + Some(T), +} + +impl<T> Option<T> { + pub fn ok_or<E>(self, err: E) -> Result<T, E> { + match self { + Some(ok) => Result::Ok(ok), + None => Result::Err(err) + } + } +} + +use Option::*; + +#[unstable(feature = "try_trait", issue = "42327")] +impl<T> Try for Option<T> { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result<T, NoneError> { + self.ok_or(NoneError) + } + + #[inline] + fn from_ok(v: T) -> Self { + Some(v) + } + + #[inline] + fn from_error(_: NoneError) -> Self { + None + } +} + +fn main() { + let _: Option<i32> = try { 15i32 }; +} diff --git a/gcc/testsuite/rust/compile/tuple_mismatch.rs b/gcc/testsuite/rust/compile/tuple_mismatch.rs index 828586b..1ff358b 100644 --- a/gcc/testsuite/rust/compile/tuple_mismatch.rs +++ b/gcc/testsuite/rust/compile/tuple_mismatch.rs @@ -3,6 +3,7 @@ fn main() { let (_,) = (1, 2); // { dg-error "expected a tuple with 2 elements, found one with 1 element" } let (_, _) = (1, 2, 3); // { dg-error "expected a tuple with 3 elements, found one with 2 elements" } let (_, _) = (1,); // { dg-error "expected a tuple with 1 element, found one with 2 elements" } + let (_, .., _) = (1,); // { dg-error "expected a tuple with 1 element, found one with 2 elements" } } // The lhs and rhs sizes don't match, but we still resolve 'a' to be bool, we don't diff --git a/gcc/testsuite/rust/compile/unify-errors1.rs b/gcc/testsuite/rust/compile/unify-errors1.rs new file mode 100644 index 0000000..0fe95ef --- /dev/null +++ b/gcc/testsuite/rust/compile/unify-errors1.rs @@ -0,0 +1,49 @@ +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +trait MyTrait {} + +struct Wrapper<T: MyTrait> { + value: T, +} + +struct NotImpl; + +trait A {} +trait B {} + +struct Wrapper2<T: A + B> { + value: T, +} + +struct NotImpl2; + +impl A for NotImpl2 {} + +fn takes_tuple(x: (i32, bool)) {} + +fn requires_copy<T: Copy>(value: T) {} + +pub fn test() { + takes_tuple((1, 2)); + // { dg-error "mismatched types, expected .bool. but got .<integer>. .E0308." "" { target *-*-* } .-1 } + + takes_tuple((1, 2, 3)); + // { dg-error "mismatched types, expected ..i32, bool.. but got ..<integer>, <integer>, <integer>.. .E0308." "" { target *-*-* } .-1 } + + takes_tuple("hello"); + // { dg-error "mismatched types, expected ..i32, bool.. but got .& str. .E0308." "" { target *-*-* } .-1 } + + let x = &mut 5; + requires_copy(x); + // { dg-error "bounds not satisfied for &mut <integer> .Copy. is not satisfied .E0277." "" { target *-*-* } .-1 } + + let _x = Wrapper { value: NotImpl }; + // { dg-error "bounds not satisfied for NotImpl .MyTrait. is not satisfied .E0277." "" { target *-*-* } .-1 } + + let _x = Wrapper2 { value: NotImpl2 }; + // { dg-error "bounds not satisfied for NotImpl2 .B. is not satisfied .E0277." "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/rust/compile/use_1.rs b/gcc/testsuite/rust/compile/use_1.rs index e8e2037..21ee3e1 100644 --- a/gcc/testsuite/rust/compile/use_1.rs +++ b/gcc/testsuite/rust/compile/use_1.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } mod frob {} use foo::bar::baz; // { dg-error "unresolved import .foo::bar::baz." } diff --git a/gcc/testsuite/rust/compile/usize1.rs b/gcc/testsuite/rust/compile/usize1.rs index 36cb99b..08f6c9c 100644 --- a/gcc/testsuite/rust/compile/usize1.rs +++ b/gcc/testsuite/rust/compile/usize1.rs @@ -1,5 +1,5 @@ fn main() { let a = [1, 2, 3]; let b: u32 = 1; - let c = a[b]; // { dg-error "the type ...integer..CAPACITY.. cannot be indexed by .u32." } + let c = a[b]; // { dg-error "the type ...integer.; 3.. cannot be indexed by .u32." } } diff --git a/gcc/testsuite/rust/compile/while_let1.rs b/gcc/testsuite/rust/compile/while_let1.rs new file mode 100644 index 0000000..a3fa305 --- /dev/null +++ b/gcc/testsuite/rust/compile/while_let1.rs @@ -0,0 +1,109 @@ +// use self::Ordering::*; +// use Ordering::*; + +// enum Ordering { +// A, +// B, +// } + +// fn foo(_: Ordering) {} + +// fn main() { +// let a = A; + +// foo(a); +// foo(B); +// } + +#[lang = "sized"] +trait Sized {} + +enum Result<T, E> { + Ok(T), + Err(E), +} + +pub trait Try { + /// The type of this value when viewed as successful. + #[unstable(feature = "try_trait", issue = "42327")] + type Ok; + /// The type of this value when viewed as failed. + #[unstable(feature = "try_trait", issue = "42327")] + type Error; + + /// Applies the "?" operator. A return of `Ok(t)` means that the + /// execution should continue normally, and the result of `?` is the + /// value `t`. A return of `Err(e)` means that execution should branch + /// to the innermost enclosing `catch`, or return from the function. + /// + /// If an `Err(e)` result is returned, the value `e` will be "wrapped" + /// in the return type of the enclosing scope (which must itself implement + /// `Try`). Specifically, the value `X::from_error(From::from(e))` + /// is returned, where `X` is the return type of the enclosing function. + #[lang = "into_result"] + #[unstable(feature = "try_trait", issue = "42327")] + fn into_result(self) -> Result<Self::Ok, Self::Error>; + + /// Wrap an error value to construct the composite result. For example, + /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. + #[lang = "from_error"] + #[unstable(feature = "try_trait", issue = "42327")] + fn from_error(v: Self::Error) -> Self; + + /// Wrap an OK value to construct the composite result. For example, + /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. + #[lang = "from_ok"] + #[unstable(feature = "try_trait", issue = "42327")] + fn from_ok(v: Self::Ok) -> Self; +} + +pub struct NoneError; + +pub enum Option<T> { + /// No value + None, + /// Some value `T` + Some(T), +} + +impl<T> Option<T> { + pub fn ok_or<E>(self, err: E) -> Result<T, E> { + match self { + Some(ok) => Result::Ok(ok), + None => Result::Err(err), + } + } +} + +use Option::*; + +#[unstable(feature = "try_trait", issue = "42327")] +impl<T> Try for Option<T> { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result<T, NoneError> { + self.ok_or(NoneError) + } + + #[inline] + fn from_ok(v: T) -> Self { + Some(v) + } + + #[inline] + fn from_error(_: NoneError) -> Self { + None + } +} + +fn foo() -> Option<i32> { + Option::Some(15) +} + +fn main() { + // let _: Option<i32> = try { 15i32 }; + + while let Option::Some(15) = foo() {} +} diff --git a/gcc/testsuite/rust/compile/while_let_without_label.rs b/gcc/testsuite/rust/compile/while_let_without_label.rs new file mode 100644 index 0000000..e04e4b5 --- /dev/null +++ b/gcc/testsuite/rust/compile/while_let_without_label.rs @@ -0,0 +1,11 @@ +// { dg-additional-options "-frust-compile-until=lowering" } + +enum Foo { + A(i32), +} + +fn main() { + let b = Foo::A(15); + + while let Foo::A(x) = b {} +} diff --git a/gcc/testsuite/rust/compile/xfail/name_resolution21.rs b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs index df48d00..fc8e94b 100644 --- a/gcc/testsuite/rust/compile/xfail/name_resolution21.rs +++ b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - pub mod foo { pub macro bar() {} } diff --git a/gcc/testsuite/rust/execute/black_box.rs b/gcc/testsuite/rust/execute/black_box.rs index 7a9920e..58d10a3 100644 --- a/gcc/testsuite/rust/execute/black_box.rs +++ b/gcc/testsuite/rust/execute/black_box.rs @@ -21,10 +21,11 @@ pub fn black_box<T>(mut dummy: T) -> T { dummy } -fn main() { +fn main() -> i32 { let dummy: i32 = 42; let result = black_box(dummy); unsafe { printf("Value is: %i\n\0" as *const str as *const i8, result); } + 0 } diff --git a/gcc/testsuite/rust/execute/execute.exp b/gcc/testsuite/rust/execute/execute.exp new file mode 100644 index 0000000..3754778 --- /dev/null +++ b/gcc/testsuite/rust/execute/execute.exp @@ -0,0 +1,33 @@ +# Copyright (C) 2021-2025 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Execute tests. + +# Load support procs. +load_lib rust-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +set saved-dg-do-what-default ${dg-do-what-default} + +set dg-do-what-default "run" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" "" +set dg-do-what-default ${saved-dg-do-what-default} + +# All done. +dg-finish diff --git a/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs b/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs new file mode 100644 index 0000000..b0a3d25 --- /dev/null +++ b/gcc/testsuite/rust/execute/inline_asm_inout_ident.rs @@ -0,0 +1,23 @@ +/* { dg-output "Value is: 5\r*\n" } */ +#![feature(rustc_attrs)] + +extern "C" { + fn printf(s: *const i8, ...); +} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +fn main() -> i32 { + let x: i32; + // `inout` can also move values to different places + unsafe { + asm!("inc {}", inout(reg) 4u64=>x); + } + unsafe { + printf("Value is: %i\n\0" as *const str as *const i8, x); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/inline_asm_inout_var.rs b/gcc/testsuite/rust/execute/inline_asm_inout_var.rs new file mode 100644 index 0000000..ff101b8 --- /dev/null +++ b/gcc/testsuite/rust/execute/inline_asm_inout_var.rs @@ -0,0 +1,24 @@ +/* { dg-output "Value is: 5\r*\n" } */ +#![feature(rustc_attrs)] + +extern "C" { + fn printf(s: *const i8, ...); +} + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +fn main() -> i32 { + let y: i32 = 4; + let x: i32; + // `inout` can also move values to different places + unsafe { + asm!("inc {}", inout(reg) y=>x); + } + unsafe { + printf("Value is: %i\n\0" as *const str as *const i8, x); + } + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs b/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs new file mode 100644 index 0000000..0431629 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs @@ -0,0 +1,189 @@ +/* { dg-output "less\r*" }*/ +mod core { + mod option { + pub enum Option<T> { + None, + Some(T), + } + } + + mod marker { + #[lang = "phantom_data"] + pub struct PhantomData<T: ?Sized>; + + #[lang = "structural_peq"] + pub trait StructuralPartialEq {} + + #[lang = "structural_teq"] + pub trait StructuralEq {} + + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq<Self> { + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + } + + pub trait Ord: Eq + PartialOrd<Self> { + fn cmp(&self, other: &Self) -> Ordering; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::option::Option; + +// Needed impls for primitives +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self < *other { + Option::Some(Ordering::Less) + } else if *self > *other { + Option::Some(Ordering::Greater) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Eq for i32 {} +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self < *other { + Ordering::Less + } else if *self > *other { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +// Manual impl for struct Bar +struct Bar { + a: i32, + b: i32, +} + +impl PartialEq for Bar { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) && self.b.eq(&other.b) + } +} + +impl Eq for Bar {} + +impl PartialOrd for Bar { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + match self.a.partial_cmp(&other.a) { + Option::Some(Ordering::Equal) => self.b.partial_cmp(&other.b), + ord => ord, + } + } +} + +impl Ord for Bar { + fn cmp(&self, other: &Self) -> Ordering { + match self.a.cmp(&other.a) { + Ordering::Equal => self.b.cmp(&other.b), + ord => ord, + } + } +} + +// External print shim +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Bar { a: 1, b: 2 }; + let y = Bar { a: 1, b: 3 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Less) => print("less"), + Option::Some(Ordering::Greater) => print("greater"), + Option::Some(Ordering::Equal) => print("equal"), + _ => print("none"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs b/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs new file mode 100644 index 0000000..b6a9695 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs @@ -0,0 +1,197 @@ +/* { dg-output "<><=>=\r*" } */ +/* { dg-options "-w" } */ +mod core { + mod option { + pub enum Option<T> { + None, + Some(T), + } + } + + mod marker { + #[lang = "phantom_data"] + pub struct PhantomData<T: ?Sized>; + + #[lang = "structural_peq"] + pub trait StructuralPartialEq {} + + #[lang = "structural_teq"] + pub trait StructuralEq {} + + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq<Self> { + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) | Option::Some(Ordering::Equal) => true, + _ => false, + } + } + } + + pub trait Ord: Eq + PartialOrd<Self> { + fn cmp(&self, other: &Self) -> Ordering; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::option::Option; + +// Needed impls for primitives +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self < *other { + Option::Some(Ordering::Less) + } else if *self > *other { + Option::Some(Ordering::Greater) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Eq for i32 {} +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self < *other { + Ordering::Less + } else if *self > *other { + Ordering::Greater + } else { + Ordering::Equal + } + } +} + +// Manual impl for struct Bar +struct Bar { + a: i32, + b: i32, +} + +impl PartialEq for Bar { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) && self.b.eq(&other.b) + } +} + +impl Eq for Bar {} + +impl PartialOrd for Bar { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + match self.a.partial_cmp(&other.a) { + Option::Some(Ordering::Equal) => self.b.partial_cmp(&other.b), + ord => ord, + } + } +} + +impl Ord for Bar { + fn cmp(&self, other: &Self) -> Ordering { + match self.a.cmp(&other.a) { + Ordering::Equal => self.b.cmp(&other.b), + ord => ord, + } + } +} + +// External print shim +extern "C" { + fn printf(s: *const i8); +} + +fn print(s: &str) { + unsafe { + printf(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Bar { a: 1, b: 2 }; + let b = Bar { a: 1, b: 3 }; + let c = Bar { a: 1, b: 2 }; + + if a < b { + print("<"); + } + if b > a { + print(">"); + } + if a <= c { + print("<="); + } + if b >= c { + print(">="); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_abort.rs b/gcc/testsuite/rust/execute/torture/builtin_abort.rs index 9f2d8c2..8c8259a 100644 --- a/gcc/testsuite/rust/execute/torture/builtin_abort.rs +++ b/gcc/testsuite/rust/execute/torture/builtin_abort.rs @@ -9,6 +9,6 @@ mod intrinsics { } pub fn main () -> i32 { - abort(); + intrinsics::abort(); 0 } diff --git a/gcc/testsuite/rust/execute/torture/const-generics-1.rs b/gcc/testsuite/rust/execute/torture/const-generics-1.rs new file mode 100644 index 0000000..dbb7afe --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const-generics-1.rs @@ -0,0 +1,24 @@ +#[lang = "sized"] +trait Sized {} + +struct Foo<const N: usize>; + +impl Foo<1> { + fn call(&self) -> i32 { + 10 + } +} + +impl Foo<2> { + fn call(&self) -> i32 { + 20 + } +} + +fn main() -> i32 { + let a = Foo::<1> {}; + let b = Foo::<2> {}; + let aa = a.call(); + let bb = b.call(); + bb - aa - 10 +} diff --git a/gcc/testsuite/rust/execute/torture/const_block1.rs b/gcc/testsuite/rust/execute/torture/const_block1.rs new file mode 100644 index 0000000..eaf3432 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/const_block1.rs @@ -0,0 +1,9 @@ +const X: i32 = const { + let a = 15; + let b = 14; + a + b +}; + +fn main() -> i32 { + X - 29 +} diff --git a/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs new file mode 100644 index 0000000..e316017 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs @@ -0,0 +1,80 @@ +// { dg-output "true\r*\nfalse\r*\nfalse\r*\nfalse\r*\nfalse\r*\n" } + +#![feature(intrinsics)] + +pub mod core { + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "structural_peq"] +trait StructuralPartialEq {} + +#[lang = "eq"] +pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + /// This method tests for `!=`. + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +#[derive(PartialEq)] +enum Foo { + A { a: i32, b: i32 }, + B(i32, i32), + C, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(b: bool) { + if b { + unsafe { puts("true\0" as *const str as *const i8) } + } else { + unsafe { puts("false\0" as *const str as *const i8) } + } +} + +fn main() -> i32 { + let x = Foo::A { a: 15, b: 14 }; + + let b1 = x == Foo::A { a: 15, b: 14 }; + let b12 = x == Foo::A { a: 15, b: 19 }; + let b13 = x == Foo::A { a: 19, b: 14 }; + let b2 = x == Foo::B(15, 14); + let b3 = x == Foo::C; + + print(b1); + print(b12); + print(b13); + print(b2); + print(b3); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/for-loop1.rs b/gcc/testsuite/rust/execute/torture/for-loop1.rs index 5a6a70c..3342189 100644 --- a/gcc/testsuite/rust/execute/torture/for-loop1.rs +++ b/gcc/testsuite/rust/execute/torture/for-loop1.rs @@ -102,30 +102,30 @@ mod ptr { #[lang = "const_ptr"] impl<T> *const T { pub unsafe fn offset(self, count: isize) -> *const T { - intrinsics::offset(self, count) + crate::intrinsics::offset(self, count) } } #[lang = "mut_ptr"] impl<T> *mut T { pub unsafe fn offset(self, count: isize) -> *mut T { - intrinsics::offset(self, count) as *mut T + crate::intrinsics::offset(self, count) as *mut T } } pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; - let len = mem::size_of::<T>() * count; + let len = crate::mem::size_of::<T>() * count; swap_nonoverlapping_bytes(x, y, len) } pub unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. - if mem::size_of::<T>() < 32 { + if crate::mem::size_of::<T>() < 32 { let z = read(x); - intrinsics::copy_nonoverlapping(y, x, 1); + crate::intrinsics::copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); @@ -133,12 +133,12 @@ mod ptr { } pub unsafe fn write<T>(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) + crate::intrinsics::move_val_init(&mut *dst, src) } pub unsafe fn read<T>(src: *const T) -> T { - let mut tmp: T = mem::uninitialized(); - intrinsics::copy_nonoverlapping(src, &mut tmp, 1); + let mut tmp: T = crate::mem::uninitialized(); + crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1); tmp } @@ -146,7 +146,7 @@ mod ptr { struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); - let block_size = mem::size_of::<Block>(); + let block_size = crate::mem::size_of::<Block>(); // Loop through x & y, copying them `Block` at a time // The optimizer should unroll the loop fully for most types @@ -155,31 +155,31 @@ mod ptr { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t: Block = mem::uninitialized(); + let mut t: Block = crate::mem::uninitialized(); let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); // Swap a block of bytes of x & y, using t as a temporary buffer // This should be optimized into efficient SIMD operations where available - intrinsics::copy_nonoverlapping(x, t, block_size); - intrinsics::copy_nonoverlapping(y, x, block_size); - intrinsics::copy_nonoverlapping(t, y, block_size); + crate::intrinsics::copy_nonoverlapping(x, t, block_size); + crate::intrinsics::copy_nonoverlapping(y, x, block_size); + crate::intrinsics::copy_nonoverlapping(t, y, block_size); i += block_size; } if i < len { // Swap any remaining bytes - let mut t: UnalignedBlock = mem::uninitialized(); + let mut t: UnalignedBlock = crate::mem::uninitialized(); let rem = len - i; let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); - intrinsics::copy_nonoverlapping(x, t, rem); - intrinsics::copy_nonoverlapping(y, x, rem); - intrinsics::copy_nonoverlapping(t, y, rem); + crate::intrinsics::copy_nonoverlapping(x, t, rem); + crate::intrinsics::copy_nonoverlapping(y, x, rem); + crate::intrinsics::copy_nonoverlapping(t, y, rem); } } } @@ -194,7 +194,7 @@ mod mem { pub fn swap<T>(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping_one(x, y); + crate::ptr::swap_nonoverlapping_one(x, y); } } @@ -204,7 +204,7 @@ mod mem { } pub unsafe fn uninitialized<T>() -> T { - intrinsics::uninit() + crate::intrinsics::uninit() } } diff --git a/gcc/testsuite/rust/execute/torture/for-loop2.rs b/gcc/testsuite/rust/execute/torture/for-loop2.rs index 5ba2cd1..4f5dfe1 100644 --- a/gcc/testsuite/rust/execute/torture/for-loop2.rs +++ b/gcc/testsuite/rust/execute/torture/for-loop2.rs @@ -101,30 +101,30 @@ mod ptr { #[lang = "const_ptr"] impl<T> *const T { pub unsafe fn offset(self, count: isize) -> *const T { - intrinsics::offset(self, count) + crate::intrinsics::offset(self, count) } } #[lang = "mut_ptr"] impl<T> *mut T { pub unsafe fn offset(self, count: isize) -> *mut T { - intrinsics::offset(self, count) as *mut T + crate::intrinsics::offset(self, count) as *mut T } } pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; - let len = mem::size_of::<T>() * count; + let len = crate::mem::size_of::<T>() * count; swap_nonoverlapping_bytes(x, y, len) } pub unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. - if mem::size_of::<T>() < 32 { + if crate::mem::size_of::<T>() < 32 { let z = read(x); - intrinsics::copy_nonoverlapping(y, x, 1); + crate::intrinsics::copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); @@ -132,12 +132,12 @@ mod ptr { } pub unsafe fn write<T>(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) + crate::intrinsics::move_val_init(&mut *dst, src) } pub unsafe fn read<T>(src: *const T) -> T { - let mut tmp: T = mem::uninitialized(); - intrinsics::copy_nonoverlapping(src, &mut tmp, 1); + let mut tmp: T = crate::mem::uninitialized(); + crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1); tmp } @@ -145,7 +145,7 @@ mod ptr { struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); - let block_size = mem::size_of::<Block>(); + let block_size = crate::mem::size_of::<Block>(); // Loop through x & y, copying them `Block` at a time // The optimizer should unroll the loop fully for most types @@ -154,31 +154,31 @@ mod ptr { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t: Block = mem::uninitialized(); + let mut t: Block = crate::mem::uninitialized(); let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); // Swap a block of bytes of x & y, using t as a temporary buffer // This should be optimized into efficient SIMD operations where available - intrinsics::copy_nonoverlapping(x, t, block_size); - intrinsics::copy_nonoverlapping(y, x, block_size); - intrinsics::copy_nonoverlapping(t, y, block_size); + crate::intrinsics::copy_nonoverlapping(x, t, block_size); + crate::intrinsics::copy_nonoverlapping(y, x, block_size); + crate::intrinsics::copy_nonoverlapping(t, y, block_size); i += block_size; } if i < len { // Swap any remaining bytes - let mut t: UnalignedBlock = mem::uninitialized(); + let mut t: UnalignedBlock = crate::mem::uninitialized(); let rem = len - i; let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); - intrinsics::copy_nonoverlapping(x, t, rem); - intrinsics::copy_nonoverlapping(y, x, rem); - intrinsics::copy_nonoverlapping(t, y, rem); + crate::intrinsics::copy_nonoverlapping(x, t, rem); + crate::intrinsics::copy_nonoverlapping(y, x, rem); + crate::intrinsics::copy_nonoverlapping(t, y, rem); } } } @@ -193,7 +193,7 @@ mod mem { pub fn swap<T>(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping_one(x, y); + crate::ptr::swap_nonoverlapping_one(x, y); } } @@ -203,7 +203,7 @@ mod mem { } pub unsafe fn uninitialized<T>() -> T { - intrinsics::uninit() + crate::intrinsics::uninit() } } diff --git a/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs b/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs new file mode 100644 index 0000000..c73ea34 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs @@ -0,0 +1,32 @@ +#[lang = "sized"] +trait Sized {} + +macro_rules! impl_foo { + () => { impl Foo } +} + +pub trait Foo {} + +pub trait Bar { + type Baz; +} + +struct MyBaz; // { dg-warning "struct is never constructed" } +impl Foo for MyBaz {} + +struct MyBar; + +impl Bar for MyBar { + type Baz = MyBaz; +} + +pub fn foo(_value: impl Bar<Baz = impl_foo!()>) -> i32 { + 15 +} + +fn main() -> i32 { + let bar = MyBar; + let result: i32 = foo(bar); + + result - 15 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_desugar.rs b/gcc/testsuite/rust/execute/torture/impl_desugar.rs new file mode 100644 index 0000000..22d3951 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_desugar.rs @@ -0,0 +1,32 @@ +#[lang = "sized"] +trait Sized {} + +pub trait Foo {} + +pub trait Bar { + type Baz; +} + +struct MyBaz; // { dg-warning "struct is never constructed" } +impl Foo for MyBaz {} + +struct MyBar; + +impl Bar for MyBar { + type Baz = MyBaz; +} + +pub fn foo<T, U>(_value: T) -> i32 +where + T: Bar<Baz = U>, + U: Foo, +{ + 15 +} + +fn main() -> i32 { + let bar = MyBar; + let result: i32 = foo::<MyBar, MyBaz>(bar); + + result - 15 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_rpit1.rs b/gcc/testsuite/rust/execute/torture/impl_rpit1.rs new file mode 100644 index 0000000..8ce5f21 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_rpit1.rs @@ -0,0 +1,28 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct Thing(i32); + +impl Foo for Thing { + fn id(&self) -> i32 { + self.0 + } +} + +fn make_thing(a: i32) -> impl Foo { + Thing(a) +} + +fn use_foo(f: impl Foo) -> i32 { + f.id() +} + +fn main() -> i32 { + let value = make_thing(42); + let val = use_foo(value); + val - 42 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_rpit2.rs b/gcc/testsuite/rust/execute/torture/impl_rpit2.rs new file mode 100644 index 0000000..f7cbbb6 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_rpit2.rs @@ -0,0 +1,36 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct Thing(i32); + +impl Thing { + fn double(&self) -> i32 { + // { dg-warning "associated function is never used: .double." "" { target *-*-* } .-1 } + self.0 * 2 + } +} + +impl Foo for Thing { + fn id(&self) -> i32 { + self.0 + } +} + +fn make_thing(a: i32) -> impl Foo { + Thing(a) +} + +fn use_foo(f: impl Foo) -> i32 { + f.id() +} + +fn main() -> i32 { + let value = make_thing(21); + let id = use_foo(value); + + id - 21 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_rpit3.rs b/gcc/testsuite/rust/execute/torture/impl_rpit3.rs new file mode 100644 index 0000000..dd68eb2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_rpit3.rs @@ -0,0 +1,25 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct Thing(i32); + +impl Foo for Thing { + fn id(&self) -> i32 { + self.0 + } +} + +fn make_thing() -> impl Foo { + Thing(99) +} + +fn main() -> i32 { + let v = make_thing(); + let r = &v; + let val = r.id(); + val - 99 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait1.rs b/gcc/testsuite/rust/execute/torture/impl_trait1.rs new file mode 100644 index 0000000..33a5c8c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait1.rs @@ -0,0 +1,31 @@ +#[lang = "sized"] +trait Sized {} + +pub trait Value { + fn get(&self) -> i32; +} + +struct Foo(i32); +struct Bar(i32); + +impl Value for Foo { + fn get(&self) -> i32 { + self.0 + } +} +impl Value for Bar { + fn get(&self) -> i32 { + self.0 + } +} + +pub fn foo(a: impl Value, b: impl Value) -> i32 { + a.get() + b.get() +} + +fn main() -> i32 { + let a = Foo(1); + let b = Bar(2); + + foo(a, b) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait2.rs b/gcc/testsuite/rust/execute/torture/impl_trait2.rs new file mode 100644 index 0000000..29f393d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait2.rs @@ -0,0 +1,31 @@ +#[lang = "sized"] +trait Sized {} + +pub trait Value { + fn get(&self) -> i32; +} + +struct Foo(i32); +struct Bar(i32); + +impl Value for Foo { + fn get(&self) -> i32 { + self.0 + } +} +impl Value for Bar { + fn get(&self) -> i32 { + self.0 + } +} + +pub fn foo(a: &impl Value, b: &impl Value) -> i32 { + a.get() + b.get() +} + +fn main() -> i32 { + let a = Foo(1); + let b = Bar(2); + + foo(&a, &b) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait3.rs b/gcc/testsuite/rust/execute/torture/impl_trait3.rs new file mode 100644 index 0000000..c1cec07 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait3.rs @@ -0,0 +1,45 @@ +/* { dg-output "Hello from Message\r*\n" } */ +#[lang = "sized"] +pub trait Sized {} + +extern "C" { + fn printf(s: *const i8, ...); +} + +trait Speak { + fn speak(&self) -> &'static str; +} + +trait Printer { + fn print(&self, input: impl Speak); +} + +struct Console; + +impl Printer for Console { + fn print(&self, input: impl Speak) { + unsafe { + let a = input.speak(); + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + } +} + +struct Message(&'static str); + +impl Speak for Message { + fn speak(&self) -> &'static str { + self.0 + } +} + +fn main() -> i32 { + let c = Console; + let msg = Message("Hello from Message\n"); + c.print(msg); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait4.rs b/gcc/testsuite/rust/execute/torture/impl_trait4.rs new file mode 100644 index 0000000..67d0095 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/impl_trait4.rs @@ -0,0 +1,31 @@ +#[lang = "sized"] +trait Sized {} + +trait Foo { + fn id(&self) -> i32; +} + +struct A(i32); +struct B(i32); + +impl Foo for A { + fn id(&self) -> i32 { + self.0 + } +} + +impl Foo for B { + fn id(&self) -> i32 { + self.0 + } +} + +fn takes_tuple(pair: (impl Foo, impl Foo)) -> i32 { + pair.0.id() + pair.1.id() +} + +fn main() -> i32 { + let a = A(1); + let b = B(2); + takes_tuple((a, b)) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1481.rs b/gcc/testsuite/rust/execute/torture/issue-1481.rs new file mode 100644 index 0000000..2ff78d9 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1481.rs @@ -0,0 +1,35 @@ +/* { dg-output "called Foo::print\\(\\)\r*" } */ +/* { dg-options "-w" } */ + +#[lang = "sized"] +trait Sized {} + +trait Printable { + fn print(&self); +} + +struct Foo; + +impl Printable for Foo { + fn print(&self) { + // Simulate output + unsafe { + puts("called Foo::print()\0" as *const _ as *const i8); + } + } +} + +fn get_printable() -> impl Printable { + Foo +} + +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let p = get_printable(); + p.print(); + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-1482.rs b/gcc/testsuite/rust/execute/torture/issue-1482.rs new file mode 100644 index 0000000..ed8dc81 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1482.rs @@ -0,0 +1,23 @@ +#[lang = "sized"] +trait Sized {} + +#[lang = "fn_once"] +pub trait FnOnce<Args> { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +fn takes_fn(a: i32, f: impl FnOnce(i32) -> i32) -> i32 { + f(a) +} + +pub fn main() -> i32 { + let capture = 2; + let a = |i: i32| { + let b = i + capture; + b + }; + takes_fn(1, a) - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-2005.rs b/gcc/testsuite/rust/execute/torture/issue-2005.rs new file mode 100644 index 0000000..87edb95 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-2005.rs @@ -0,0 +1,465 @@ +// { dg-additional-options "-w" } +/* { dg-output "WORKS\r?\n" } */ +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// -------------- + +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Eq for isize {} + +impl Ord for isize { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +// ---------------------------------- + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +impl Eq for i32 {} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +enum Foo { + A, + B(i32), +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo::A; + let b = Foo::B(15); + + if (a != b) { + print("WORKS"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/issue-3836.rs b/gcc/testsuite/rust/execute/torture/issue-3836.rs new file mode 100644 index 0000000..61ad424 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-3836.rs @@ -0,0 +1,454 @@ +// { dg-options "-w" } +// { dg-output "less\r*\n" } + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +// ------------ + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Bar { + a: i32, + b: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Bar { a: 1, b: 2 }; + let y = Bar { a: 1, b: 3 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Less) => print("less"), + Option::Some(Ordering::Greater) => print("greater"), + Option::Some(Ordering::Equal) => print("equal"), + _ => print("none"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/iter1.rs b/gcc/testsuite/rust/execute/torture/iter1.rs index c3b6c7b..233eb60 100644 --- a/gcc/testsuite/rust/execute/torture/iter1.rs +++ b/gcc/testsuite/rust/execute/torture/iter1.rs @@ -99,30 +99,30 @@ mod ptr { #[lang = "const_ptr"] impl<T> *const T { pub unsafe fn offset(self, count: isize) -> *const T { - intrinsics::offset(self, count) + crate::intrinsics::offset(self, count) } } #[lang = "mut_ptr"] impl<T> *mut T { pub unsafe fn offset(self, count: isize) -> *mut T { - intrinsics::offset(self, count) as *mut T + crate::intrinsics::offset(self, count) as *mut T } } pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; - let len = mem::size_of::<T>() * count; + let len = crate::mem::size_of::<T>() * count; swap_nonoverlapping_bytes(x, y, len) } pub unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. - if mem::size_of::<T>() < 32 { + if crate::mem::size_of::<T>() < 32 { let z = read(x); - intrinsics::copy_nonoverlapping(y, x, 1); + crate::intrinsics::copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); @@ -130,12 +130,12 @@ mod ptr { } pub unsafe fn write<T>(dst: *mut T, src: T) { - intrinsics::move_val_init(&mut *dst, src) + crate::intrinsics::move_val_init(&mut *dst, src) } pub unsafe fn read<T>(src: *const T) -> T { - let mut tmp: T = mem::uninitialized(); - intrinsics::copy_nonoverlapping(src, &mut tmp, 1); + let mut tmp: T = crate::mem::uninitialized(); + crate::intrinsics::copy_nonoverlapping(src, &mut tmp, 1); tmp } @@ -143,7 +143,7 @@ mod ptr { struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); - let block_size = mem::size_of::<Block>(); + let block_size = crate::mem::size_of::<Block>(); // Loop through x & y, copying them `Block` at a time // The optimizer should unroll the loop fully for most types @@ -152,31 +152,31 @@ mod ptr { while i + block_size <= len { // Create some uninitialized memory as scratch space // Declaring `t` here avoids aligning the stack when this loop is unused - let mut t: Block = mem::uninitialized(); + let mut t: Block = crate::mem::uninitialized(); let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); // Swap a block of bytes of x & y, using t as a temporary buffer // This should be optimized into efficient SIMD operations where available - intrinsics::copy_nonoverlapping(x, t, block_size); - intrinsics::copy_nonoverlapping(y, x, block_size); - intrinsics::copy_nonoverlapping(t, y, block_size); + crate::intrinsics::copy_nonoverlapping(x, t, block_size); + crate::intrinsics::copy_nonoverlapping(y, x, block_size); + crate::intrinsics::copy_nonoverlapping(t, y, block_size); i += block_size; } if i < len { // Swap any remaining bytes - let mut t: UnalignedBlock = mem::uninitialized(); + let mut t: UnalignedBlock = crate::mem::uninitialized(); let rem = len - i; let t = &mut t as *mut _ as *mut u8; let x = x.offset(i as isize); let y = y.offset(i as isize); - intrinsics::copy_nonoverlapping(x, t, rem); - intrinsics::copy_nonoverlapping(y, x, rem); - intrinsics::copy_nonoverlapping(t, y, rem); + crate::intrinsics::copy_nonoverlapping(x, t, rem); + crate::intrinsics::copy_nonoverlapping(y, x, rem); + crate::intrinsics::copy_nonoverlapping(t, y, rem); } } } @@ -191,7 +191,7 @@ mod mem { pub fn swap<T>(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping_one(x, y); + crate::ptr::swap_nonoverlapping_one(x, y); } } @@ -201,7 +201,7 @@ mod mem { } pub unsafe fn uninitialized<T>() -> T { - intrinsics::uninit() + crate::intrinsics::uninit() } } diff --git a/gcc/testsuite/rust/execute/torture/match-identifierpattern.rs b/gcc/testsuite/rust/execute/torture/match-identifierpattern.rs new file mode 100644 index 0000000..b102ad1 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-identifierpattern.rs @@ -0,0 +1,10 @@ +fn main() -> i32 { + let mut x = 2; + + match x { + a @ 2 => { x = a + 1 }, + _ => {} + } + + x - 3 +} diff --git a/gcc/testsuite/rust/execute/torture/match-restpattern-tuple.rs b/gcc/testsuite/rust/execute/torture/match-restpattern-tuple.rs new file mode 100644 index 0000000..2c1418c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-restpattern-tuple.rs @@ -0,0 +1,27 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let x = (1, 2, 3, 4); + let mut ret = 1; + + match x { + (1, .., 2, 4) => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + (2, ..) => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + (b, .., 4) => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +}
\ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-array-1.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-1.rs new file mode 100644 index 0000000..95c55d8 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-array-1.rs @@ -0,0 +1,23 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let a = [0, 1]; + let mut ret = 1; + + match a { + [0, 0] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + [0, b] => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs new file mode 100644 index 0000000..3ed0b644 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-slicepattern-slice-1.rs @@ -0,0 +1,24 @@ +// { dg-output "correct\r*" } +extern "C" { + fn puts(s: *const i8); +} + +fn main() -> i32 { + let arr = [0, 1]; + let a: &[i32] = &arr; + let mut ret = 1; + + match a { + [0, 0] => { + /* should not take this path */ + unsafe { puts("wrong\0" as *const str as *const i8) } + }, + [0, b] => { + ret -= b; + unsafe { puts("correct\0" as *const str as *const i8) } + }, + _ => {} + } + + ret +} diff --git a/gcc/testsuite/rust/execute/torture/match-tuplestructpattern.rs b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern.rs new file mode 100644 index 0000000..323109c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/match-tuplestructpattern.rs @@ -0,0 +1,12 @@ +fn main() -> i32 { + struct A (i32, i32); + let a = A (0, 1); + let mut ret = 1; + + match a { + A (0, b) => { ret -= b }, + _ => {} + } + + ret +} diff --git a/gcc/testsuite/rust/execute/torture/min_specialization2.rs b/gcc/testsuite/rust/execute/torture/min_specialization2.rs index d3239ee..74faee4 100644 --- a/gcc/testsuite/rust/execute/torture/min_specialization2.rs +++ b/gcc/testsuite/rust/execute/torture/min_specialization2.rs @@ -8,7 +8,7 @@ trait Foo { } impl<T> Foo for T { - default fn foo(&self) -> i32 { // { dg-warning "unused" } + default fn foo(&self) -> i32 { 15 } } diff --git a/gcc/testsuite/rust/execute/torture/name_resolution.rs b/gcc/testsuite/rust/execute/torture/name_resolution.rs index 7492183..a2eaf48 100644 --- a/gcc/testsuite/rust/execute/torture/name_resolution.rs +++ b/gcc/testsuite/rust/execute/torture/name_resolution.rs @@ -1,4 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } // { dg-output "Value is 10\r*\n" } const BAZ: i32 = 10; diff --git a/gcc/testsuite/rust/execute/torture/offset_of1.rs b/gcc/testsuite/rust/execute/torture/offset_of1.rs new file mode 100644 index 0000000..7d39483 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/offset_of1.rs @@ -0,0 +1,16 @@ +// { dg-do run { target x86_64*-*-* } } +// { dg-additional-options "-frust-assume-builtin-offset-of" } + +pub struct Foo { + pub a: i32, + pub b: i32, +} + +fn main() -> i32 { + let a = offset_of!(Foo, a); // valid + let b = offset_of!(Foo, b); // valid + + let res = a + b - 4; + + res as i32 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-1.rs b/gcc/testsuite/rust/execute/torture/partial-eq-1.rs new file mode 100644 index 0000000..db123a1 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-1.rs @@ -0,0 +1,103 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +mod core { + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[lang = "sized"] + pub trait Sized {} + } + + pub mod cmp { + use super::marker::Sized; + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + pub trait Eq: PartialEq<Self> { + fn assert_receiver_is_total_eq(&self) {} + } + } +} + +use core::cmp::{Eq, PartialEq}; + +// PartialEq for i32 and u32 so we can compare across types +impl PartialEq<u32> for i32 { + fn eq(&self, other: &u32) -> bool { + *self >= 0 && (*self as u32) == *other + } +} +impl PartialEq<i32> for u32 { + fn eq(&self, other: &i32) -> bool { + *other >= 0 && *self == *other as u32 + } +} + +// Our generic struct +struct Foo<T> { + value: T, +} + +// Manual impl of PartialEq for different generic params +impl<T, U> PartialEq<Foo<U>> for Foo<T> +where + T: PartialEq<U>, +{ + fn eq(&self, other: &Foo<U>) -> bool { + self.value.eq(&other.value) + } +} + +impl<T: PartialEq> Eq for Foo<T> {} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { value: 42i32 }; + let b = Foo { value: 42u32 }; + let c = Foo { value: 7u32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-2.rs b/gcc/testsuite/rust/execute/torture/partial-eq-2.rs new file mode 100644 index 0000000..debed8c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-2.rs @@ -0,0 +1,60 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "eq"] +pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +struct Foo<T> { + value: T, +} + +impl<T: PartialEq> PartialEq for Foo<T> { + fn eq(&self, other: &Self) -> bool { + self.value.eq(&other.value) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { value: 42i32 }; + let b = Foo { value: 42i32 }; + let c = Foo { value: 99i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-3.rs b/gcc/testsuite/rust/execute/torture/partial-eq-3.rs new file mode 100644 index 0000000..849910a --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-3.rs @@ -0,0 +1,457 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +#[derive(PartialEq)] +struct Foo { + a: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-eq-4.rs b/gcc/testsuite/rust/execute/torture/partial-eq-4.rs new file mode 100644 index 0000000..b6997d8 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-eq-4.rs @@ -0,0 +1,457 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +#[derive(PartialEq, Eq)] +struct Foo { + a: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-1.rs b/gcc/testsuite/rust/execute/torture/partial-ord-1.rs new file mode 100644 index 0000000..a3558e7 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-1.rs @@ -0,0 +1,101 @@ +/* { dg-output "x == y\r*\nx > z\r*\n" }*/ +#[lang = "sized"] +pub trait Sized {} + +pub enum Option<T> { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), +} + +use Option::{None, Some}; + +#[lang = "eq"] +pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +#[lang = "partial_ord"] +pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; +} + +// Implement for i32 +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// Implement PartialOrd for i32 +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self < *other { + Some(Ordering::Less) + } else if *self > *other { + Some(Ordering::Greater) + } else { + Some(Ordering::Equal) + } + } +} + +// Struct with manual PartialEq +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.a.eq(&other.a) + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + match x.partial_cmp(&y) { + Some(Ordering::Equal) => print("x == y"), + Some(Ordering::Less) => print("x < y"), + Some(Ordering::Greater) => print("x > y"), + None => print("x ? y"), + } + + match x.partial_cmp(&z) { + Some(Ordering::Equal) => print("x == z"), + Some(Ordering::Less) => print("x < z"), + Some(Ordering::Greater) => print("x > z"), + None => print("x ? z"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-2.rs b/gcc/testsuite/rust/execute/torture/partial-ord-2.rs new file mode 100644 index 0000000..d3b713f --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-2.rs @@ -0,0 +1,469 @@ +/* { dg-output "x == y\r*\nx > z\r*\n" }*/ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + self.a == other.a + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + match x.partial_cmp(&y) { + Option::Some(Ordering::Equal) => print("x == y"), + Option::Some(Ordering::Less) => print("x < y"), + Option::Some(Ordering::Greater) => print("x > y"), + Option::None => print("x ? y"), + } + + match x.partial_cmp(&z) { + Option::Some(Ordering::Equal) => print("x == z"), + Option::Some(Ordering::Less) => print("x < z"), + Option::Some(Ordering::Greater) => print("x > z"), + Option::None => print("x ? z"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-3.rs b/gcc/testsuite/rust/execute/torture/partial-ord-3.rs new file mode 100644 index 0000000..7aec07c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-3.rs @@ -0,0 +1,489 @@ +/* { dg-output "x == y\r*\nx > z\r*\nx < z\r*\nx >= y\r*\nx <= y\r*\n" } */ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.a == other.a + } +} +impl Eq for Foo {} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.a.partial_cmp(&other.a) + } +} + +impl Ord for Foo { + fn cmp(&self, other: &Self) -> Ordering { + self.a.cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let x = Foo { a: 42 }; + let y = Foo { a: 42 }; + let z = Foo { a: 7 }; + + // test direct equality + if x == y { + print("x == y"); + } + + // test PartialOrd via match + match x.partial_cmp(&z) { + Option::Some(Ordering::Greater) => print("x > z"), + _ => print("x ? z"), + } + + // test `<` directly + if z < x { + print("x < z"); + } + + // test `>=` + if x >= y { + print("x >= y"); + } + + // test `<=` + if x <= y { + print("x <= y"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-4.rs b/gcc/testsuite/rust/execute/torture/partial-ord-4.rs new file mode 100644 index 0000000..fd52f32 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-4.rs @@ -0,0 +1,115 @@ +/* { dg-output "a == b\r*\na != c\r*\n" }*/ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + pub enum Option<T> { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), + } + } + + mod marker { + #[lang = "sized"] + pub trait Sized {} + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + pub enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, + } + + #[lang = "eq"] + pub trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[lang = "partial_ord"] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + } + } +} + +use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } +} + +struct Foo { + a: i32, +} + +impl PartialEq for Foo { + fn eq(&self, other: &'_ Self) -> bool { + self.a == other.a + } +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + ::core::cmp::PartialOrd::partial_cmp(&self.a, &other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42i32 }; + let b = Foo { a: 42i32 }; + let c = Foo { a: 7i32 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a == c { + print("a == c"); + } else { + print("a != c"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-5.rs b/gcc/testsuite/rust/execute/torture/partial-ord-5.rs new file mode 100644 index 0000000..721d2aa --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-5.rs @@ -0,0 +1,487 @@ +/* { dg-output "a == b\r*\na != c\r*\na >= c\r*\na <= b\r*\na > c\r*\nc < b\r*\n" } */ +/* { dg-options "-w" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} +impl Eq for i32 {} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +#[derive(PartialEq, Eq, Ord)] +struct Foo { + a: i32, +} + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &'_ Foo) -> Option<::core::cmp::Ordering> { + self.a.partial_cmp(&other.a) + } +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + let a = Foo { a: 42 }; + let b = Foo { a: 42 }; + let c = Foo { a: 7 }; + + if a == b { + print("a == b"); + } else { + print("a != b"); + } + + if a != c { + print("a != c"); + } else { + print("a == c"); + } + + if a < c { + print("a < c"); + } else { + print("a >= c"); + } + + if a <= b { + print("a <= b"); + } else { + print("a > b"); + } + + if a > c { + print("a > c"); + } else { + print("a <= c"); + } + + if c >= b { + print("c >= b"); + } else { + print("c < b"); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/partial-ord-6.rs b/gcc/testsuite/rust/execute/torture/partial-ord-6.rs new file mode 100644 index 0000000..5d64f8c --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/partial-ord-6.rs @@ -0,0 +1,518 @@ +// { dg-additional-options "-w" } +/* { dg-output "Foo A < B\r?\nFoo B < C\r?\nFoo C == C\r?\nBar x < y\r?\nBarFull s1 < s2\r?\n" } */ + +#![feature(intrinsics)] + +mod core { + mod option { + // #[rustc_diagnostic_item = "option_type"] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Option<T> { + /// No value + #[lang = "None"] + #[stable(feature = "rust1", since = "1.0.0")] + None, + /// Some value `T` + #[lang = "Some"] + #[stable(feature = "rust1", since = "1.0.0")] + Some(#[stable(feature = "rust1", since = "1.0.0")] T), + } + } + + mod marker { + #[lang = "phantom_data"] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct PhantomData<T: ?Sized>; + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(PartialEq)]`")] + #[lang = "structural_peq"] + pub trait StructuralPartialEq { + // Empty. + } + + #[unstable(feature = "structural_match", issue = "31434")] + // #[rustc_on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")] + #[lang = "structural_teq"] + pub trait StructuralEq { + // Empty. + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[lang = "sized"] + // #[rustc_on_unimplemented( + // message = "the size for values of type `{Self}` cannot be known at compilation time", + // label = "doesn't have a size known at compile-time" + // )] + // #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable + // #[rustc_specialization_trait] + pub trait Sized { + // Empty. + } + } + + mod cmp { + use super::marker::Sized; + use super::option::Option; + + // #[derive(Clone, Copy, PartialEq, Debug, Hash)] + #[stable(feature = "rust1", since = "1.0.0")] + pub enum Ordering { + /// An ordering where a compared value is less than another. + #[stable(feature = "rust1", since = "1.0.0")] + Less = -1, + /// An ordering where a compared value is equal to another. + #[stable(feature = "rust1", since = "1.0.0")] + Equal = 0, + /// An ordering where a compared value is greater than another. + #[stable(feature = "rust1", since = "1.0.0")] + Greater = 1, + } + + #[lang = "eq"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = "==")] + #[doc(alias = "!=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} == {Rhs}`" + // )] + pub trait PartialEq<Rhs: ?Sized = Self> { + /// This method tests for `self` and `other` values to be equal, and is used + /// by `==`. + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn eq(&self, other: &Rhs) -> bool; + + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } + } + + #[doc(alias = "==")] + #[doc(alias = "!=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Eq: PartialEq<Self> { + // this method is used solely by #[deriving] to assert + // that every component of a type implements #[deriving] + // itself, the current deriving infrastructure means doing this + // assertion without using a method on this trait is nearly + // impossible. + // + // This should never be implemented by hand. + #[doc(hidden)] + #[stable(feature = "rust1", since = "1.0.0")] + fn assert_receiver_is_total_eq(&self) {} + } + + #[lang = "partial_ord"] + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(alias = ">")] + #[doc(alias = "<")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + // #[rustc_on_unimplemented( + // message = "can't compare `{Self}` with `{Rhs}`", + // label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`" + // )] + pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { + /// This method returns an ordering between `self` and `other` values if one exists. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// let result = 1.0.partial_cmp(&2.0); + /// assert_eq!(result, Some(Ordering::Less)); + /// + /// let result = 1.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Equal)); + /// + /// let result = 2.0.partial_cmp(&1.0); + /// assert_eq!(result, Some(Ordering::Greater)); + /// ``` + /// + /// When comparison is impossible: + /// + /// ``` + /// let result = f64::NAN.partial_cmp(&1.0); + /// assert_eq!(result, None); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>; + + /// This method tests less than (for `self` and `other`) and is used by the `<` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 < 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 < 1.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn lt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less) => true, + _ => false, + } + } + + /// This method tests less than or equal to (for `self` and `other`) and is used by the `<=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 <= 2.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 <= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn le(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Less | Ordering::Equal) => true, + _ => false, + } + } + + /// This method tests greater than (for `self` and `other`) and is used by the `>` operator. + /// + /// # Examples + /// + /// ``` + /// let result = 1.0 > 2.0; + /// assert_eq!(result, false); + /// + /// let result = 2.0 > 2.0; + /// assert_eq!(result, false); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn gt(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater) => true, + _ => false, + } + } + + /// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=` + /// operator. + /// + /// # Examples + /// + /// ``` + /// let result = 2.0 >= 1.0; + /// assert_eq!(result, true); + /// + /// let result = 2.0 >= 2.0; + /// assert_eq!(result, true); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn ge(&self, other: &Rhs) -> bool { + match self.partial_cmp(other) { + Option::Some(Ordering::Greater | Ordering::Equal) => true, + _ => false, + } + } + } + + #[doc(alias = "<")] + #[doc(alias = ">")] + #[doc(alias = "<=")] + #[doc(alias = ">=")] + #[stable(feature = "rust1", since = "1.0.0")] + pub trait Ord: Eq + PartialOrd<Self> { + /// This method returns an [`Ordering`] between `self` and `other`. + /// + /// By convention, `self.cmp(&other)` returns the ordering matching the expression + /// `self <operator> other` if true. + /// + /// # Examples + /// + /// ``` + /// use std::cmp::Ordering; + /// + /// assert_eq!(5.cmp(&10), Ordering::Less); + /// assert_eq!(10.cmp(&5), Ordering::Greater); + /// assert_eq!(5.cmp(&5), Ordering::Equal); + /// ``` + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn max(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[stable(feature = "ord_max_min", since = "1.21.0")] + #[must_use] + fn min(self, other: Self) -> Self + where + Self: Sized, + { + self + } + + /// Restrict a value to a certain interval. + /// + /// Returns `max` if `self` is greater than `max`, and `min` if `self` is + /// less than `min`. Otherwise this returns `self`. + /// + /// # Panics + /// + /// Panics if `min > max`. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + #[must_use] + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where + Self: Sized, + { + if self < min { + min + } else if self > max { + max + } else { + self + } + } + } + } + + pub mod intrinsics { + #[lang = "discriminant_kind"] + pub trait DiscriminantKind { + #[lang = "discriminant_type"] + type Discriminant; + } + + extern "rust-intrinsic" { + pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; + } + } +} + +use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; +use core::marker::Sized; +use core::option::Option; + +// for comparing discriminant_value +impl PartialEq for isize { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +// for comparing discriminant_value +impl PartialOrd for isize { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &Self) -> bool { + *self == *other + } +} + +impl PartialOrd for i32 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + if *self > *other { + Option::Some(Ordering::Greater) + } else if *self < *other { + Option::Some(Ordering::Less) + } else { + Option::Some(Ordering::Equal) + } + } + + fn lt(&self, other: &Self) -> bool { + *self < *other + } + fn le(&self, other: &Self) -> bool { + *self <= *other + } + fn ge(&self, other: &Self) -> bool { + *self >= *other + } + fn gt(&self, other: &Self) -> bool { + *self > *other + } +} + +impl Ord for i32 { + fn cmp(&self, other: &Self) -> Ordering { + if *self > *other { + Ordering::Greater + } else if *self < *other { + Ordering::Less + } else { + Ordering::Equal + } + } +} + +impl Eq for i32 {} + +#[derive(PartialEq, PartialOrd)] +enum Foo { + A, + B(i32, i32, i32), + C { inner: i32, outer: i32 }, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Bar { + a: i32, +} + +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct BarFull { + a: i32, + b: i32, + c: i32, + d: i32, +} + +extern "C" { + fn puts(s: *const i8); +} + +fn print(s: &str) { + unsafe { + puts(s as *const str as *const i8); + } +} + +fn main() -> i32 { + // Enum comparison + let a = Foo::A; + let b = Foo::B(15, 14, 13); + let c = Foo::C { + inner: 10, + outer: 20, + }; + + match a.partial_cmp(&b) { + Option::Some(Ordering::Less) => print("Foo A < B"), + Option::Some(Ordering::Greater) => print("Foo A > B"), + Option::Some(Ordering::Equal) => print("Foo A == B"), + _ => print("Foo A ? B"), + } + + match b.partial_cmp(&c) { + Option::Some(Ordering::Less) => print("Foo B < C"), + Option::Some(Ordering::Greater) => print("Foo B > C"), + Option::Some(Ordering::Equal) => print("Foo B == C"), + _ => print("Foo B ? C"), + } + + match c.partial_cmp(&c) { + Option::Some(Ordering::Less) => print("Foo C < C ???"), + Option::Some(Ordering::Greater) => print("Foo C > C ???"), + Option::Some(Ordering::Equal) => print("Foo C == C"), + _ => print("Foo C ? C"), + } + + // Struct comparison: Bar + let x = Bar { a: 10 }; + let y = Bar { a: 20 }; + + if x < y { + print("Bar x < y"); + } else if x > y { + print("Bar x > y"); + } else { + print("Bar x == y"); + } + + // Struct comparison: BarFull + let s1 = BarFull { + a: 1, + b: 2, + c: 3, + d: 4, + }; + let s2 = BarFull { + a: 1, + b: 2, + c: 3, + d: 5, + }; + + match s1.cmp(&s2) { + Ordering::Less => print("BarFull s1 < s2"), + Ordering::Greater => print("BarFull s1 > s2"), + Ordering::Equal => print("BarFull s1 == s2"), + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/sip-hasher.rs b/gcc/testsuite/rust/execute/torture/sip-hasher.rs new file mode 100644 index 0000000..60826a3 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/sip-hasher.rs @@ -0,0 +1,438 @@ +// { dg-skip-if "" { *-*-* } { "-m32" } { "" } } +// { dg-options "-w" } +// { dg-output "Hash: 0x63d53fd2170bbb8c\r*\n" } +#![feature(intrinsics)] +#![feature(rustc_attrs)] + +#[lang = "sized"] +trait Sized {} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn wrapping_add<T>(a: T, b: T) -> T; + pub fn rotate_left<T>(a: T, b: T) -> T; + pub fn offset<T>(ptr: *const T, count: isize) -> *const T; + } +} + +#[lang = "add"] +trait Add<Rhs = Self> { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +macro_rules! add_impl { + ($($t:ty)*) => ($( + impl Add for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn add(self, other: $t) -> $t { self + other } + } + + + )*) +} + +add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +impl<T> *const T { + pub unsafe fn add(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.offset(count as isize) } + } + + pub unsafe fn offset(self, count: isize) -> *const T { + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { intrinsics::offset(self, count) } + } +} + +macro_rules! impl_uint { + ($($ty:ident = $lang:literal),*) => { + $( + #[lang = $lang] + impl $ty { + pub fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + + pub fn rotate_left(self, n: u32) -> Self { + intrinsics::rotate_left(self, n as Self) + } + + pub fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + )* + } +} + +impl_uint!( + u8 = "u8", + u16 = "u16", + u32 = "u32", + u64 = "u64", + u128 = "u128", + usize = "usize" +); + +#[repr(C)] +pub(crate) struct SliceComponents { + pub(crate) data_address: *const (), + pub(crate) metadata: usize, +} + +#[repr(C)] +pub(crate) union SliceRepr<T> { + pub(crate) const_ptr: *const [T], + pub(crate) mut_ptr: *mut [T], + pub(crate) components: SliceComponents, +} + +impl<T> [T] { + pub const fn as_ptr(&self) -> *const T { + self as *const [T] as *const T + } + + pub unsafe fn get_unchecked(&self, index: usize) -> &T { + unsafe { &*self.as_ptr().add(index) } + } + + pub fn len(&self) -> usize { + unsafe { + SliceRepr { + const_ptr: self as *const _, + } + .components + .metadata + } + } +} + +trait HasherTrait { + fn write(&mut self, msg: &[u8]); + fn finish(&self) -> u64; +} + +mod cmp { + pub fn min(a: usize, b: usize) -> usize { + if a < b { + a + } else { + b + } + } +} + +struct PhantomData<T>; + +mod mem { + extern "rust-intrinsic" { + fn transmute<T, U>(_: T) -> U; + fn size_of<T>() -> usize; + } +} + +mod ptr { + extern "rust-intrinsic" { + fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + } +} + +#[repr(C)] +struct State { + v0: u64, + v2: u64, + v1: u64, + v3: u64, +} + +struct Hasher<S: Sip> { + k0: u64, + k1: u64, + length: usize, // how many bytes we've processed + state: State, // hash State + tail: u64, // unprocessed bytes le + ntail: usize, // how many bytes in tail are valid + _marker: PhantomData<S>, +} + +macro_rules! compress { + ($state:expr) => {{ + compress!($state.v0, $state.v1, $state.v2, $state.v3) + }}; + ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ + $v0 = $v0.wrapping_add($v1); + $v1 = $v1.rotate_left(13); + $v1 ^= $v0; + $v0 = $v0.rotate_left(32); + $v2 = $v2.wrapping_add($v3); + $v3 = $v3.rotate_left(16); + $v3 ^= $v2; + $v0 = $v0.wrapping_add($v3); + $v3 = $v3.rotate_left(21); + $v3 ^= $v0; + $v2 = $v2.wrapping_add($v1); + $v1 = $v1.rotate_left(17); + $v1 ^= $v2; + $v2 = $v2.rotate_left(32); + }}; +} + +#[doc(hidden)] +trait Sip { + fn c_rounds(_: &mut State); + fn d_rounds(_: &mut State); +} + +struct Sip13Rounds; + +impl Sip for Sip13Rounds { + #[inline] + fn c_rounds(state: &mut State) { + compress!(state); + } + + #[inline] + fn d_rounds(state: &mut State) { + compress!(state); + compress!(state); + compress!(state); + } +} + +struct Sip24Rounds; + +impl Sip for Sip24Rounds { + #[inline] + fn c_rounds(state: &mut State) { + compress!(state); + compress!(state); + } + + #[inline] + fn d_rounds(state: &mut State) { + compress!(state); + compress!(state); + compress!(state); + compress!(state); + } +} + +pub struct SipHasher13 { + hasher: Hasher<Sip13Rounds>, +} + +struct SipHasher24 { + hasher: Hasher<Sip24Rounds>, +} + +pub struct SipHasher(SipHasher24); + +macro_rules! load_int_le { + ($buf:expr, $i:expr, $int_ty:ident) => {{ + let mut data = 0 as $int_ty; + ptr::copy_nonoverlapping( + $buf.as_ptr().add($i), + &mut data as *mut _ as *mut u8, + mem::size_of::<$int_ty>(), + ); + data.to_le() + }}; +} + +#[inline] +unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { + let mut i = 0; // current byte index (from LSB) in the output u64 + let mut out = 0; + if i + 3 < len { + // SAFETY: `i` cannot be greater than `len`, and the caller must guarantee + // that the index start..start+len is in bounds. + out = unsafe { load_int_le!(buf, start + i, u32) } as u64; + i += 4; + } + if i + 1 < len { + // SAFETY: same as above. + out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << ((i * 8) as u64); + i += 2 + } + if i < len { + // SAFETY: same as above. + out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << ((i * 8) as u64); + i += 1; + } + out +} + +impl SipHasher { + #[inline] + #[must_use] + pub fn new() -> SipHasher { + SipHasher::new_with_keys(0, 0) + } + + #[inline] + #[must_use] + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { + SipHasher(SipHasher24 { + hasher: Hasher::new_with_keys(key0, key1), + }) + } +} + +impl SipHasher13 { + #[inline] + pub fn new() -> SipHasher13 { + SipHasher13::new_with_keys(0, 0) + } + + #[inline] + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { + SipHasher13 { + hasher: Hasher::new_with_keys(key0, key1), + } + } +} + +impl<S: Sip> Hasher<S> { + #[inline] + fn new_with_keys(key0: u64, key1: u64) -> Hasher<S> { + let mut state = Hasher { + k0: key0, + k1: key1, + length: 0, + state: State { + v0: 0, + v1: 0, + v2: 0, + v3: 0, + }, + tail: 0, + ntail: 0, + _marker: PhantomData, + }; + state.reset(); + state + } + + #[inline] + fn reset(&mut self) { + self.length = 0; + self.state.v0 = self.k0 ^ 0x736f6d6570736575; + self.state.v1 = self.k1 ^ 0x646f72616e646f6d; + self.state.v2 = self.k0 ^ 0x6c7967656e657261; + self.state.v3 = self.k1 ^ 0x7465646279746573; + self.ntail = 0; + } +} + +impl HasherTrait for SipHasher { + #[inline] + fn write(&mut self, msg: &[u8]) { + self.0.hasher.write(msg) + } + + #[inline] + fn finish(&self) -> u64 { + self.0.hasher.finish() + } +} + +impl HasherTrait for SipHasher13 { + #[inline] + fn write(&mut self, msg: &[u8]) { + self.hasher.write(msg) + } + + #[inline] + fn finish(&self) -> u64 { + self.hasher.finish() + } +} + +impl<S: Sip> HasherTrait for Hasher<S> { + #[inline] + fn write(&mut self, msg: &[u8]) { + let length = msg.len(); + self.length += length; + + let mut needed = 0; + + if self.ntail != 0 { + needed = 8 - self.ntail; + // SAFETY: `cmp::min(length, needed)` is guaranteed to not be over `length` + self.tail |= + unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << ((8 * self.ntail) as u64); + if length < needed { + self.ntail += length; + return; + } else { + self.state.v3 ^= self.tail; + S::c_rounds(&mut self.state); + self.state.v0 ^= self.tail; + self.ntail = 0; + } + } + + // Buffered tail is now flushed, process new input. + let len = length - needed; + let left = len & 0x7; // len % 8 + + let mut i = needed; + while i < len - left { + let mi = unsafe { load_int_le!(msg, i, u64) }; + + self.state.v3 ^= mi; + S::c_rounds(&mut self.state); + self.state.v0 ^= mi; + + i += 8; + } + + self.tail = unsafe { u8to64_le(msg, i, left) }; + self.ntail = left; + } + + #[inline] + fn finish(&self) -> u64 { + let mut state = self.state; + + let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; + + state.v3 ^= b; + S::c_rounds(&mut state); + state.v0 ^= b; + + state.v2 ^= 0xff; + S::d_rounds(&mut state); + + state.v0 ^ state.v1 ^ state.v2 ^ state.v3 + } +} + +extern "C" { + fn printf(fmt: *const u8, ...) -> i32; +} + +fn main() -> i32 { + let mut hasher = SipHasher::new_with_keys(0x0706050403020100, 0x0f0e0d0c0b0a0908); + hasher.write(b"Hello"); + let result = hasher.finish(); + + unsafe { + printf("Hash: 0x%016llx\n\0" as *const str as *const u8, result); + } + + 0 +} diff --git a/gcc/testsuite/rust/execute/torture/struct-pattern-match.rs b/gcc/testsuite/rust/execute/torture/struct-pattern-match.rs new file mode 100644 index 0000000..6aec51f --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/struct-pattern-match.rs @@ -0,0 +1,13 @@ +enum Foo { + A { x: i32 }, + B { y: i32 } +} + +fn main() -> i32 { + let x = Foo::A { x: 12 }; + match x { + Foo::A { x: 10 } => 1, + Foo::B { y: 11 } => 2, + Foo::A { x: abc } => { abc - 12 } + } +} diff --git a/gcc/testsuite/rust/execute/torture/struct_pattern1.rs b/gcc/testsuite/rust/execute/torture/struct_pattern1.rs new file mode 100644 index 0000000..7a74092 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/struct_pattern1.rs @@ -0,0 +1,19 @@ +struct A { + // the two warnings are invalid but this should be fixed by our lint rework + // with this year's GSoC so ok for now + a: i32, // { dg-warning "never read" } + b: i32, // { dg-warning "never read" } +} + +fn main() -> i32 { + let a = A { a: 15, b: 14 }; + + let result = match a { + A { + a: self_a, + b: self_b, + } => self_a + self_b, + }; + + result - 29 +} diff --git a/gcc/testsuite/rust/execute/torture/trait10.rs b/gcc/testsuite/rust/execute/torture/trait10.rs index a595122..4e576eb 100644 --- a/gcc/testsuite/rust/execute/torture/trait10.rs +++ b/gcc/testsuite/rust/execute/torture/trait10.rs @@ -26,7 +26,6 @@ impl Bar for Foo { struct S; impl S { fn dynamic_dispatch(self, t: &dyn Bar) { - // { dg-warning "unused name" "" { target *-*-* } .-1 } t.baz(); } } diff --git a/gcc/testsuite/rust/execute/torture/trait11.rs b/gcc/testsuite/rust/execute/torture/trait11.rs index 093343c..cca084a 100644 --- a/gcc/testsuite/rust/execute/torture/trait11.rs +++ b/gcc/testsuite/rust/execute/torture/trait11.rs @@ -13,7 +13,6 @@ trait FnLike<A, R> { struct S; impl<'a, T> FnLike<&'a T, &'a T> for S { fn call(&self, arg: &'a T) -> &'a T { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } arg } } diff --git a/gcc/testsuite/rust/execute/torture/trait12.rs b/gcc/testsuite/rust/execute/torture/trait12.rs index 83cf107..d174a89 100644 --- a/gcc/testsuite/rust/execute/torture/trait12.rs +++ b/gcc/testsuite/rust/execute/torture/trait12.rs @@ -16,7 +16,6 @@ struct Identity; impl<'a, T> FnLike<&'a T, &'a T> for Identity { fn call(&self, arg: &'a T) -> &'a T { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } arg } } diff --git a/gcc/testsuite/rust/execute/torture/trait13.rs b/gcc/testsuite/rust/execute/torture/trait13.rs index 928a37c..0d8f894 100644 --- a/gcc/testsuite/rust/execute/torture/trait13.rs +++ b/gcc/testsuite/rust/execute/torture/trait13.rs @@ -11,7 +11,6 @@ trait Bar { fn baz(&self); fn qux(&self) { - // { dg-warning "unused name" "" { target *-*-* } .-1 } unsafe { let a = "%i\n\0"; let b = a as *const str; diff --git a/gcc/testsuite/rust/execute/torture/trait9.rs b/gcc/testsuite/rust/execute/torture/trait9.rs index a1642f6..f60554a 100644 --- a/gcc/testsuite/rust/execute/torture/trait9.rs +++ b/gcc/testsuite/rust/execute/torture/trait9.rs @@ -13,7 +13,6 @@ trait FnLike<A, R> { struct S; impl<T> FnLike<&T, &T> for S { fn call(&self, arg: &T) -> &T { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } arg } } diff --git a/gcc/testsuite/rust/execute/xfail/match-identifierpattern-enum.rs b/gcc/testsuite/rust/execute/xfail/match-identifierpattern-enum.rs new file mode 100644 index 0000000..c3a0f65 --- /dev/null +++ b/gcc/testsuite/rust/execute/xfail/match-identifierpattern-enum.rs @@ -0,0 +1,15 @@ +enum Foo { + I(i32), +} + +fn main() -> i32 { + let x = Foo::I(0); + let ret = 1; + + match x { + _ @ Foo::I(b) => { ret = b }, + _ => {}, + }; + + ret +} diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/embedded-links-check-html.py b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/embedded-links-check-html.py index ff1c2f2..845a7af 100644 --- a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/embedded-links-check-html.py +++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/embedded-links-check-html.py @@ -25,4 +25,4 @@ def test_generated_html(html_tree): assert_tag(msg[1], 'a') assert msg[1].text == 'link' assert msg[1].get('href') == 'http://www.example.com' - assert msg[1].tail == '. ' + assert msg[1].tail == '.' diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py index 63b80c9..355c84b 100644 --- a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py +++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/graphs-check-html.py @@ -24,7 +24,7 @@ def test_result_graph(html_tree): assert message.attrib['id'] == 'gcc-diag-0-message' assert message[0].tag == make_tag('strong') - assert message[0].tail == ' this is a placeholder error, with graphs ' + assert message[0].tail == ' this is a placeholder error, with graphs' graph = diag.find("./xhtml:div[@class='gcc-directed-graph']", ns) assert graph is not None diff --git a/gcc/testsuite/sarif-replay.dg/2.1.0-valid/nested-diagnostics-1.sarif b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/nested-diagnostics-1.sarif new file mode 100644 index 0000000..b924012 --- /dev/null +++ b/gcc/testsuite/sarif-replay.dg/2.1.0-valid/nested-diagnostics-1.sarif @@ -0,0 +1,164 @@ +/* Test a replay of a .sarif file generated from GCC testsuite. + + The dg directives were stripped out from the generated .sarif + to avoid confusing DejaGnu for this test. */ +/* { dg-additional-options "-fdiagnostics-add-output=sarif:file=nested-diagnostics-1.roundtrip.sarif" } */ +/* { dg-additional-options "-fdiagnostics-add-output=experimental-html:file=nested-diagnostics-1.sarif.html,javascript=no" } */ + +{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", + "version": "2.1.0", + "runs": [{"tool": {"driver": {"name": "GNU C23", + "fullName": "GNU C23 (GCC) version 16.0.0 20250723 (experimental) (x86_64-pc-linux-gnu)", + "version": "16.0.0 20250723 (experimental)", + "informationUri": "https://gcc.gnu.org/gcc-16/", + "rules": []}, + "extensions": [{"name": "diagnostic_plugin_test_nesting", + "fullName": "./diagnostic_plugin_test_nesting.so"}]}, + "invocations": [{"executionSuccessful": false, + "toolExecutionNotifications": []}], + "artifacts": [{"location": {"uri": "diagnostic-test-nesting-sarif.c"}, + "sourceLanguage": "c", + "contents": {"text": "\n\nextern void foo (void);\n\nvoid test_nesting (void)\n{\n foo ();\n}\n"}, + "roles": ["analysisTarget"]}], + "results": [{"ruleId": "error", + "level": "error", + "message": {"text": "top-level error"}, + "locations": [{"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "logicalLocations": [{"index": 0, + "fullyQualifiedName": "test_nesting"}]}], + "relatedLocations": [{"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "child 0"}, + "properties": {"nestingLevel": 1}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 0 0"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 0 1"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 0 2"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "child 1"}, + "properties": {"nestingLevel": 1}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 1 0"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 1 1"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 1 2"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "child 2"}, + "properties": {"nestingLevel": 1}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 2 0"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 2 1"}, + "properties": {"nestingLevel": 2}}, + {"physicalLocation": {"artifactLocation": {"uri": "diagnostic-test-nesting-sarif.c"}, + "region": {"startLine": 8, + "startColumn": 3, + "endColumn": 9}, + "contextRegion": {"startLine": 8, + "snippet": {"text": " foo ();\n"}}}, + "message": {"text": "grandchild 2 2"}, + "properties": {"nestingLevel": 2}}]}], + "logicalLocations": [{"name": "test_nesting", + "fullyQualifiedName": "test_nesting", + "decoratedName": "test_nesting", + "kind": "function", + "index": 0}]}]} + +/* For now, we don't have a way of enabling showing the nesting + on the default text output. However we do test the nesting + in the SARIF and HTML outputs below. */ +/* { dg-begin-multiline-output "" } +In function 'test_nesting': +diagnostic-test-nesting-sarif.c:8:3: error: top-level error + 8 | } + | ^ +diagnostic-test-nesting-sarif.c:8:3: note: child 0 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 0 0 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 0 1 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 0 2 +diagnostic-test-nesting-sarif.c:8:3: note: child 1 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 1 0 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 1 1 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 1 2 +diagnostic-test-nesting-sarif.c:8:3: note: child 2 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 2 0 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 2 1 +diagnostic-test-nesting-sarif.c:8:3: note: grandchild 2 2 + { dg-end-multiline-output "" } */ + +/* Use a Python script to verify various properties about the *generated* + .sarif file: + { dg-final { run-sarif-pytest nested-diagnostics-1.roundtrip "../gcc.dg/plugin/diagnostic-test-nesting-sarif.py" } } */ + +/* Use a Python script to verify various properties about the generated + .html file: + { dg-final { run-html-pytest nested-diagnostics-1.sarif "../gcc.dg/plugin/diagnostic-test-nesting-html.py" } } */ diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 70dbb3e..d349d83 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -1096,10 +1096,10 @@ general_init (const char *argv0, bool init_signals, unique_argv original_argv) (global_options_init.x_flag_diagnostics_show_highlight_colors); global_dc->set_internal_error_callback (internal_error_function); const unsigned lang_mask = lang_hooks.option_lang_mask (); - global_dc->set_option_manager - (std::make_unique<compiler_diagnostic_option_manager> (*global_dc, - lang_mask, - &global_options), + global_dc->set_option_id_manager + (std::make_unique<compiler_diagnostic_option_id_manager> (*global_dc, + lang_mask, + &global_options), lang_mask); global_dc->push_owned_urlifier (make_gcc_urlifier (lang_mask)); diff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc index 8d75a2f..813334b 100644 --- a/gcc/tree-nested.cc +++ b/gcc/tree-nested.cc @@ -1796,6 +1796,8 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_TARGET: + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_target_iterator_loops_ptr (stmt)); if (!is_gimple_omp_offloaded (stmt)) { save_suppress = info->suppress_expansion; @@ -2517,6 +2519,9 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_TARGET: + walk_body (convert_local_reference_stmt, convert_local_reference_op, info, + gimple_omp_target_iterator_loops_ptr (stmt)); + if (!is_gimple_omp_offloaded (stmt)) { save_suppress = info->suppress_expansion; @@ -2898,6 +2903,8 @@ convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, *handled_ops_p = false; return NULL_TREE; } + walk_body (convert_tramp_reference_stmt, convert_tramp_reference_op, + info, gimple_omp_target_iterator_loops_ptr (stmt)); /* FALLTHRU */ case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index 50d0851..c19baba 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -448,6 +448,15 @@ dump_omp_iterators (pretty_printer *pp, tree iter, int spc, dump_flags_t flags) pp_colon (pp); dump_generic_node (pp, TREE_VEC_ELT (it, 3), spc, flags, false); } + if (TREE_VEC_LENGTH (iter) > 6) + { + pp_string (pp, ", loop_label="); + dump_generic_node (pp, TREE_VEC_ELT (iter, 6), spc, flags, false); + pp_string (pp, ", elems="); + dump_generic_node (pp, TREE_VEC_ELT (iter, 7), spc, flags, false); + pp_string (pp, ", index="); + dump_generic_node (pp, TREE_VEC_ELT (iter, 8), spc, flags, false); + } pp_right_paren (pp); } @@ -1008,6 +1017,11 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_string (pp, "map("); if (OMP_CLAUSE_MAP_READONLY (clause)) pp_string (pp, "readonly,"); + if (OMP_CLAUSE_ITERATORS (clause)) + { + dump_omp_iterators (pp, OMP_CLAUSE_ITERATORS (clause), spc, flags); + pp_colon (pp); + } switch (OMP_CLAUSE_MAP_KIND (clause)) { case GOMP_MAP_ALLOC: @@ -1185,6 +1199,11 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_string (pp, "from("); if (OMP_CLAUSE_MOTION_PRESENT (clause)) pp_string (pp, "present:"); + if (OMP_CLAUSE_ITERATORS (clause)) + { + dump_omp_iterators (pp, OMP_CLAUSE_ITERATORS (clause), spc, flags); + pp_colon (pp); + } dump_generic_node (pp, OMP_CLAUSE_DECL (clause), spc, flags, false); goto print_clause_size; @@ -1193,6 +1212,11 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_string (pp, "to("); if (OMP_CLAUSE_MOTION_PRESENT (clause)) pp_string (pp, "present:"); + if (OMP_CLAUSE_ITERATORS (clause)) + { + dump_omp_iterators (pp, OMP_CLAUSE_ITERATORS (clause), spc, flags); + pp_colon (pp); + } dump_generic_node (pp, OMP_CLAUSE_DECL (clause), spc, flags, false); goto print_clause_size; diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc index 413ca49..3b3748a 100644 --- a/gcc/tree-scalar-evolution.cc +++ b/gcc/tree-scalar-evolution.cc @@ -670,6 +670,17 @@ scev_dfs::add_to_evolution_1 (tree chrec_before, tree to_add, gimple *at_stmt) to_add = chrec_convert (type, to_add, at_stmt); right = chrec_convert_rhs (type, right, at_stmt); right = chrec_fold_plus (chrec_type (right), right, to_add); + /* When we have an evolution in a non-wrapping type and + in the process of accumulating CHREC_RIGHT there was + overflow this indicates in the association that happened + in building the CHREC clearly involved UB. Avoid this. + In building a CHREC we basically turn (a + INCR1) + INCR2 + into a + (INCR1 + INCR2) which is not always valid. + Note this check only catches few invalid cases. */ + if ((INTEGRAL_TYPE_P (type) && ! TYPE_OVERFLOW_WRAPS (type)) + && TREE_CODE (right) == INTEGER_CST + && TREE_OVERFLOW (right)) + return chrec_dont_know; return build_polynomial_chrec (var, left, right); } else diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc index 879668c..2fe2655 100644 --- a/gcc/tree-ssa-loop-ivopts.cc +++ b/gcc/tree-ssa-loop-ivopts.cc @@ -132,6 +132,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-vectorizer.h" #include "dbgcnt.h" #include "cfganal.h" +#include "gimple-fold.h" /* For lang_hooks.types.type_for_mode. */ #include "langhooks.h" @@ -7252,7 +7253,24 @@ create_new_iv (struct ivopts_data *data, struct iv_cand *cand) base = unshare_expr (cand->iv->base); - create_iv (base, PLUS_EXPR, unshare_expr (cand->iv->step), + /* The step computation could invoke UB when the loop does not iterate. + Avoid inserting it on the preheader in its native form but rewrite + it to a well-defined form. This also helps masking SCEV issues + which freely re-associates the IV computations when building up + CHRECs without much regard for signed overflow invoking UB. */ + gimple_seq stmts = NULL; + tree step = force_gimple_operand (unshare_expr (cand->iv->step), &stmts, + true, NULL_TREE); + if (stmts) + { + for (auto gsi = gsi_start (stmts); !gsi_end_p (gsi); gsi_next (&gsi)) + if (gimple_needing_rewrite_undefined (gsi_stmt (gsi))) + rewrite_to_defined_unconditional (&gsi); + gsi_insert_seq_on_edge_immediate + (loop_preheader_edge (data->current_loop), stmts); + } + + create_iv (base, PLUS_EXPR, step, cand->var_before, data->current_loop, &incr_pos, after, &cand->var_before, &cand->var_after); } diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 3974c4d..00315d1 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -3549,8 +3549,95 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, /* Find the common base of ref and the lhs. lhs_ops already contains valueized operands for the lhs. */ + poly_int64 extra_off = 0; i = vr->operands.length () - 1; j = lhs_ops.length () - 1; + + /* The base should be always equal due to the above check. */ + if (! vn_reference_op_eq (&vr->operands[i], &lhs_ops[j])) + return (void *)-1; + i--, j--; + + /* The 2nd component should always exist and be a MEM_REF. */ + if (!(i >= 0 && j >= 0)) + ; + else if (vn_reference_op_eq (&vr->operands[i], &lhs_ops[j])) + i--, j--; + else if (vr->operands[i].opcode == MEM_REF + && lhs_ops[j].opcode == MEM_REF + && known_ne (lhs_ops[j].off, -1) + && known_ne (vr->operands[i].off, -1)) + { + bool found = false; + /* When we ge a mismatch at a MEM_REF that is not the sole component + try finding a match in one of the outer components and continue + stripping there. This happens when addresses of components get + forwarded into dereferences. */ + if (j > 0) + { + int temi = i - 1; + extra_off = vr->operands[i].off; + while (temi >= 0 + && known_ne (vr->operands[temi].off, -1)) + { + if (vr->operands[temi].type + && lhs_ops[j].type + && (TYPE_MAIN_VARIANT (vr->operands[temi].type) + == TYPE_MAIN_VARIANT (lhs_ops[j].type))) + { + i = temi; + /* Strip the component that was type matched to + the MEM_REF. */ + extra_off += vr->operands[i].off - lhs_ops[j].off; + i--, j--; + /* Strip further equal components. */ + found = true; + break; + } + extra_off += vr->operands[temi].off; + temi--; + } + } + if (!found && i > 0) + { + int temj = j - 1; + extra_off = -lhs_ops[j].off; + while (temj >= 0 + && known_ne (lhs_ops[temj].off, -1)) + { + if (vr->operands[i].type + && lhs_ops[temj].type + && (TYPE_MAIN_VARIANT (vr->operands[i].type) + == TYPE_MAIN_VARIANT (lhs_ops[temj].type))) + { + j = temj; + /* Strip the component that was type matched to + the MEM_REF. */ + extra_off += vr->operands[i].off - lhs_ops[j].off; + i--, j--; + /* Strip further equal components. */ + found = true; + break; + } + extra_off += -lhs_ops[temj].off; + temj--; + } + } + /* When the LHS is already at the outermost level simply + adjust for any offset difference. Further lookups + will fail when there's too gross of a type compatibility + issue. */ + if (!found && j == 0) + { + extra_off = vr->operands[i].off - lhs_ops[j].off; + i--, j--; + } + } + else + return (void *)-1; + + /* Strip further common components, attempting to consume lhs_ops + in full. */ while (j >= 0 && i >= 0 && vn_reference_op_eq (&vr->operands[i], &lhs_ops[j])) { @@ -3558,27 +3645,6 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, j--; } - /* ??? The innermost op should always be a MEM_REF and we already - checked that the assignment to the lhs kills vr. Thus for - aggregate copies using char[] types the vn_reference_op_eq - may fail when comparing types for compatibility. But we really - don't care here - further lookups with the rewritten operands - will simply fail if we messed up types too badly. */ - poly_int64 extra_off = 0; - if (j == 0 && i >= 0 - && lhs_ops[0].opcode == MEM_REF - && maybe_ne (lhs_ops[0].off, -1)) - { - if (known_eq (lhs_ops[0].off, vr->operands[i].off)) - i--, j--; - else if (vr->operands[i].opcode == MEM_REF - && maybe_ne (vr->operands[i].off, -1)) - { - extra_off = vr->operands[i].off - lhs_ops[0].off; - i--, j--; - } - } - /* i now points to the first additional op. ??? LHS may not be completely contained in VR, one or more VIEW_CONVERT_EXPRs could be in its way. We could at least diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index da700cd..dc82bf6 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -1856,21 +1856,14 @@ vect_get_data_access_cost (vec_info *vinfo, dr_vec_info *dr_info, stmt_vector_for_cost *prologue_cost_vec) { stmt_vec_info stmt_info = dr_info->stmt; - loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); - int ncopies; - - if (PURE_SLP_STMT (stmt_info)) - ncopies = 1; - else - ncopies = vect_get_num_copies (loop_vinfo, STMT_VINFO_VECTYPE (stmt_info)); if (DR_IS_READ (dr_info->dr)) - vect_get_load_cost (vinfo, stmt_info, NULL, ncopies, + vect_get_load_cost (vinfo, stmt_info, NULL, 1, alignment_support_scheme, misalignment, true, inside_cost, outside_cost, prologue_cost_vec, body_cost_vec, false); else - vect_get_store_cost (vinfo,stmt_info, NULL, ncopies, + vect_get_store_cost (vinfo,stmt_info, NULL, 1, alignment_support_scheme, misalignment, inside_cost, body_cost_vec); diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 460de57..85f3e90 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -2512,9 +2512,8 @@ start_over: if (!vect_make_slp_decision (loop_vinfo)) return opt_result::failure_at (vect_location, "no stmts to vectorize.\n"); - /* Find stmts that need to be both vectorized and SLPed. */ - if (!vect_detect_hybrid_slp (loop_vinfo)) - return opt_result::failure_at (vect_location, "needs non-SLP handling\n"); + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, "Loop contains only SLP stmts\n"); /* Determine the vectorization factor from the SLP decision. */ LOOP_VINFO_VECT_FACTOR (loop_vinfo) @@ -2923,7 +2922,7 @@ again: !gsi_end_p (si); gsi_next (&si)) { stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si)); - STMT_SLP_TYPE (stmt_info) = loop_vect; + STMT_SLP_TYPE (stmt_info) = not_vect; if (STMT_VINFO_DEF_TYPE (stmt_info) == vect_reduction_def || STMT_VINFO_DEF_TYPE (stmt_info) == vect_double_reduction_def) { @@ -2942,7 +2941,7 @@ again: if (is_gimple_debug (gsi_stmt (si))) continue; stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si)); - STMT_SLP_TYPE (stmt_info) = loop_vect; + STMT_SLP_TYPE (stmt_info) = not_vect; if (STMT_VINFO_IN_PATTERN_P (stmt_info)) { stmt_vec_info pattern_stmt_info @@ -2951,11 +2950,11 @@ again: STMT_VINFO_IN_PATTERN_P (stmt_info) = false; gimple *pattern_def_seq = STMT_VINFO_PATTERN_DEF_SEQ (stmt_info); - STMT_SLP_TYPE (pattern_stmt_info) = loop_vect; + STMT_SLP_TYPE (pattern_stmt_info) = not_vect; for (gimple_stmt_iterator pi = gsi_start (pattern_def_seq); !gsi_end_p (pi); gsi_next (&pi)) STMT_SLP_TYPE (loop_vinfo->lookup_stmt (gsi_stmt (pi))) - = loop_vect; + = not_vect; } } } diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index ca14a2d..794a073 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -1140,7 +1140,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, soft_fail_nunits_vectype = nunits_vectype; } - gcc_assert (vectype); + gcc_assert (vectype || !gimple_get_lhs (first_stmt_info->stmt)); *node_vectype = vectype; /* For every stmt in NODE find its def stmt/s. */ @@ -1187,10 +1187,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, gcall *call_stmt = dyn_cast <gcall *> (stmt); tree lhs = gimple_get_lhs (stmt); - if (lhs == NULL_TREE - && (!call_stmt - || !gimple_call_internal_p (stmt) - || !internal_store_fn_p (gimple_call_internal_fn (stmt)))) + if (lhs == NULL_TREE && !call_stmt) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -4888,9 +4885,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, /* Find SLP sequences starting from groups of grouped stores. */ FOR_EACH_VEC_ELT (vinfo->grouped_stores, i, first_element) - vect_analyze_slp_instance (vinfo, bst_map, first_element, - slp_inst_kind_store, max_tree_size, &limit, - force_single_lane); + if (! vect_analyze_slp_instance (vinfo, bst_map, first_element, + slp_inst_kind_store, max_tree_size, &limit, + force_single_lane) + && loop_vinfo) + return opt_result::failure_at (vect_location, "SLP build failed.\n"); /* For loops also start SLP discovery from non-grouped stores. */ if (loop_vinfo) @@ -4908,10 +4907,29 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, vec<tree> remain = vNULL; stmts.create (1); stmts.quick_push (stmt_info); - vect_build_slp_instance (vinfo, slp_inst_kind_store, - stmts, roots, remain, max_tree_size, - &limit, bst_map, NULL, force_single_lane); + if (! vect_build_slp_instance (vinfo, slp_inst_kind_store, + stmts, roots, remain, max_tree_size, + &limit, bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } + + stmt_vec_info stmt_info; + FOR_EACH_VEC_ELT (LOOP_VINFO_ALTERNATE_DEFS (loop_vinfo), i, stmt_info) + { + vec<stmt_vec_info> stmts; + vec<stmt_vec_info> roots = vNULL; + vec<tree> remain = vNULL; + stmts.create (1); + stmts.quick_push (stmt_info); + if (! vect_build_slp_instance (vinfo, slp_inst_kind_store, + stmts, roots, remain, max_tree_size, + &limit, bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); + } } if (bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo)) @@ -5002,12 +5020,14 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, vec<tree> remain = vNULL; stmts.create (1); stmts.quick_push (next_info); - vect_build_slp_instance (vinfo, - slp_inst_kind_reduc_group, - stmts, roots, remain, - max_tree_size, &limit, - bst_map, NULL, - force_single_lane); + if (! vect_build_slp_instance (vinfo, + slp_inst_kind_reduc_group, + stmts, roots, remain, + max_tree_size, &limit, + bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } } } @@ -5032,11 +5052,14 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, vec<tree> remain = vNULL; stmts.create (1); stmts.quick_push (vect_stmt_to_vectorize (stmt_info)); - vect_build_slp_instance (vinfo, - slp_inst_kind_reduc_group, - stmts, roots, remain, - max_tree_size, &limit, - bst_map, NULL, force_single_lane); + if (! vect_build_slp_instance (vinfo, + slp_inst_kind_reduc_group, + stmts, roots, remain, + max_tree_size, &limit, + bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } } saved_stmts.release (); @@ -5065,11 +5088,14 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, vec<tree> remain = vNULL; stmts.create (1); stmts.quick_push (vect_stmt_to_vectorize (stmt_info)); - vect_build_slp_instance (vinfo, - slp_inst_kind_reduc_group, - stmts, roots, remain, - max_tree_size, &limit, - bst_map, NULL, force_single_lane); + if (! vect_build_slp_instance (vinfo, + slp_inst_kind_reduc_group, + stmts, roots, remain, + max_tree_size, &limit, + bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } } @@ -5092,7 +5118,8 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, || !integer_zerop (args1)) { roots.release (); - continue; + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } /* An argument without a loop def will be codegened from vectorizing the @@ -5110,7 +5137,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, stmts, roots, remain, max_tree_size, &limit, bst_map, NULL, force_single_lane)) - roots.release (); + { + roots.release (); + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); + } } /* Find and create slp instances for inductions that have been forced @@ -5128,10 +5159,13 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, { stmts.create (1); stmts.quick_push (vect_stmt_to_vectorize (lc_info)); - vect_build_slp_instance (vinfo, slp_inst_kind_reduc_group, - stmts, roots, remain, - max_tree_size, &limit, - bst_map, NULL, force_single_lane); + if (! vect_build_slp_instance (vinfo, slp_inst_kind_reduc_group, + stmts, roots, remain, + max_tree_size, &limit, + bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } /* When the latch def is from a different cycle this can only be a induction. Build a simple instance for this. @@ -5144,10 +5178,13 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size, { stmts.create (1); stmts.quick_push (stmt_info); - vect_build_slp_instance (vinfo, slp_inst_kind_reduc_group, - stmts, roots, remain, - max_tree_size, &limit, - bst_map, NULL, force_single_lane); + if (! vect_build_slp_instance (vinfo, slp_inst_kind_reduc_group, + stmts, roots, remain, + max_tree_size, &limit, + bst_map, NULL, + force_single_lane)) + return opt_result::failure_at (vect_location, + "SLP build failed.\n"); } } } @@ -7610,7 +7647,8 @@ vect_make_slp_decision (loop_vec_info loop_vinfo) /* If all instances ended up with vector(1) T roots make sure to not vectorize. RVV for example relies on loop vectorization when some instances are essentially kept scalar. See PR121048. */ - if (known_gt (TYPE_VECTOR_SUBPARTS (SLP_TREE_VECTYPE (root)), 1U)) + if (SLP_TREE_VECTYPE (root) + && known_gt (TYPE_VECTOR_SUBPARTS (SLP_TREE_VECTYPE (root)), 1U)) decided_to_slp++; } @@ -7628,232 +7666,6 @@ vect_make_slp_decision (loop_vec_info loop_vinfo) return (decided_to_slp > 0); } -/* Private data for vect_detect_hybrid_slp. */ -struct vdhs_data -{ - loop_vec_info loop_vinfo; - vec<stmt_vec_info> *worklist; -}; - -/* Walker for walk_gimple_op. */ - -static tree -vect_detect_hybrid_slp (tree *tp, int *, void *data) -{ - walk_stmt_info *wi = (walk_stmt_info *)data; - vdhs_data *dat = (vdhs_data *)wi->info; - - if (wi->is_lhs) - return NULL_TREE; - - stmt_vec_info def_stmt_info = dat->loop_vinfo->lookup_def (*tp); - if (!def_stmt_info) - return NULL_TREE; - def_stmt_info = vect_stmt_to_vectorize (def_stmt_info); - if (PURE_SLP_STMT (def_stmt_info)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, "marking hybrid: %G", - def_stmt_info->stmt); - STMT_SLP_TYPE (def_stmt_info) = hybrid; - dat->worklist->safe_push (def_stmt_info); - } - - return NULL_TREE; -} - -/* Look if STMT_INFO is consumed by SLP indirectly and mark it pure_slp - if so, otherwise pushing it to WORKLIST. */ - -static void -maybe_push_to_hybrid_worklist (vec_info *vinfo, - vec<stmt_vec_info> &worklist, - stmt_vec_info stmt_info) -{ - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Processing hybrid candidate : %G", stmt_info->stmt); - stmt_vec_info orig_info = vect_orig_stmt (stmt_info); - imm_use_iterator iter2; - ssa_op_iter iter1; - use_operand_p use_p; - def_operand_p def_p; - bool any_def = false; - FOR_EACH_PHI_OR_STMT_DEF (def_p, orig_info->stmt, iter1, SSA_OP_DEF) - { - any_def = true; - FOR_EACH_IMM_USE_FAST (use_p, iter2, DEF_FROM_PTR (def_p)) - { - if (is_gimple_debug (USE_STMT (use_p))) - continue; - stmt_vec_info use_info = vinfo->lookup_stmt (USE_STMT (use_p)); - /* An out-of loop use means this is a loop_vect sink. */ - if (!use_info) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Found loop_vect sink: %G", stmt_info->stmt); - worklist.safe_push (stmt_info); - return; - } - else if (!STMT_SLP_TYPE (vect_stmt_to_vectorize (use_info))) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Found loop_vect use: %G", use_info->stmt); - worklist.safe_push (stmt_info); - return; - } - } - } - /* No def means this is a loop_vect sink. Gimple conditionals also don't have a - def but shouldn't be considered sinks. */ - if (!any_def && STMT_VINFO_DEF_TYPE (stmt_info) != vect_condition_def) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Found loop_vect sink: %G", stmt_info->stmt); - worklist.safe_push (stmt_info); - return; - } - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Marked SLP consumed stmt pure: %G", stmt_info->stmt); - STMT_SLP_TYPE (stmt_info) = pure_slp; -} - -/* Find stmts that must be both vectorized and SLPed. */ - -bool -vect_detect_hybrid_slp (loop_vec_info loop_vinfo) -{ - DUMP_VECT_SCOPE ("vect_detect_hybrid_slp"); - - /* All stmts participating in SLP are marked pure_slp, all other - stmts are loop_vect. - First collect all loop_vect stmts into a worklist. - SLP patterns cause not all original scalar stmts to appear in - SLP_TREE_SCALAR_STMTS and thus not all of them are marked pure_slp. - Rectify this here and do a backward walk over the IL only considering - stmts as loop_vect when they are used by a loop_vect stmt and otherwise - mark them as pure_slp. */ - auto_vec<stmt_vec_info> worklist; - for (int i = LOOP_VINFO_LOOP (loop_vinfo)->num_nodes - 1; i >= 0; --i) - { - basic_block bb = LOOP_VINFO_BBS (loop_vinfo)[i]; - for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi); - gsi_next (&gsi)) - { - gphi *phi = gsi.phi (); - stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (phi); - if (!STMT_SLP_TYPE (stmt_info) && STMT_VINFO_RELEVANT (stmt_info)) - maybe_push_to_hybrid_worklist (loop_vinfo, - worklist, stmt_info); - } - for (gimple_stmt_iterator gsi = gsi_last_bb (bb); !gsi_end_p (gsi); - gsi_prev (&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - if (is_gimple_debug (stmt)) - continue; - stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (stmt); - if (STMT_VINFO_IN_PATTERN_P (stmt_info)) - { - for (gimple_stmt_iterator gsi2 - = gsi_start (STMT_VINFO_PATTERN_DEF_SEQ (stmt_info)); - !gsi_end_p (gsi2); gsi_next (&gsi2)) - { - stmt_vec_info patt_info - = loop_vinfo->lookup_stmt (gsi_stmt (gsi2)); - if (!STMT_SLP_TYPE (patt_info) - && STMT_VINFO_RELEVANT (patt_info)) - maybe_push_to_hybrid_worklist (loop_vinfo, - worklist, patt_info); - } - stmt_info = STMT_VINFO_RELATED_STMT (stmt_info); - } - if (!STMT_SLP_TYPE (stmt_info) && STMT_VINFO_RELEVANT (stmt_info)) - maybe_push_to_hybrid_worklist (loop_vinfo, - worklist, stmt_info); - } - } - - /* Now we have a worklist of non-SLP stmts, follow use->def chains and - mark any SLP vectorized stmt as hybrid. - ??? We're visiting def stmts N times (once for each non-SLP and - once for each hybrid-SLP use). */ - walk_stmt_info wi; - vdhs_data dat; - dat.worklist = &worklist; - dat.loop_vinfo = loop_vinfo; - memset (&wi, 0, sizeof (wi)); - wi.info = (void *)&dat; - while (!worklist.is_empty ()) - { - stmt_vec_info stmt_info = worklist.pop (); - /* Since SSA operands are not set up for pattern stmts we need - to use walk_gimple_op. */ - wi.is_lhs = 0; - walk_gimple_op (stmt_info->stmt, vect_detect_hybrid_slp, &wi); - /* For gather/scatter make sure to walk the offset operand, that - can be a scaling and conversion away. */ - gather_scatter_info gs_info; - if (STMT_VINFO_GATHER_SCATTER_P (stmt_info) - && vect_check_gather_scatter (stmt_info, loop_vinfo, &gs_info)) - { - int dummy; - vect_detect_hybrid_slp (&gs_info.offset, &dummy, &wi); - } - } - - /* Determine if all the stmts in the loop can be SLPed. */ - for (unsigned i = 0; i < LOOP_VINFO_LOOP (loop_vinfo)->num_nodes; i++) - { - basic_block bb = LOOP_VINFO_BBS (loop_vinfo)[i]; - for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); - gsi_next (&si)) - { - stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (si.phi ()); - if (!stmt_info) - continue; - if ((STMT_VINFO_RELEVANT_P (stmt_info) - || VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (stmt_info))) - && !PURE_SLP_STMT (stmt_info)) - { - /* STMT needs both SLP and loop-based vectorization. */ - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Loop contains SLP and non-SLP stmts\n"); - return false; - } - } - for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si); - gsi_next (&si)) - { - if (is_gimple_debug (gsi_stmt (si))) - continue; - stmt_vec_info stmt_info = loop_vinfo->lookup_stmt (gsi_stmt (si)); - stmt_info = vect_stmt_to_vectorize (stmt_info); - if ((STMT_VINFO_RELEVANT_P (stmt_info) - || VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (stmt_info))) - && !PURE_SLP_STMT (stmt_info)) - { - /* STMT needs both SLP and loop-based vectorization. */ - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Loop contains SLP and non-SLP stmts\n"); - return false; - } - } - } - - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "Loop contains only SLP stmts\n"); - return true; -} - - /* Initialize a bb_vec_info struct for the statements in BBS basic blocks. */ _bb_vec_info::_bb_vec_info (vec<basic_block> _bbs, vec_info_shared *shared) @@ -7937,7 +7749,10 @@ vect_slp_analyze_node_operations_1 (vec_info *vinfo, slp_tree node, elements in a vector. For single-defuse-cycle, lane-reducing op, and PHI statement that starts reduction comprised of only lane-reducing ops, the number is more than effective vector statements actually required. */ - SLP_TREE_NUMBER_OF_VEC_STMTS (node) = vect_get_num_copies (vinfo, node); + if (SLP_TREE_VECTYPE (node)) + SLP_TREE_NUMBER_OF_VEC_STMTS (node) = vect_get_num_copies (vinfo, node); + else + SLP_TREE_NUMBER_OF_VEC_STMTS (node) = 0; /* Handle purely internal nodes. */ if (SLP_TREE_CODE (node) == VEC_PERM_EXPR) @@ -11294,8 +11109,10 @@ vect_schedule_slp_node (vec_info *vinfo, stmt_vec_info stmt_info = SLP_TREE_REPRESENTATIVE (node); - gcc_assert (SLP_TREE_NUMBER_OF_VEC_STMTS (node) != 0); - SLP_TREE_VEC_DEFS (node).create (SLP_TREE_NUMBER_OF_VEC_STMTS (node)); + gcc_assert (!SLP_TREE_VECTYPE (node) + || SLP_TREE_NUMBER_OF_VEC_STMTS (node) != 0); + if (SLP_TREE_NUMBER_OF_VEC_STMTS (node) != 0) + SLP_TREE_VEC_DEFS (node).create (SLP_TREE_NUMBER_OF_VEC_STMTS (node)); if (SLP_TREE_CODE (node) != VEC_PERM_EXPR && STMT_VINFO_DATA_REF (stmt_info)) @@ -11540,8 +11357,6 @@ vect_remove_slp_scalar_calls (vec_info *vinfo, { if (!stmt_info) continue; - if (!PURE_SLP_STMT (stmt_info)) - continue; stmt_info = vect_orig_stmt (stmt_info); gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt); if (!stmt || gimple_bb (stmt) == NULL) diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 97222f6..f7a052b 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -386,6 +386,9 @@ vect_stmt_relevant_p (stmt_vec_info stmt_info, loop_vec_info loop_vinfo, dump_printf_loc (MSG_NOTE, vect_location, "vec_stmt_relevant_p: stmt has vdefs.\n"); *relevant = vect_used_in_scope; + if (! STMT_VINFO_DATA_REF (stmt_info) + && zero_ssa_operands (stmt_info->stmt, SSA_OP_DEF)) + LOOP_VINFO_ALTERNATE_DEFS (loop_vinfo).safe_push (stmt_info); } /* uses outside the loop. */ @@ -4752,7 +4755,8 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info, } } - SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt)); + if (gimple_get_lhs (new_stmt)) + SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt)); } for (i = 0; i < nargs; ++i) @@ -7780,10 +7784,6 @@ vectorizable_store (vec_info *vinfo, return false; } - /* Cannot have hybrid store SLP -- that would mean storing to the - same location twice. */ - gcc_assert (PURE_SLP_STMT (stmt_info)); - tree vectype = SLP_TREE_VECTYPE (stmt_info), rhs_vectype = NULL_TREE; poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc index f992856..50985a6 100644 --- a/gcc/tree-vectorizer.cc +++ b/gcc/tree-vectorizer.cc @@ -733,7 +733,7 @@ vec_info::new_stmt_vec_info (gimple *stmt) else STMT_VINFO_DEF_TYPE (res) = vect_internal_def; - STMT_SLP_TYPE (res) = loop_vect; + STMT_SLP_TYPE (res) = not_vect; /* This is really "uninitialized" until vect_compute_data_ref_alignment. */ res->dr_aux.misalignment = DR_MISALIGNMENT_UNINITIALIZED; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 0a75ee1..52e1075 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -947,6 +947,10 @@ public: stmt in the chain. */ auto_vec<stmt_vec_info> reduction_chains; + /* Defs that could not be analyzed such as OMP SIMD calls without + a LHS. */ + auto_vec<stmt_vec_info> alternate_defs; + /* Cost vector for a single scalar iteration. */ auto_vec<stmt_info_for_cost> scalar_cost_vec; @@ -1186,6 +1190,7 @@ public: #define LOOP_VINFO_INNER_LOOP_COST_FACTOR(L) (L)->inner_loop_cost_factor #define LOOP_VINFO_INV_PATTERN_DEF_SEQ(L) (L)->inv_pattern_def_seq #define LOOP_VINFO_DRS_ADVANCED_BY(L) (L)->drs_advanced_by +#define LOOP_VINFO_ALTERNATE_DEFS(L) (L)->alternate_defs #define LOOP_VINFO_FULLY_MASKED_P(L) \ (LOOP_VINFO_USING_PARTIAL_VECTORS_P (L) \ @@ -1288,26 +1293,12 @@ enum vect_relevant { vect_used_in_scope }; -/* The type of vectorization that can be applied to the stmt: regular loop-based - vectorization; pure SLP - the stmt is a part of SLP instances and does not - have uses outside SLP instances; or hybrid SLP and loop-based - the stmt is - a part of SLP instance and also must be loop-based vectorized, since it has - uses outside SLP sequences. - - In the loop context the meanings of pure and hybrid SLP are slightly - different. By saying that pure SLP is applied to the loop, we mean that we - exploit only intra-iteration parallelism in the loop; i.e., the loop can be - vectorized without doing any conceptual unrolling, cause we don't pack - together stmts from different iterations, only within a single iteration. - Loop hybrid SLP means that we exploit both intra-iteration and - inter-iteration parallelism (e.g., number of elements in the vector is 4 - and the slp-group-size is 2, in which case we don't have enough parallelism - within an iteration, so we obtain the rest of the parallelism from subsequent - iterations by unrolling the loop by 2). */ +/* The type of vectorization. pure_slp means the stmt is covered by the + SLP graph, not_vect means it is not. This is mostly used by BB + vectorization. */ enum slp_vect_type { - loop_vect = 0, + not_vect = 0, pure_slp, - hybrid }; /* Says whether a statement is a load, a store of a vectorized statement @@ -1655,7 +1646,6 @@ struct gather_scatter_info { #define STMT_VINFO_RELEVANT_P(S) ((S)->relevant != vect_unused_in_scope) -#define HYBRID_SLP_STMT(S) ((S)->slp_type == hybrid) #define PURE_SLP_STMT(S) ((S)->slp_type == pure_slp) #define STMT_SLP_TYPE(S) (S)->slp_type diff --git a/gcc/tree.cc b/gcc/tree.cc index 0f02924..dcc1abd 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -323,9 +323,9 @@ unsigned const char omp_clause_num_ops[] = 1, /* OMP_CLAUSE_IS_DEVICE_PTR */ 1, /* OMP_CLAUSE_INCLUSIVE */ 1, /* OMP_CLAUSE_EXCLUSIVE */ - 2, /* OMP_CLAUSE_FROM */ - 2, /* OMP_CLAUSE_TO */ - 2, /* OMP_CLAUSE_MAP */ + 3, /* OMP_CLAUSE_FROM */ + 3, /* OMP_CLAUSE_TO */ + 3, /* OMP_CLAUSE_MAP (update walk_tree_1 if this is changed) */ 1, /* OMP_CLAUSE_HAS_DEVICE_ADDR */ 1, /* OMP_CLAUSE_DOACROSS */ 3, /* OMP_CLAUSE__MAPPER_BINDING_ */ @@ -11769,6 +11769,9 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE: { int len = omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; + /* Do not walk the iterator operand of OpenMP MAP clauses. */ + if (OMP_CLAUSE_HAS_ITERATORS (t)) + len--; for (int i = 0; i < len; i++) WALK_SUBTREE (OMP_CLAUSE_OPERAND (t, i)); WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (t)); @@ -1659,6 +1659,16 @@ class auto_suppress_location_wrappers != UNKNOWN_LOCATION) #define OMP_CLAUSE_LOCATION(NODE) (OMP_CLAUSE_CHECK (NODE))->omp_clause.locus +#define OMP_CLAUSE_HAS_ITERATORS(NODE) \ + ((OMP_CLAUSE_CODE (NODE) == OMP_CLAUSE_FROM \ + || OMP_CLAUSE_CODE (NODE) == OMP_CLAUSE_TO \ + || OMP_CLAUSE_CODE (NODE) == OMP_CLAUSE_MAP) \ + && OMP_CLAUSE_ITERATORS (NODE)) +#define OMP_CLAUSE_ITERATORS(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ + OMP_CLAUSE_FROM, \ + OMP_CLAUSE_MAP), 2) + /* True on OMP_FOR and other OpenMP/OpenACC looping constructs if the loop nest is non-rectangular. */ #define OMP_FOR_NON_RECTANGULAR(NODE) \ |