diff options
Diffstat (limited to 'gcc')
490 files changed, 22865 insertions, 3453 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4b6bc90..b600551 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,352 @@ +2025-08-06 Uros Bizjak <ubizjak@gmail.com> + + PR target/96226 + * config/i386/predicates.md (and_operator): New operator. + * config/i386/i386.md (splitter after *<rotate_insn><mode>3_mask): + Use and_operator to match AND RTX and use its mode + in the split pattern. + +2025-08-06 Gerald Pfeifer <gerald@pfeifer.com> + + PR target/69374 + * doc/install.texi (Prerequisites): Replace bzip2 by xz. + +2025-08-06 Yangyu Chen <cyy@cyyself.name> + + * config/i386/i386.h (PTA_BDVER1): + Add missing PTA_POPCNT and PTA_LZCNT with PTA_ABM. + (PTA_ZNVER1): Ditto. + (PTA_BTVER1): Ditto. + (PTA_LUJIAZUI): Ditto. + (PTA_YONGFENG): Do not include extra PTA_LZCNT. + +2025-08-06 Sam James <sam@gentoo.org> + + PR libstdc++/29286 + * Makefile.in (ALIASING_FLAGS): Drop. + * configure: Regenerate. + * configure.ac: Drop -fno-strict-aliasing workaround for < GCC 4.3. + +2025-08-06 Richard Biener <rguenther@suse.de> + + * tree-vect-data-refs.cc (vect_supportable_dr_alignment): + Prune dead code. + +2025-08-06 Patrick Palka <ppalka@redhat.com> + + PR c++/121231 + PR c++/119688 + PR c++/94511 + * common.opt: Document additional ABI version 21 change. + * doc/invoke.texi: Likewise. + +2025-08-06 Richard Biener <rguenther@suse.de> + + * tree-vectorizer.h (_slp_tree::gs_scale): New. + (_slp_tree::gs_base): Likewise. + (SLP_TREE_GS_SCALE): Likewise. + (SLP_TREE_GS_BASE): Likewise. + (vect_describe_gather_scatter_call): Declare. + * tree-vect-slp.cc (_slp_tree::_slp_tree): Initialize + new members. + (vect_build_slp_tree_2): Record gather/scatter base and scale. + (vect_get_and_check_slp_defs): For gather/scatter IFNs + describe the call to first_gs_info. + * tree-vect-data-refs.cc (vect_gather_scatter_fn_p): Add + mode of operation with fixed offset vector type. + (vect_describe_gather_scatter_call): Export. + * tree-vect-stmts.cc (get_load_store_type): Do not call + vect_check_gather_scatter to fill gs_info, instead populate + from the SLP tree. Check which of, IFN, decl or fallback + is supported and record that decision. + +2025-08-06 Richard Biener <rguenther@suse.de> + + * tree-vect-stmts.cc (vectorizable_store): Build proper + alias + align pointer value for gather/scatter and SLP + and use it. + (vectorizable_load): Likewise. + +2025-08-06 Richard Biener <rguenther@suse.de> + + * tree-vect-stmts.cc (check_load_store_for_partial_vectors): + Remove redundant gather/scatter target support check, instead + check the recorded ifns. Also allow legacy gather/scatter + with loop masking. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/121413 + * gimple-lower-bitint.cc (gimple_lower_bitint): Fix up last + commit, cast limb_prec to unsigned before comparison. + +2025-08-06 Yang Yujie <yangyujie@loongson.cn> + + * match.pd: Preserve conversion to _BitInt before a VCE + if the _BitInt is extended. + +2025-08-06 Yang Yujie <yangyujie@loongson.cn> + + * gimple-lower-bitint.cc (bitint_large_huge::lower_mergeable_stmt): + Zero-extend the partial limb of any unsigned _BitInt LHS assigned + with a widening sign-extension. + +2025-08-06 Yang Yujie <yangyujie@loongson.cn> + + * gimple-lower-bitint.cc (bitint_large_huge::limb_access): + Add a parameter abi_load_p. If set, load a limb directly + in its actual precision without casting from m_limb_type. + (struct bitint_large_huge): Same. + (bitint_large_huge::handle_load): Use. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/121413 + * gimple-lower-bitint.cc (abi_limb_prec): New variable + (bitint_precision_kind): Initialize it. + (gimple_lower_bitint): Clear it at the start. For + min_prec > limb_prec descreased precision vars for + INTEGER_CST PHI arguments ensure min_prec is either + prec or multiple of abi_limb_prec. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/121127 + * gimple-lower-bitint.cc (bitint_large_huge::handle_operand_addr): For + uninitialized SSA_NAME, set *prec_stored to 0 rather than *prec. + Handle that case in narrowing casts. If prec_stored is non-NULL, + set *prec_stored to prec_stored_val. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR bootstrap/121386 + * Makefile.in (gengtype-lex.cc): Append #define FLEX_SCANNER, + #include "system.h" and #undef FLEX_SCANNER to the prepended lines. + * gengtype-lex.l: Remove inclusion of config.h or bconfig.h, system.h + and definition of malloc/realloc from %{} section. + +2025-08-06 Kito Cheng <kito.cheng@sifive.com> + + * config/riscv/arch-canonicalize: Read extension data from + riscv-ext*.def and adding unittest. + +2025-08-06 Kito Cheng <kito.cheng@sifive.com> + + * common/config/riscv/riscv-common.cc (riscv_expand_arch): + Ignore `unset`. + * config/riscv/riscv.h (OPTION_DEFAULT_SPECS): Handle + `-march=unset`. + (ARCH_UNSET_CLEANUP_SPECS): New. + (DRIVER_SELF_SPECS): Handle -march=unset. + * doc/invoke.texi (RISC-V Options): Update documentation for + `-march=unset`. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * gimplify.cc (remove_unused_omp_iterator_vars): Display unused + variable warning for 'to' and 'from' clauses. + (gimplify_scan_omp_clauses): Add argument for iterator loop sequence. + Gimplify the clause decl and size into the iterator loop if iterators + are used. + (gimplify_omp_workshare): Add argument for iterator loops sequence + in call to gimplify_scan_omp_clauses. + (gimplify_omp_target_update): Call remove_unused_omp_iterator_vars and + build_omp_iterators_loops. Add loop sequence as argument when calling + gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses and building + the Gimple statement. + * tree-pretty-print.cc (dump_omp_clause): Call dump_omp_iterators + for to/from clauses with iterators. + * tree.cc (omp_clause_num_ops): Add extra operand for OMP_CLAUSE_FROM + and OMP_CLAUSE_TO. + * tree.h (OMP_CLAUSE_HAS_ITERATORS): Add check for OMP_CLAUSE_TO and + OMP_CLAUSE_FROM. + (OMP_CLAUSE_ITERATORS): Likewise. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + Andrew Stubbs <ams@baylibre.com> + + * gimple-pretty-print.cc (dump_gimple_omp_target): Print expanded + iterator loops. + * gimple.cc (gimple_build_omp_target): Add argument for iterator + loops sequence. Initialize iterator loops field. + * gimple.def (GIMPLE_OMP_TARGET): Set GSS symbol to GSS_OMP_TARGET. + * gimple.h (gomp_target): Set GSS symbol to GSS_OMP_TARGET. Add extra + field for iterator loops. + (gimple_build_omp_target): Add argument for iterator loops sequence. + (gimple_omp_target_iterator_loops): New. + (gimple_omp_target_iterator_loops_ptr): New. + (gimple_omp_target_set_iterator_loops): New. + * gimplify.cc (find_var_decl): New. + (copy_omp_iterator): New. + (remap_omp_iterator_var_1): New. + (remap_omp_iterator_var): New. + (remove_unused_omp_iterator_vars): New. + (struct iterator_loop_info_t): New type. + (iterator_loop_info_map_t): New type. + (build_omp_iterators_loops): New. + (enter_omp_iterator_loop_context_1): New. + (enter_omp_iterator_loop_context): New. + (enter_omp_iterator_loop_context): New. + (exit_omp_iterator_loop_context): New. + (gimplify_adjust_omp_clauses): Add argument for iterator loop + sequence. Gimplify the clause decl and size into the iterator + loop if iterators are used. + (gimplify_omp_workshare): Call remove_unused_omp_iterator_vars and + build_omp_iterators_loops for OpenMP target expressions. Add + loop sequence as argument when calling gimplify_adjust_omp_clauses + and building the Gimple statement. + * gimplify.h (enter_omp_iterator_loop_context): New prototype. + (exit_omp_iterator_loop_context): New prototype. + * gsstruct.def (GSS_OMP_TARGET): New. + * omp-low.cc (lower_omp_map_iterator_expr): New. + (lower_omp_map_iterator_size): New. + (finish_omp_map_iterators): New. + (lower_omp_target): Add sorry if iterators used with deep mapping. + Call lower_omp_map_iterator_expr before assigning to sender ref. + Call lower_omp_map_iterator_size before setting the size. Insert + iterator loop sequence before the statements for the target clause. + * tree-nested.cc (convert_nonlocal_reference_stmt): Walk the iterator + loop sequence of OpenMP target statements. + (convert_local_reference_stmt): Likewise. + (convert_tramp_reference_stmt): Likewise. + * tree-pretty-print.cc (dump_omp_iterators): Dump extra iterator + information if present. + (dump_omp_clause): Call dump_omp_iterators for iterators in map + clauses. + * tree.cc (omp_clause_num_ops): Add operand for OMP_CLAUSE_MAP. + (walk_tree_1): Do not walk last operand of OMP_CLAUSE_MAP. + * tree.h (OMP_CLAUSE_HAS_ITERATORS): New. + (OMP_CLAUSE_ITERATORS): New. + +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 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 3724f15..d4024d7 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20250805 +20250807 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index d7d5cbe..cc79595 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -187,8 +187,6 @@ C_STRICT_WARN = @c_strict_warn@ NOEXCEPTION_FLAGS = @noexception_flags@ -ALIASING_FLAGS = @aliasing_flags@ - # This is set by --disable-maintainer-mode (default) to "#" # FIXME: 'MAINT' will always be set to an empty string, no matter if # --disable-maintainer-mode is used or not. This is because the @@ -3402,6 +3400,9 @@ gengtype-lex.cc : gengtype-lex.l echo '#else' >> $@.tmp; \ echo '#include "bconfig.h"' >> $@.tmp; \ echo '#endif' >> $@.tmp; \ + echo '#define FLEX_SCANNER' >> $@.tmp; \ + echo '#include "system.h"' >> $@.tmp; \ + echo '#undef FLEX_SCANNER' >> $@.tmp; \ cat $@ >> $@.tmp; \ mv $@.tmp $@; \ } diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index c9ab153..2abe6df 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2025-08-06 Alexandre Oliva <oliva@adacore.com> + + * c-attribs.cc (handle_hardbool_attribute): Create distinct + enumeration types, with structural equality. Handle + base type qualifiers. + 2025-08-02 Martin Uecker <uecker@tugraz.at> * c-attribs.cc (handle_argspec_attribute): Update. diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index a0d832b..041a004 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -1128,11 +1128,16 @@ handle_hardbool_attribute (tree *node, tree name, tree args, } tree orig = *node; - *node = build_duplicate_type (orig); + /* Drop qualifiers from the base type. Keep attributes, so that, in the odd + chance attributes are applicable and relevant to the base type, if they + are specified first, or through a typedef, they wouldn't be dropped on the + floor here. */ + tree unqual = build_qualified_type (orig, TYPE_UNQUALIFIED); + *node = build_distinct_type_copy (unqual); TREE_SET_CODE (*node, ENUMERAL_TYPE); - ENUM_UNDERLYING_TYPE (*node) = orig; - TYPE_CANONICAL (*node) = TYPE_CANONICAL (orig); + ENUM_UNDERLYING_TYPE (*node) = unqual; + SET_TYPE_STRUCTURAL_EQUALITY (*node); tree false_value; if (args) @@ -1191,7 +1196,13 @@ handle_hardbool_attribute (tree *node, tree name, tree args, gcc_checking_assert (!TYPE_CACHED_VALUES_P (*node)); TYPE_VALUES (*node) = values; - TYPE_NAME (*node) = orig; + TYPE_NAME (*node) = unqual; + + if (TYPE_QUALS (orig) != TYPE_QUALS (*node)) + { + *node = build_qualified_type (*node, TYPE_QUALS (orig)); + TYPE_NAME (*node) = orig; + } return NULL_TREE; } diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 7c7e21d..009c8ef 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -747,7 +747,7 @@ enum cxx_dialect { cxx26 }; -/* The C++ dialect being used. C++98 is the default. */ +/* The C++ dialect being used. C++17 is the default. */ extern enum cxx_dialect cxx_dialect; /* Maximum template instantiation depth. This limit is rather diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index c652e82..3fb12b9 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -959,6 +959,15 @@ c_common_post_options (const char **pfilename) if (warn_enum_compare == -1) warn_enum_compare = c_dialect_cxx () ? 1 : 0; + /* For C++26 default to -Wkeyword-macro if -Wpedantic. */ + if (cxx_dialect >= cxx26 && pedantic) + { + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + warn_keyword_macro, 1); + if (warn_keyword_macro) + cpp_opts->cpp_warn_keyword_macro = warn_keyword_macro; + } + /* -Wpacked-bitfield-compat is on by default for the C languages. The warning is issued in stor-layout.cc which is not part of the front-end so we need to selectively turn it on here. */ diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 12877eb..0ee2c30 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -964,6 +964,10 @@ Enum(warn_leading_whitespace_kind) String(tabs) Value(2) EnumValue Enum(warn_leading_whitespace_kind) String(blanks) Value(3) +Wkeyword-macro +C ObjC C++ ObjC++ CPP(cpp_warn_keyword_macro) CppReason(CPP_W_KEYWORD_MACRO) Var(warn_keyword_macro) Init(0) Warning +Warn about defining or undefining macros with identifiers equal to keywords (or for C++ conditional keywords or standard attribute names). + Wleading-whitespace= C ObjC C++ ObjC++ CPP(cpp_warn_leading_whitespace) CppReason(CPP_W_LEADING_WHITESPACE) Enum(warn_leading_whitespace_kind) Joined RejectNegative Var(warn_leading_whitespace) Init(0) Warning Warn about leading whitespace style issues on lines except when in raw string literals. diff --git a/gcc/c-family/c.opt.urls b/gcc/c-family/c.opt.urls index 5c97593..6eb1178 100644 --- a/gcc/c-family/c.opt.urls +++ b/gcc/c-family/c.opt.urls @@ -508,6 +508,9 @@ UrlSuffix(gcc/Warning-Options.html#index-Winvalid-utf8) Wjump-misses-init UrlSuffix(gcc/Warning-Options.html#index-Wjump-misses-init) +Wkeyword-macro +UrlSuffix(gcc/Warning-Options.html#index-Wkeyword-macro) + Wleading-whitespace= UrlSuffix(gcc/Warning-Options.html#index-Wleading-whitespace_003d) diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 464e5a1..2e5c896 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,45 @@ +2025-08-06 Alexandre Oliva <oliva@adacore.com> + + * c-tree.h (C_BOOLEAN_TYPE_P): Cover hardbools as well. + * c-typeck.cc (convert_lvalue_to_rvalue): New overload and + wrapper. + (build_atomic_assign, build_modify_expr): Use it. + (build_asm_expr, handle_omp-array_sections_1): Simplify with + it. + (build_unary_op): Handle hardbools. + +2025-08-06 Martin Uecker <uecker@tugraz.at> + + PR c/108931 + * c-typeck.cc (composite_type_cond): Renamed from + composite_type with argument for condition + (composite_type): New function. + (composite_type_internal): Implement new logic. + (build_conditional_expr): Pass condition. + (common_pointer_type): Adapt. + (pointer_diff): Adapt. + (build_binary_op): Adapt. + +2025-08-06 Martin Uecker <uecker@tugraz.at> + + PR c/121217 + * c-typeck.cc (tagged_types_tu_compatible_p): Add check. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * c-parser.cc (c_parser_omp_clause_from_to): Parse 'iterator' modifier. + * c-typeck.cc (c_finish_omp_clauses): Finish iterators for to/from + clauses. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + Andrew Stubbs <ams@baylibre.com> + + * c-parser.cc (c_parser_omp_variable_list): Use location of the + map expression as the clause location. + (c_parser_omp_clause_map): Parse 'iterator' modifier. + * c-typeck.cc (c_finish_omp_clauses): Finish iterators. Apply + iterators to generated clauses. + 2025-08-02 Martin Uecker <uecker@tugraz.at> * c-decl.cc (get_parm_array_spec): Remove. diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 7850365..8e8bac6 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4825,6 +4825,29 @@ c_init_decl_processing (void) make_fname_decl = c_make_fname_decl; start_fname_decls (); + + if (warn_keyword_macro) + { + for (unsigned int i = 0; i < num_c_common_reswords; ++i) + /* For C register keywords which don't start with underscore + or start with just single underscore. Don't complain about + ObjC or Transactional Memory keywords. */ + if (c_common_reswords[i].word[0] == '_' + && c_common_reswords[i].word[1] == '_') + continue; + else if (c_common_reswords[i].disable + & (D_TRANSMEM | D_OBJC | D_CXX_OBJC)) + continue; + else + { + tree id = get_identifier (c_common_reswords[i].word); + if (C_IS_RESERVED_WORD (id) + && C_RID_CODE (id) != RID_CXX_COMPAT_WARN) + cpp_lookup (parse_in, + (const unsigned char *) IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id))->flags |= NODE_WARN; + } + } } /* Create the VAR_DECL at LOC for __FUNCTION__ etc. ID is the name 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-tree.h b/gcc/c/c-tree.h index bb0b113..dba94ab 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -163,7 +163,8 @@ along with GCC; see the file COPYING3. If not see (TREE_CODE (TYPE) == BOOLEAN_TYPE \ || (TREE_CODE (TYPE) == ENUMERAL_TYPE \ && ENUM_UNDERLYING_TYPE (TYPE) != NULL_TREE \ - && TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE)) + && (TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE \ + || c_hardbool_type_attr (TYPE)))) /* Record parser information about an expression that is irrelevant for code generation alongside a tree representing its value. */ diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index ed6e56e..7a95f72 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -641,7 +641,8 @@ struct composite_cache { }; tree -composite_type_internal (tree t1, tree t2, struct composite_cache* cache) +composite_type_internal (tree t1, tree t2, tree cond, + struct composite_cache* cache) { enum tree_code code1; enum tree_code code2; @@ -686,8 +687,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) { tree pointed_to_1 = TREE_TYPE (t1); tree pointed_to_2 = TREE_TYPE (t2); - tree target = composite_type_internal (pointed_to_1, - pointed_to_2, cache); + tree target = composite_type_internal (pointed_to_1, pointed_to_2, + cond, cache); t1 = c_build_pointer_type_for_mode (target, TYPE_MODE (t1), false); t1 = c_build_type_attribute_variant (t1, attributes); return qualify_type (t1, t2); @@ -695,25 +696,20 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) case ARRAY_TYPE: { - tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), - cache); - int quals; - tree unqual_elt; tree d1 = TYPE_DOMAIN (t1); tree d2 = TYPE_DOMAIN (t2); - bool d1_variable, d2_variable; - bool d1_zero, d2_zero; - bool t1_complete, t2_complete; /* We should not have any type quals on arrays at all. */ gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) && !TYPE_QUALS_NO_ADDR_SPACE (t2)); - t1_complete = COMPLETE_TYPE_P (t1); - t2_complete = COMPLETE_TYPE_P (t2); + bool t1_complete = COMPLETE_TYPE_P (t1); + bool t2_complete = COMPLETE_TYPE_P (t2); - d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1); - d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2); + bool d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1); + bool d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2); + + bool d1_variable, d2_variable; d1_variable = (!d1_zero && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST @@ -722,10 +718,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); - bool use1 = TYPE_DOMAIN (t1) - && (d2_variable || d2_zero || !d1_variable); - bool use2 = TYPE_DOMAIN (t2) - && (d1_variable || d1_zero || !d2_variable); + bool use1 = d1 && (d2_variable || d2_zero || !d1_variable); + bool use2 = d2 && (d1_variable || d1_zero || !d2_variable); /* If the first is an unspecified size pick the other one. */ if (d2_variable && c_type_unspecified_p (t1)) @@ -734,25 +728,53 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) use1 = false; } - /* Save space: see if the result is identical to one of the args. */ - if (elt == TREE_TYPE (t1) && use1) - return c_build_type_attribute_variant (t1, attributes); - if (elt == TREE_TYPE (t2) && use2) - return c_build_type_attribute_variant (t2, attributes); + /* If both are VLAs but not unspecified and we are in the + conditional operator, we create a conditional to select + the size of the active branch. */ + bool use0 = cond && d1_variable && !c_type_unspecified_p (t1) + && d2_variable && !c_type_unspecified_p (t2); + + tree td; + tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), + cond, cache); + + if (!use0) + { + /* Save space: see if the result is identical to one of the args. */ + if (elt == TREE_TYPE (t1) && use1) + return c_build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && use2) + return c_build_type_attribute_variant (t2, attributes); + + if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return c_build_type_attribute_variant (t1, attributes); + if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) + return c_build_type_attribute_variant (t2, attributes); + + td = TYPE_DOMAIN (use1 ? t1 : t2); + } + else + { + /* Not used in C. */ + gcc_assert (size_zero_node == TYPE_MIN_VALUE (d1)); + gcc_assert (size_zero_node == TYPE_MIN_VALUE (d2)); - if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return c_build_type_attribute_variant (t1, attributes); - if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) - return c_build_type_attribute_variant (t2, attributes); + tree d = fold_build3_loc (UNKNOWN_LOCATION, COND_EXPR, sizetype, + cond, TYPE_MAX_VALUE (d1), + TYPE_MAX_VALUE (d2)); + + td = build_index_type (d); + } /* Merge the element types, and have a size if either arg has one. We may have qualifiers on the element types. To set up TYPE_MAIN_VARIANT correctly, we need to form the composite of the unqualified types and add the qualifiers back at the end. */ - quals = TYPE_QUALS (strip_array_types (elt)); - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); - t1 = c_build_array_type (unqual_elt, TYPE_DOMAIN (use1 ? t1 : t2)); + int quals = TYPE_QUALS (strip_array_types (elt)); + tree unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + + t1 = c_build_array_type (unqual_elt, td); /* Check that a type which has a varying outermost dimension got marked has having a variable size. */ @@ -819,7 +841,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) gcc_assert (DECL_NAME (a) == DECL_NAME (b)); gcc_checking_assert (!DECL_NAME (a) || comptypes (ta, tb)); - tree t = composite_type_internal (ta, tb, cache); + tree t = composite_type_internal (ta, tb, cond, cache); tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a), t); DECL_PACKED (f) = DECL_PACKED (a); @@ -876,8 +898,8 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) /* Function types: prefer the one that specified arg types. If both do, merge the arg types. Also merge the return types. */ { - tree valtype = composite_type_internal (TREE_TYPE (t1), - TREE_TYPE (t2), cache); + tree valtype = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2), + cond, cache); tree p1 = TYPE_ARG_TYPES (t1); tree p2 = TYPE_ARG_TYPES (t2); int len; @@ -956,7 +978,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) { TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb), TREE_VALUE (p2), - cache); + cond, cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; @@ -979,14 +1001,14 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) TREE_VALUE (n) = composite_type_internal (TREE_TYPE (memb), TREE_VALUE (p1), - cache); + cond, cache); pedwarn (input_location, OPT_Wpedantic, "function types not truly compatible in ISO C"); goto parm_done; } } } - TREE_VALUE (n) = composite_type_internal (mv1, mv2, cache); + TREE_VALUE (n) = composite_type_internal (mv1, mv2, cond, cache); parm_done: ; } @@ -1001,18 +1023,25 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) } tree -composite_type (tree t1, tree t2) +composite_type_cond (tree t1, tree t2, tree cond) { gcc_checking_assert (comptypes_check_for_composite (t1, t2)); struct composite_cache cache = { }; - tree n = composite_type_internal (t1, t2, &cache); + tree n = composite_type_internal (t1, t2, cond, &cache); gcc_checking_assert (comptypes_check_for_composite (n, t1)); gcc_checking_assert (comptypes_check_for_composite (n, t2)); return n; } + +tree +composite_type (tree t1, tree t2) +{ + return composite_type_cond (t1, t2, NULL_TREE); +} + /* Return the type of a conditional expression between pointers to possibly differently qualified versions of compatible types. @@ -1020,7 +1049,7 @@ composite_type (tree t1, tree t2) true; if that isn't so, this may crash. */ static tree -common_pointer_type (tree t1, tree t2) +common_pointer_type (tree t1, tree t2, tree cond) { tree attributes; unsigned target_quals; @@ -1047,8 +1076,8 @@ common_pointer_type (tree t1, tree t2) qualifiers of the two types' targets. */ tree pointed_to_1 = TREE_TYPE (t1); tree pointed_to_2 = TREE_TYPE (t2); - tree target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1), - TYPE_MAIN_VARIANT (pointed_to_2)); + tree target = composite_type_cond (TYPE_MAIN_VARIANT (pointed_to_1), + TYPE_MAIN_VARIANT (pointed_to_2), cond); /* Strip array types to get correct qualifier for pointers to arrays */ quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1)); @@ -1970,6 +1999,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2, ft2 = DECL_BIT_FIELD_TYPE (s2); } + if (!ft1 || !ft2) + return false; + if (TREE_CODE (ft1) == ERROR_MARK || TREE_CODE (ft2) == ERROR_MARK) return false; @@ -2648,6 +2680,20 @@ convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, return exp; } +/* Wrapper for the overload above, same arguments but for tree rather than + c_expr. This is important for hardbools to decay to bools. */ + +static inline tree +convert_lvalue_to_rvalue (location_t loc, tree val, + bool convert_p, bool read_p, bool for_init = false) +{ + struct c_expr expr; + memset (&expr, 0, sizeof (expr)); + expr.value = val; + expr = convert_lvalue_to_rvalue (loc, expr, convert_p, read_p, for_init); + return expr.value; +} + /* EXP is an expression of integer type. Apply the integer promotions to it and return the promoted value. */ @@ -4926,7 +4972,7 @@ pointer_diff (location_t loc, tree op0, tree op1, tree *instrument_expr) if (!addr_space_superset (as0, as1, &as_common)) gcc_unreachable (); - common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1)); + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1), NULL_TREE); op0 = convert (common_type, op0); op1 = convert (common_type, op1); } @@ -5271,7 +5317,9 @@ cas_loop: /* newval = old + val; */ if (rhs_type != rhs_semantic_type) val = build1 (EXCESS_PRECISION_EXPR, nonatomic_rhs_semantic_type, val); - rhs = build_binary_op (loc, modifycode, old, val, true); + rhs = build_binary_op (loc, modifycode, + convert_lvalue_to_rvalue (loc, old, true, true), + val, true); if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR) { tree eptype = TREE_TYPE (rhs); @@ -5727,7 +5775,48 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, goto return_build_unary_op; } - if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) + tree true_res; + if (c_hardbool_type_attr (TREE_TYPE (arg), NULL, &true_res)) + { + tree larg = stabilize_reference (arg); + tree sarg = save_expr (larg); + switch (code) + { + case PREINCREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, true_res); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val); + break; + case POSTINCREMENT_EXPR: + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, true_res); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), val, sarg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val); + break; + case PREDECREMENT_EXPR: + { + tree rarg = convert_lvalue_to_rvalue (location, sarg, + true, true); + rarg = invert_truthvalue_loc (location, rarg); + rarg = convert (TREE_TYPE (sarg), rarg); + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, rarg); + } + break; + case POSTDECREMENT_EXPR: + { + tree rarg = convert_lvalue_to_rvalue (location, sarg, + true, true); + rarg = invert_truthvalue_loc (location, rarg); + tree iarg = convert (TREE_TYPE (larg), rarg); + val = build2 (MODIFY_EXPR, TREE_TYPE (larg), larg, iarg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), val, sarg); + val = build2 (COMPOUND_EXPR, TREE_TYPE (larg), sarg, val); + } + break; + default: + gcc_unreachable (); + } + TREE_SIDE_EFFECTS (val) = 1; + } + else if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) val = boolean_increment (code, arg); else val = build2 (code, TREE_TYPE (arg), arg, inc); @@ -6380,7 +6469,10 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, addr_space_t as_common; if (comp_target_types (colon_loc, type1, type2)) - result_type = common_pointer_type (type1, type2); + { + ifexp = save_expr (ifexp); + result_type = common_pointer_type (type1, type2, ifexp); + } else if (null_pointer_constant_p (orig_op1)) result_type = type2; else if (null_pointer_constant_p (orig_op2)) @@ -7337,8 +7429,10 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, clear_decl_read = true; } - newrhs = build_binary_op (location, - modifycode, lhs, newrhs, true); + newrhs = build_binary_op (location, modifycode, + convert_lvalue_to_rvalue (location, lhs, + true, true), + newrhs, true); if (clear_decl_read) DECL_READ_P (lhs) = 0; @@ -12730,11 +12824,9 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs, } else { - struct c_expr expr; - memset (&expr, 0, sizeof (expr)); - expr.value = input; - expr = convert_lvalue_to_rvalue (loc, expr, true, false); - input = c_fully_fold (expr.value, false, NULL); + input = c_fully_fold (convert_lvalue_to_rvalue (loc, input, + true, false), + false, NULL); if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input))) { @@ -14390,7 +14482,7 @@ build_binary_op (location_t location, enum tree_code code, Otherwise, the targets must be compatible and both must be object or both incomplete. */ if (comp_target_types (location, type0, type1)) - result_type = common_pointer_type (type0, type1); + result_type = common_pointer_type (type0, type1, NULL_TREE); else if (!addr_space_superset (as0, as1, &as_common)) { error_at (location, "comparison of pointers to " @@ -14529,7 +14621,7 @@ build_binary_op (location_t location, enum tree_code code, if (comp_target_types (location, type0, type1)) { - result_type = common_pointer_type (type0, type1); + result_type = common_pointer_type (type0, type1, NULL_TREE); if (!COMPLETE_TYPE_P (TREE_TYPE (type0)) != !COMPLETE_TYPE_P (TREE_TYPE (type1))) pedwarn_c99 (location, OPT_Wpedantic, @@ -15356,12 +15448,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, /* If the array section is pointer based and the pointer itself is _Atomic qualified, we need to atomically load the pointer. */ - c_expr expr; - memset (&expr, 0, sizeof (expr)); - expr.value = ret; - expr = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c), - expr, false, false); - ret = expr.value; + ret = convert_lvalue_to_rvalue (OMP_CLAUSE_LOCATION (c), + ret, false, false); } return ret; } @@ -16204,7 +16292,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 +17057,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 +17792,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/common.opt b/gcc/common.opt index 70659fa..bf38f60 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1067,6 +1067,8 @@ Driver Undocumented ; ; 21: Fix noexcept lambda capture pruning. ; Fix C++20 layout of base with all explicitly defaulted constructors. +; Fix mangling of class and array objects with implicitly +; zero-initialized non-trailing subojects. ; Default in G++ 16. ; ; Additional positive integers will be assigned as new versions of diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index da3cb9f..f2ede07 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -1758,6 +1758,11 @@ riscv_expand_arch (int argc, { gcc_assert (argc == 1); location_t loc = UNKNOWN_LOCATION; + + /* Filter out -march=unset, it will expand from -mcpu later. */ + if (strcmp (argv[0], "unset") == 0) + return ""; + /* Try to interpret the arch as CPU first. */ const char *arch_str = riscv_expand_arch_from_cpu (argc, argv); if (!strlen (arch_str)) diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 1bfa3f5..ae49d4d 100644 --- a/gcc/config/avr/avr.cc +++ b/gcc/config/avr/avr.cc @@ -12758,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)), diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index d4bf4da..60b1f60 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -2943,7 +2943,7 @@ [(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 @@ -3004,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 ;****************************************************************************** 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.h b/gcc/config/i386/i386.h index 791f3b9..49af963 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2477,9 +2477,9 @@ constexpr wide_int_bitmask PTA_DIAMONDRAPIDS = PTA_GRANITERAPIDS_D | PTA_MOVRS | PTA_AMX_MOVRS | PTA_USER_MSR; constexpr wide_int_bitmask PTA_BDVER1 = PTA_64BIT | PTA_MMX | PTA_SSE - | PTA_SSE2 | PTA_SSE3 | PTA_SSE4A | PTA_CX16 | PTA_ABM | PTA_SSSE3 - | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL | PTA_AVX | PTA_FMA4 - | PTA_XOP | PTA_LWP | PTA_PRFCHW | PTA_FXSR | PTA_XSAVE; + | PTA_SSE2 | PTA_SSE3 | PTA_SSE4A | PTA_CX16 | PTA_POPCNT | PTA_LZCNT + | PTA_ABM | PTA_SSSE3 | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL + | PTA_AVX | PTA_FMA4 | PTA_XOP | PTA_LWP | PTA_PRFCHW | PTA_FXSR | PTA_XSAVE; constexpr wide_int_bitmask PTA_BDVER2 = PTA_BDVER1 | PTA_BMI | PTA_TBM | PTA_F16C | PTA_FMA; constexpr wide_int_bitmask PTA_BDVER3 = PTA_BDVER2 | PTA_XSAVEOPT @@ -2487,13 +2487,13 @@ constexpr wide_int_bitmask PTA_BDVER3 = PTA_BDVER2 | PTA_XSAVEOPT constexpr wide_int_bitmask PTA_BDVER4 = PTA_BDVER3 | PTA_AVX2 | PTA_BMI2 | PTA_RDRND | PTA_MOVBE | PTA_MWAITX; -constexpr wide_int_bitmask PTA_ZNVER1 = PTA_64BIT | PTA_MMX | PTA_SSE | PTA_SSE2 - | PTA_SSE3 | PTA_SSE4A | PTA_CX16 | PTA_ABM | PTA_SSSE3 | PTA_SSE4_1 - | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL | PTA_AVX | PTA_AVX2 | PTA_BMI | PTA_BMI2 - | PTA_F16C | PTA_FMA | PTA_PRFCHW | PTA_FXSR | PTA_XSAVE | PTA_XSAVEOPT - | PTA_FSGSBASE | PTA_RDRND | PTA_MOVBE | PTA_MWAITX | PTA_ADX | PTA_RDSEED - | PTA_CLZERO | PTA_CLFLUSHOPT | PTA_XSAVEC | PTA_XSAVES | PTA_SHA | PTA_LZCNT - | PTA_POPCNT; +constexpr wide_int_bitmask PTA_ZNVER1 = PTA_64BIT | PTA_MMX | PTA_SSE + | PTA_SSE2 | PTA_SSE3 | PTA_SSE4A | PTA_CX16 | PTA_POPCNT | PTA_LZCNT + | PTA_ABM | PTA_SSSE3 | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL + | PTA_AVX | PTA_AVX2 | PTA_BMI | PTA_BMI2 | PTA_F16C | PTA_FMA | PTA_PRFCHW + | PTA_FXSR | PTA_XSAVE | PTA_XSAVEOPT | PTA_FSGSBASE | PTA_RDRND | PTA_MOVBE + | PTA_MWAITX | PTA_ADX | PTA_RDSEED | PTA_CLZERO | PTA_CLFLUSHOPT + | PTA_XSAVEC | PTA_XSAVES | PTA_SHA; constexpr wide_int_bitmask PTA_ZNVER2 = PTA_ZNVER1 | PTA_CLWB | PTA_RDPID | PTA_WBNOINVD; constexpr wide_int_bitmask PTA_ZNVER3 = PTA_ZNVER2 | PTA_VAES | PTA_VPCLMULQDQ @@ -2506,19 +2506,19 @@ constexpr wide_int_bitmask PTA_ZNVER5 = PTA_ZNVER4 | PTA_AVXVNNI | PTA_MOVDIRI | PTA_MOVDIR64B | PTA_AVX512VP2INTERSECT | PTA_PREFETCHI; constexpr wide_int_bitmask PTA_BTVER1 = PTA_64BIT | PTA_MMX | PTA_SSE - | PTA_SSE2 | PTA_SSE3 | PTA_SSSE3 | PTA_SSE4A | PTA_ABM | PTA_CX16 - | PTA_PRFCHW | PTA_FXSR | PTA_XSAVE; + | PTA_SSE2 | PTA_SSE3 | PTA_SSSE3 | PTA_SSE4A | PTA_LZCNT | PTA_POPCNT + | PTA_ABM | PTA_CX16 | PTA_PRFCHW | PTA_FXSR | PTA_XSAVE; constexpr wide_int_bitmask PTA_BTVER2 = PTA_BTVER1 | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL | PTA_AVX | PTA_BMI | PTA_F16C | PTA_MOVBE | PTA_XSAVEOPT; constexpr wide_int_bitmask PTA_LUJIAZUI = PTA_64BIT | PTA_MMX | PTA_SSE - | PTA_SSE2 | PTA_SSE3 | PTA_CX16 | PTA_ABM | PTA_SSSE3 | PTA_SSE4_1 - | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL | PTA_BMI | PTA_BMI2 | PTA_PRFCHW - | PTA_FXSR | PTA_XSAVE | PTA_XSAVEOPT | PTA_FSGSBASE | PTA_RDRND | PTA_MOVBE - | PTA_ADX | PTA_RDSEED | PTA_POPCNT; + | PTA_SSE2 | PTA_SSE3 | PTA_CX16 | PTA_LZCNT | PTA_POPCNT | PTA_ABM + | PTA_SSSE3 | PTA_SSE4_1 | PTA_SSE4_2 | PTA_AES | PTA_PCLMUL | PTA_BMI + | PTA_BMI2 | PTA_PRFCHW | PTA_FXSR | PTA_XSAVE | PTA_XSAVEOPT | PTA_FSGSBASE + | PTA_RDRND | PTA_MOVBE | PTA_ADX | PTA_RDSEED; constexpr wide_int_bitmask PTA_YONGFENG = PTA_LUJIAZUI | PTA_AVX | PTA_AVX2 - | PTA_F16C | PTA_FMA | PTA_SHA | PTA_LZCNT; + | PTA_F16C | PTA_FMA | PTA_SHA; #ifndef GENERATOR_FILE diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 2b0dd66..6686f10 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -18298,17 +18298,17 @@ (any_rotate:SWI (match_operand:SWI 1 "const_int_operand") (subreg:QI - (and - (match_operand 2 "int248_register_operand") - (match_operand 3 "const_int_operand")) 0)))] + (match_operator 4 "and_operator" + [(match_operand 2 "int248_register_operand") + (match_operand 3 "const_int_operand")]) 0)))] "(INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) == GET_MODE_BITSIZE (<MODE>mode) - 1" - [(set (match_dup 4) (match_dup 1)) + [(set (match_dup 5) (match_dup 1)) (set (match_dup 0) - (any_rotate:SWI (match_dup 4) + (any_rotate:SWI (match_dup 5) (subreg:QI - (and:SI (match_dup 2) (match_dup 3)) 0)))] - "operands[4] = gen_reg_rtx (<MODE>mode);") + (match_op_dup 4 [(match_dup 2) (match_dup 3)]) 0)))] + "operands[5] = gen_reg_rtx (<MODE>mode);") (define_insn_and_split "*<insn><mode>3_mask_1" [(set (match_operand:SWI 0 "nonimmediate_operand") diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 0f31090..175798c 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1714,10 +1714,14 @@ (define_predicate "div_operator" (match_code "div")) -;; Return true if this is a and, ior or xor operation. +;; Return true if this is an and, ior or xor operation. (define_predicate "logic_operator" (match_code "and,ior,xor")) +;; Return true if this is an and operation. +(define_predicate "and_operator" + (match_code "and")) + ;; Return true if this is a plus, minus, and, ior or xor operation. (define_predicate "plusminuslogic_operator" (match_code "plus,minus,and,ior,xor")) diff --git a/gcc/config/riscv/arch-canonicalize b/gcc/config/riscv/arch-canonicalize index 34dad45..5d24f5ed 100755 --- a/gcc/config/riscv/arch-canonicalize +++ b/gcc/config/riscv/arch-canonicalize @@ -20,77 +20,314 @@ # along with GCC; see the file COPYING3. If not see # <http://www.gnu.org/licenses/>. -# TODO: Extract riscv_subset_t from riscv-common.cc and make it can be compiled -# standalone to replace this script, that also prevents us implementing -# that twice and keep sync again and again. - from __future__ import print_function import sys import argparse import collections import itertools +import re +import os from functools import reduce SUPPORTED_ISA_SPEC = ["2.2", "20190608", "20191213"] CANONICAL_ORDER = "imafdqlcbkjtpvnh" LONG_EXT_PREFIXES = ['z', 's', 'h', 'x'] +def parse_define_riscv_ext(content): + """Parse DEFINE_RISCV_EXT macros using position-based parsing.""" + extensions = [] + + # Find all DEFINE_RISCV_EXT blocks + pattern = r'DEFINE_RISCV_EXT\s*\(' + matches = [] + + pos = 0 + while True: + match = re.search(pattern, content[pos:]) + if not match: + break + + start_pos = pos + match.start() + paren_count = 0 + current_pos = pos + match.end() - 1 # Start at the opening parenthesis + + # Find the matching closing parenthesis + while current_pos < len(content): + if content[current_pos] == '(': + paren_count += 1 + elif content[current_pos] == ')': + paren_count -= 1 + if paren_count == 0: + break + current_pos += 1 + + if paren_count == 0: + # Extract the content inside parentheses + macro_content = content[pos + match.end():current_pos] + ext_data = parse_macro_arguments(macro_content) + if ext_data: + extensions.append(ext_data) + + pos = current_pos + 1 + + return extensions + +def parse_macro_arguments(macro_content): + """Parse the arguments of a DEFINE_RISCV_EXT macro.""" + # Remove comments /* ... */ + cleaned_content = re.sub(r'/\*[^*]*\*/', '', macro_content) + + # Split arguments by comma, but respect nested structures + args = [] + current_arg = "" + paren_count = 0 + brace_count = 0 + in_string = False + escape_next = False + + for char in cleaned_content: + if escape_next: + current_arg += char + escape_next = False + continue + + if char == '\\': + escape_next = True + current_arg += char + continue + + if char == '"' and not escape_next: + in_string = not in_string + current_arg += char + continue + + if in_string: + current_arg += char + continue + + if char == '(': + paren_count += 1 + elif char == ')': + paren_count -= 1 + elif char == '{': + brace_count += 1 + elif char == '}': + brace_count -= 1 + elif char == ',' and paren_count == 0 and brace_count == 0: + args.append(current_arg.strip()) + current_arg = "" + continue + + current_arg += char + + # Add the last argument + if current_arg.strip(): + args.append(current_arg.strip()) + + # We need at least 6 arguments to get DEP_EXTS (position 5) + if len(args) < 6: + return None + + ext_name = args[0].strip() + dep_exts_arg = args[5].strip() # DEP_EXTS is at position 5 + + # Parse dependency extensions from the DEP_EXTS argument + deps = parse_dep_exts(dep_exts_arg) + + return { + 'name': ext_name, + 'dep_exts': deps + } + +def parse_dep_exts(dep_exts_str): + """Parse the DEP_EXTS argument to extract dependency list with conditions.""" + # Remove outer parentheses if present + dep_exts_str = dep_exts_str.strip() + if dep_exts_str.startswith('(') and dep_exts_str.endswith(')'): + dep_exts_str = dep_exts_str[1:-1].strip() + + # Remove outer braces if present + if dep_exts_str.startswith('{') and dep_exts_str.endswith('}'): + dep_exts_str = dep_exts_str[1:-1].strip() + + if not dep_exts_str: + return [] + + deps = [] + + # First, find and process conditional dependencies + conditional_pattern = r'\{\s*"([^"]+)"\s*,\s*(\[.*?\]\s*\([^)]*\)\s*->\s*bool.*?)\}' + conditional_matches = [] + + for match in re.finditer(conditional_pattern, dep_exts_str, re.DOTALL): + ext_name = match.group(1) + condition_code = match.group(2) + deps.append({'ext': ext_name, 'type': 'conditional', 'condition': condition_code}) + conditional_matches.append((match.start(), match.end())) + + # Remove conditional dependency blocks from the string + remaining_str = dep_exts_str + for start, end in reversed(conditional_matches): # Reverse order to maintain indices + remaining_str = remaining_str[:start] + remaining_str[end:] + + # Now handle simple quoted strings in the remaining text + for match in re.finditer(r'"([^"]+)"', remaining_str): + deps.append({'ext': match.group(1), 'type': 'simple'}) + + # Remove duplicates while preserving order + seen = set() + unique_deps = [] + for dep in deps: + key = (dep['ext'], dep['type']) + if key not in seen: + seen.add(key) + unique_deps.append(dep) + + return unique_deps + +def evaluate_conditional_dependency(ext, dep, xlen, current_exts): + """Evaluate whether a conditional dependency should be included.""" + ext_name = dep['ext'] + condition = dep['condition'] + # Parse the condition based on known patterns + if ext_name == 'zcf' and ext in ['zca', 'c', 'zce']: + # zcf depends on RV32 and F extension + return xlen == 32 and 'f' in current_exts + elif ext_name == 'zcd' and ext in ['zca', 'c']: + # zcd depends on D extension + return 'd' in current_exts + elif ext_name == 'c' and ext in ['zca']: + # Special case for zca -> c conditional dependency + if xlen == 32: + if 'd' in current_exts: + return 'zcf' in current_exts and 'zcd' in current_exts + elif 'f' in current_exts: + return 'zcf' in current_exts + else: + return True + elif xlen == 64: + if 'd' in current_exts: + return 'zcd' in current_exts + else: + return True + return False + else: + # Report error for unhandled conditional dependencies + import sys + print(f"ERROR: Unhandled conditional dependency: '{ext_name}' with condition:", file=sys.stderr) + print(f" Condition code: {condition[:100]}...", file=sys.stderr) + print(f" Current context: xlen={xlen}, exts={sorted(current_exts)}", file=sys.stderr) + # For now, return False to be safe + return False + +def resolve_dependencies(arch_parts, xlen): + """Resolve all dependencies including conditional ones.""" + current_exts = set(arch_parts) + implied_deps = set() + + # Keep resolving until no new dependencies are found + changed = True + while changed: + changed = False + new_deps = set() + + for ext in current_exts | implied_deps: + if ext in IMPLIED_EXT: + for dep in IMPLIED_EXT[ext]: + if dep['type'] == 'simple': + if dep['ext'] not in current_exts and dep['ext'] not in implied_deps: + new_deps.add(dep['ext']) + changed = True + elif dep['type'] == 'conditional': + should_include = evaluate_conditional_dependency(ext, dep, xlen, current_exts | implied_deps) + if should_include: + if dep['ext'] not in current_exts and dep['ext'] not in implied_deps: + new_deps.add(dep['ext']) + changed = True + + implied_deps.update(new_deps) + + return implied_deps + +def parse_def_file(file_path, script_dir, processed_files=None, collect_all=False): + """Parse a single .def file and recursively process #include directives.""" + if processed_files is None: + processed_files = set() + + # Avoid infinite recursion + if file_path in processed_files: + return ({}, set()) if collect_all else {} + processed_files.add(file_path) + + implied_ext = {} + all_extensions = set() if collect_all else None + + if not os.path.exists(file_path): + return (implied_ext, all_extensions) if collect_all else implied_ext + + with open(file_path, 'r') as f: + content = f.read() + + # Process #include directives first + include_pattern = r'#include\s+"([^"]+)"' + includes = re.findall(include_pattern, content) + + for include_file in includes: + include_path = os.path.join(script_dir, include_file) + if collect_all: + included_ext, included_all = parse_def_file(include_path, script_dir, processed_files, collect_all) + implied_ext.update(included_ext) + all_extensions.update(included_all) + else: + included_ext = parse_def_file(include_path, script_dir, processed_files, collect_all) + implied_ext.update(included_ext) + + # Parse DEFINE_RISCV_EXT blocks using position-based parsing + parsed_exts = parse_define_riscv_ext(content) + + for ext_data in parsed_exts: + ext_name = ext_data['name'] + deps = ext_data['dep_exts'] + + if collect_all: + all_extensions.add(ext_name) + + if deps: + implied_ext[ext_name] = deps + + return (implied_ext, all_extensions) if collect_all else implied_ext + +def parse_def_files(): + """Parse RISC-V extension definition files starting from riscv-ext.def.""" + # Get directory containing this script + try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + except NameError: + # When __file__ is not defined (e.g., interactive mode) + script_dir = os.getcwd() + + # Start with the main definition file + main_def_file = os.path.join(script_dir, 'riscv-ext.def') + return parse_def_file(main_def_file, script_dir) + +def get_all_extensions(): + """Get all supported extensions and their implied extensions.""" + # Get directory containing this script + try: + script_dir = os.path.dirname(os.path.abspath(__file__)) + except NameError: + # When __file__ is not defined (e.g., interactive mode) + script_dir = os.getcwd() + + # Start with the main definition file + main_def_file = os.path.join(script_dir, 'riscv-ext.def') + return parse_def_file(main_def_file, script_dir, collect_all=True) + # # IMPLIED_EXT(ext) -> implied extension list. +# This is loaded dynamically from .def files # -IMPLIED_EXT = { - "d" : ["f", "zicsr"], - - "a" : ["zaamo", "zalrsc"], - "zabha" : ["zaamo"], - "zacas" : ["zaamo"], - - "f" : ["zicsr"], - "b" : ["zba", "zbb", "zbs"], - "zdinx" : ["zfinx", "zicsr"], - "zfinx" : ["zicsr"], - "zhinx" : ["zhinxmin", "zfinx", "zicsr"], - "zhinxmin" : ["zfinx", "zicsr"], - - "zk" : ["zkn", "zkr", "zkt"], - "zkn" : ["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"], - "zks" : ["zbkb", "zbkc", "zbkx", "zksed", "zksh"], - - "v" : ["zvl128b", "zve64d"], - "zve32x" : ["zvl32b"], - "zve64x" : ["zve32x", "zvl64b"], - "zve32f" : ["f", "zve32x"], - "zve64f" : ["f", "zve32f", "zve64x"], - "zve64d" : ["d", "zve64f"], - - "zvl64b" : ["zvl32b"], - "zvl128b" : ["zvl64b"], - "zvl256b" : ["zvl128b"], - "zvl512b" : ["zvl256b"], - "zvl1024b" : ["zvl512b"], - "zvl2048b" : ["zvl1024b"], - "zvl4096b" : ["zvl2048b"], - "zvl8192b" : ["zvl4096b"], - "zvl16384b" : ["zvl8192b"], - "zvl32768b" : ["zvl16384b"], - "zvl65536b" : ["zvl32768b"], - - "zvkn" : ["zvkned", "zvknhb", "zvkb", "zvkt"], - "zvknc" : ["zvkn", "zvbc"], - "zvkng" : ["zvkn", "zvkg"], - "zvks" : ["zvksed", "zvksh", "zvkb", "zvkt"], - "zvksc" : ["zvks", "zvbc"], - "zvksg" : ["zvks", "zvkg"], - "zvbb" : ["zvkb"], - "zvbc" : ["zve64x"], - "zvkb" : ["zve32x"], - "zvkg" : ["zve32x"], - "zvkned" : ["zve32x"], - "zvknha" : ["zve32x"], - "zvknhb" : ["zve64x"], - "zvksed" : ["zve32x"], - "zvksh" : ["zve32x"], -} +IMPLIED_EXT = parse_def_files() def arch_canonicalize(arch, isa_spec): # TODO: Support extension version. @@ -123,21 +360,31 @@ def arch_canonicalize(arch, isa_spec): long_exts += extra_long_ext # - # Handle implied extensions. + # Handle implied extensions using new conditional logic. # - any_change = True - while any_change: - any_change = False - for ext in std_exts + long_exts: - if ext in IMPLIED_EXT: - implied_exts = IMPLIED_EXT[ext] - for implied_ext in implied_exts: - if implied_ext == 'zicsr' and is_isa_spec_2p2: - continue + # Extract xlen from architecture string + # TODO: We should support profile here. + if arch.startswith('rv32'): + xlen = 32 + elif arch.startswith('rv64'): + xlen = 64 + else: + raise Exception("Unsupported prefix `%s`" % arch) - if implied_ext not in std_exts + long_exts: - long_exts.append(implied_ext) - any_change = True + # Get all current extensions + current_exts = std_exts + long_exts + + # Resolve dependencies + implied_deps = resolve_dependencies(current_exts, xlen) + + # Filter out zicsr for ISA spec 2.2 + if is_isa_spec_2p2: + implied_deps.discard('zicsr') + + # Add implied dependencies to long_exts + for dep in implied_deps: + if dep not in current_exts: + long_exts.append(dep) # Single letter extension might appear in the long_exts list, # because we just append extensions list to the arch string. @@ -179,17 +426,171 @@ def arch_canonicalize(arch, isa_spec): return new_arch -if len(sys.argv) < 2: - print ("Usage: %s <arch_str> [<arch_str>*]" % sys.argv) - sys.exit(1) +def dump_all_extensions(): + """Dump all extensions and their implied extensions.""" + implied_ext, all_extensions = get_all_extensions() -parser = argparse.ArgumentParser() -parser.add_argument('-misa-spec', type=str, - default='20191213', - choices=SUPPORTED_ISA_SPEC) -parser.add_argument('arch_strs', nargs=argparse.REMAINDER) + print("All supported RISC-V extensions:") + print("=" * 60) -args = parser.parse_args() + if not all_extensions: + print("No extensions found.") + return -for arch in args.arch_strs: - print (arch_canonicalize(arch, args.misa_spec)) + # Sort all extensions for consistent output + sorted_all = sorted(all_extensions) + + # Print all extensions with their dependencies (if any) + for ext_name in sorted_all: + if ext_name in implied_ext: + deps = implied_ext[ext_name] + dep_strs = [] + for dep in deps: + if dep['type'] == 'simple': + dep_strs.append(dep['ext']) + else: + dep_strs.append(f"{dep['ext']}*") # Mark conditional deps with * + print(f"{ext_name:15} -> {', '.join(dep_strs)}") + else: + print(f"{ext_name:15} -> (no dependencies)") + + print(f"\nTotal extensions: {len(all_extensions)}") + print(f"Extensions with dependencies: {len(implied_ext)}") + print(f"Extensions without dependencies: {len(all_extensions) - len(implied_ext)}") + +def run_unit_tests(): + """Run unit tests using pytest dynamically imported.""" + try: + import pytest + except ImportError: + print("Error: pytest is required for running unit tests.") + print("Please install pytest: pip install pytest") + return 1 + + # Define test functions + def test_basic_arch_parsing(): + """Test basic architecture string parsing.""" + result = arch_canonicalize("rv64i", "20191213") + assert result == "rv64i" + + def test_simple_extensions(): + """Test simple extension handling.""" + result = arch_canonicalize("rv64im", "20191213") + assert "zmmul" in result + + def test_implied_extensions(): + """Test implied extension resolution.""" + result = arch_canonicalize("rv64imaf", "20191213") + assert "zicsr" in result + + def test_conditional_dependencies(): + """Test conditional dependency evaluation.""" + # Test RV32 with F extension should include zcf when c is present + result = arch_canonicalize("rv32ifc", "20191213") + parts = result.split("_") + if "c" in parts: + assert "zca" in parts + if "f" in parts: + assert "zcf" in parts + + def test_parse_dep_exts(): + """Test dependency parsing function.""" + # Test simple dependency + deps = parse_dep_exts('{"ext1", "ext2"}') + assert len(deps) == 2 + assert deps[0]['ext'] == 'ext1' + assert deps[0]['type'] == 'simple' + + def test_evaluate_conditional_dependency(): + """Test conditional dependency evaluation.""" + # Test zcf condition for RV32 with F + dep = {'ext': 'zcf', 'type': 'conditional', 'condition': 'test'} + result = evaluate_conditional_dependency('zce', dep, 32, {'f'}) + assert result == True + + # Test zcf condition for RV64 with F (should be False) + result = evaluate_conditional_dependency('zce', dep, 64, {'f'}) + assert result == False + + def test_parse_define_riscv_ext(): + """Test DEFINE_RISCV_EXT parsing.""" + content = ''' + DEFINE_RISCV_EXT( + /* NAME */ test, + /* UPPERCASE_NAME */ TEST, + /* FULL_NAME */ "Test extension", + /* DESC */ "", + /* URL */ , + /* DEP_EXTS */ ({"dep1", "dep2"}), + /* SUPPORTED_VERSIONS */ ({{1, 0}}), + /* FLAG_GROUP */ test, + /* BITMASK_GROUP_ID */ 0, + /* BITMASK_BIT_POSITION*/ 0, + /* EXTRA_EXTENSION_FLAGS */ 0) + ''' + + extensions = parse_define_riscv_ext(content) + assert len(extensions) == 1 + assert extensions[0]['name'] == 'test' + assert len(extensions[0]['dep_exts']) == 2 + + # Collect test functions + test_functions = [ + test_basic_arch_parsing, + test_simple_extensions, + test_implied_extensions, + test_conditional_dependencies, + test_parse_dep_exts, + test_evaluate_conditional_dependency, + test_parse_define_riscv_ext + ] + + # Run tests manually first, then optionally with pytest + print("Running unit tests...") + + passed = 0 + failed = 0 + + for i, test_func in enumerate(test_functions): + try: + print(f" Running {test_func.__name__}...", end=" ") + test_func() + print("PASSED") + passed += 1 + except Exception as e: + print(f"FAILED: {e}") + failed += 1 + + print(f"\nTest Summary: {passed} passed, {failed} failed") + + if failed == 0: + print("\nAll tests passed!") + return 0 + else: + print(f"\n{failed} test(s) failed!") + return 1 + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-misa-spec', type=str, + default='20191213', + choices=SUPPORTED_ISA_SPEC) + parser.add_argument('--dump-all', action='store_true', + help='Dump all extensions and their implied extensions') + parser.add_argument('--selftest', action='store_true', + help='Run unit tests using pytest') + parser.add_argument('arch_strs', nargs='*', + help='Architecture strings to canonicalize') + + args = parser.parse_args() + + if args.dump_all: + dump_all_extensions() + elif args.selftest: + sys.exit(run_unit_tests()) + elif args.arch_strs: + for arch in args.arch_strs: + print (arch_canonicalize(arch, args.misa_spec)) + else: + parser.print_help() + sys.exit(1) diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 45fa521..29342d8 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -71,7 +71,7 @@ extern const char *riscv_arch_help (int argc, const char **argv); {"tune", "%{!mtune=*:" \ " %{!mcpu=*:-mtune=%(VALUE)}" \ " %{mcpu=*:-mtune=%:riscv_default_mtune(%* %(VALUE))}}" }, \ - {"arch", "%{!march=*:" \ + {"arch", "%{!march=*|march=unset:" \ " %{!mcpu=*:-march=%(VALUE)}" \ " %{mcpu=*:%:riscv_expand_arch_from_cpu(%* %(VALUE))}}" }, \ {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \ @@ -111,13 +111,19 @@ extern const char *riscv_arch_help (int argc, const char **argv); %(subtarget_asm_spec)" \ ASM_MISA_SPEC +/* Drop all -march=* options before -march=unset. */ +#define ARCH_UNSET_CLEANUP_SPECS \ + "%{march=unset:%<march=*} " \ + #undef DRIVER_SELF_SPECS #define DRIVER_SELF_SPECS \ +ARCH_UNSET_CLEANUP_SPECS \ "%{march=help:%:riscv_arch_help()} " \ "%{print-supported-extensions:%:riscv_arch_help()} " \ "%{-print-supported-extensions:%:riscv_arch_help()} " \ "%{march=*:%:riscv_expand_arch(%*)} " \ -"%{!march=*:%{mcpu=*:%:riscv_expand_arch_from_cpu(%*)}} " +"%{!march=*|march=unset:%{mcpu=*:%:riscv_expand_arch_from_cpu(%*)}} " \ +"%{march=unset:%{!mcpu=*:%eAt least one valid -mcpu option must be given after -march=unset}} " #define LOCAL_LABEL_PREFIX "." #define USER_LABEL_PREFIX "" diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 012b6db..d044f9a 100644 --- a/gcc/config/s390/s390.cc +++ b/gcc/config/s390/s390.cc @@ -9239,15 +9239,12 @@ print_operand (FILE *file, rtx x, int code) else if (code == 'h') fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((CONST_WIDE_INT_ELT (x, 0) & 0xffff) ^ 0x8000) - 0x8000); + /* Support arbitrary _BitInt constants in asm statements. */ + else if (code == 0) + output_addr_const (file, x); else - { - if (code == 0) - output_operand_lossage ("invalid constant - try using " - "an output modifier"); - else - output_operand_lossage ("invalid constant for output modifier '%c'", - code); - } + output_operand_lossage ("invalid constant for output modifier '%c'", + code); break; case CONST_VECTOR: switch (code) @@ -18768,6 +18765,27 @@ s390_c_mode_for_floating_type (enum tree_index ti) return default_mode_for_floating_type (ti); } +/* Return true if _BitInt(N) is supported and fill its details into *INFO. */ + +bool +s390_bitint_type_info (int n, struct bitint_info *info) +{ + if (!TARGET_64BIT) + return false; + if (n <= 8) + info->limb_mode = QImode; + else if (n <= 16) + info->limb_mode = HImode; + else if (n <= 32) + info->limb_mode = SImode; + else + info->limb_mode = DImode; + info->abi_limb_mode = info->limb_mode; + info->big_endian = true; + info->extended = true; + return true; +} + /* Initialize GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP @@ -19089,6 +19107,9 @@ s390_c_mode_for_floating_type (enum tree_index ti) #undef TARGET_DOCUMENTATION_NAME #define TARGET_DOCUMENTATION_NAME "S/390" +#undef TARGET_C_BITINT_TYPE_INFO +#define TARGET_C_BITINT_TYPE_INFO s390_bitint_type_info + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-s390.h" diff --git a/gcc/configure b/gcc/configure index bacdd29..cab9c75 100755 --- a/gcc/configure +++ b/gcc/configure @@ -872,7 +872,6 @@ c_strict_warn strict_warn c_loose_warn loose_warn -aliasing_flags CPP EGREP GREP @@ -7126,45 +7125,6 @@ $as_echo "#define HAVE_SWAP_IN_UTILITY 1" >>confdefs.h fi -# Check whether compiler is affected by placement new aliasing bug (PR 29286). -# If the host compiler is affected by the bug, and we build with optimization -# enabled (which happens e.g. when cross-compiling), the pool allocator may -# get miscompiled. Use -fno-strict-aliasing to work around this problem. -# Since there is no reliable feature check for the presence of this bug, -# we simply use a GCC version number check. (This should never trigger for -# stages 2 or 3 of a native bootstrap.) -aliasing_flags= -if test "$GCC" = yes; then - saved_CXXFLAGS="$CXXFLAGS" - - # The following test compilation will succeed if and only if $CXX accepts - # -fno-strict-aliasing *and* is older than GCC 4.3. - CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX is affected by placement new aliasing bug" >&5 -$as_echo_n "checking whether $CXX is affected by placement new aliasing bug... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) -#error compiler not affected by placement new aliasing bug -#endif - -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; aliasing_flags='-fno-strict-aliasing' -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - CXXFLAGS="$saved_CXXFLAGS" -fi - - - - # --------------------- # Warnings and checking # --------------------- @@ -21522,7 +21482,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21525 "configure" +#line 21485 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -21628,7 +21588,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21631 "configure" +#line 21591 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/gcc/configure.ac b/gcc/configure.ac index 2c43b38..ac1f0e9 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -563,35 +563,6 @@ if test $ac_cv_std_swap_in_utility = yes; then [Define if <utility> defines std::swap.]) fi -# Check whether compiler is affected by placement new aliasing bug (PR 29286). -# If the host compiler is affected by the bug, and we build with optimization -# enabled (which happens e.g. when cross-compiling), the pool allocator may -# get miscompiled. Use -fno-strict-aliasing to work around this problem. -# Since there is no reliable feature check for the presence of this bug, -# we simply use a GCC version number check. (This should never trigger for -# stages 2 or 3 of a native bootstrap.) -aliasing_flags= -if test "$GCC" = yes; then - saved_CXXFLAGS="$CXXFLAGS" - - # The following test compilation will succeed if and only if $CXX accepts - # -fno-strict-aliasing *and* is older than GCC 4.3. - CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" - AC_MSG_CHECKING([whether $CXX is affected by placement new aliasing bug]) - AC_COMPILE_IFELSE([AC_LANG_SOURCE([ -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) -#error compiler not affected by placement new aliasing bug -#endif -])], - [AC_MSG_RESULT([yes]); aliasing_flags='-fno-strict-aliasing'], - [AC_MSG_RESULT([no])]) - - CXXFLAGS="$saved_CXXFLAGS" -fi -AC_SUBST(aliasing_flags) - - - # --------------------- # Warnings and checking # --------------------- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3ab14f0..8e9b8ea 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,37 @@ +2025-08-06 Patrick Palka <ppalka@redhat.com> + + PR c++/121231 + PR c++/119688 + PR c++/94511 + * mangle.cc (write_expression): Write out implicit non-trailing + zeroes of a CONSTRUCTOR when the ABI version is at least 21. + +2025-08-06 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_indirect_ref): Improve diagnostic. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * parser.cc (cp_parser_omp_clause_from_to): Parse 'iterator' modifier. + * semantics.cc (finish_omp_clauses): Finish iterators for to/from + clauses. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + Andrew Stubbs <ams@baylibre.com> + + * parser.cc (cp_parser_omp_clause_map): Parse 'iterator' modifier. + * semantics.cc (finish_omp_clauses): Finish iterators. Apply + iterators to generated clauses. + +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 diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 142579a..b8ac454 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -7179,10 +7179,23 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t, (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); /* DR 1188 says we don't have to deal with this. */ if (!ctx->quiet) - error_at (cp_expr_loc_or_input_loc (t), - "accessing value of %qE through a %qT glvalue in a " - "constant expression", build_fold_indirect_ref (sub), - TREE_TYPE (t)); + { + auto_diagnostic_group d; + error_at (cp_expr_loc_or_input_loc (t), + "accessing value of %qT object through a %qT " + "glvalue in a constant expression", + TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t)); + tree ob = build_fold_indirect_ref (sub); + if (DECL_P (ob)) + { + if (DECL_ARTIFICIAL (ob)) + inform (DECL_SOURCE_LOCATION (ob), + "%qT object created here", TREE_TYPE (ob)); + else + inform (DECL_SOURCE_LOCATION (ob), + "%q#D declared here", ob); + } + } *non_constant_p = true; return t; } @@ -7452,12 +7465,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); @@ -7644,11 +7651,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); @@ -7785,6 +7795,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))) @@ -7848,11 +7860,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; @@ -7959,8 +7977,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 @@ -7973,6 +7993,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) { @@ -7997,6 +8033,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))))) @@ -8004,7 +8043,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; } @@ -11308,6 +11347,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, @@ -12131,6 +12177,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/lex.cc b/gcc/cp/lex.cc index 08a6348..b7d2ac6 100644 --- a/gcc/cp/lex.cc +++ b/gcc/cp/lex.cc @@ -368,6 +368,66 @@ cxx_init (void) cxx_init_decl_processing (); + if (warn_keyword_macro) + { + for (unsigned int i = 0; i < num_c_common_reswords; ++i) + /* For C++ none of the keywords in [lex.key] starts with underscore, + don't register anything like that. Don't complain about + ObjC or Transactional Memory keywords. */ + if (c_common_reswords[i].word[0] == '_') + continue; + else if (c_common_reswords[i].disable & (D_TRANSMEM | D_OBJC)) + continue; + else + { + tree id = get_identifier (c_common_reswords[i].word); + if (IDENTIFIER_KEYWORD_P (id) + /* Don't register keywords with spaces. */ + && IDENTIFIER_POINTER (id)[IDENTIFIER_LENGTH (id) - 1] != ' ') + cpp_lookup (parse_in, + (const unsigned char *) IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id))->flags |= NODE_WARN; + } + auto warn_on = [] (const char *name) { + cpp_lookup (parse_in, (const unsigned char *) name, + strlen (name))->flags |= NODE_WARN; + }; + if (cxx_dialect >= cxx11) + { + warn_on ("final"); + warn_on ("override"); + warn_on ("noreturn"); + if (cxx_dialect < cxx26) + warn_on ("carries_dependency"); + } + if (cxx_dialect >= cxx14) + warn_on ("deprecated"); + if (cxx_dialect >= cxx17) + { + warn_on ("fallthrough"); + warn_on ("maybe_unused"); + warn_on ("nodiscard"); + } + if (cxx_dialect >= cxx20) + { + warn_on ("likely"); + warn_on ("unlikely"); + warn_on ("no_unique_address"); + } + if (flag_modules) + { + warn_on ("import"); + warn_on ("module"); + } + if (cxx_dialect >= cxx23) + warn_on ("assume"); + if (cxx_dialect >= cxx26) + { + warn_on ("replaceable_if_eligible"); + warn_on ("trivially_relocatable_if_eligible"); + } + } + if (c_common_init () == false) { input_location = saved_loc; diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 13d5ded..fd69099 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -3745,11 +3745,59 @@ write_expression (tree expr) || !zero_init_expr_p (ce->value)) last_nonzero = i; + tree prev_field = NULL_TREE; if (undigested || last_nonzero != UINT_MAX) for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i) { if (i > last_nonzero) break; + if (!undigested && !CONSTRUCTOR_NO_CLEARING (expr) + && (TREE_CODE (etype) == RECORD_TYPE + || TREE_CODE (etype) == ARRAY_TYPE)) + { + /* Write out any implicit non-trailing zeros + (which we neglected to do before v21). */ + if (TREE_CODE (etype) == RECORD_TYPE) + { + tree field; + if (i == 0) + field = first_field (etype); + else + field = DECL_CHAIN (prev_field); + for (;;) + { + field = next_subobject_field (field); + if (field == ce->index) + break; + if (abi_check (21)) + write_expression (build_zero_cst + (TREE_TYPE (field))); + field = DECL_CHAIN (field); + } + } + else if (TREE_CODE (etype) == ARRAY_TYPE) + { + unsigned HOST_WIDE_INT j; + if (i == 0) + j = 0; + else + j = 1 + tree_to_uhwi (prev_field); + unsigned HOST_WIDE_INT k; + if (TREE_CODE (ce->index) == RANGE_EXPR) + k = tree_to_uhwi (TREE_OPERAND (ce->index, 0)); + else + k = tree_to_uhwi (ce->index); + tree zero = NULL_TREE; + for (; j < k; ++j) + if (abi_check (21)) + { + if (!zero) + zero = build_zero_cst (TREE_TYPE (etype)); + write_expression (zero); + } + } + } + if (!undigested && TREE_CODE (etype) == UNION_TYPE) { /* Express the active member as a designator. */ @@ -3794,6 +3842,9 @@ write_expression (tree expr) else for (unsigned j = 0; j < reps; ++j) write_expression (ce->value); + prev_field = ce->index; + if (prev_field && TREE_CODE (prev_field) == RANGE_EXPR) + prev_field = TREE_OPERAND (prev_field, 1); } } else 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/d/ChangeLog b/gcc/d/ChangeLog index 4fe6418..1217b5d 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,7 @@ +2025-08-06 Sam James <sam@gentoo.org> + + * Make-lang.in (ALL_DFLAGS): Don't use ALIASING_FLAGS. + 2025-07-25 David Malcolm <dmalcolm@redhat.com> * d-diagnostic.cc: Likewise. diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 2d444c9..0ddd524 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -61,7 +61,7 @@ WARN_DFLAGS = -Wall -Wdeprecated NOEXCEPTION_DFLAGS = $(filter-out -fno-rtti, $(NOEXCEPTION_FLAGS)) ALL_DFLAGS = $(DFLAGS-$@) $(GDCFLAGS) -fversion=IN_GCC $(CHECKING_DFLAGS) \ - $(PICFLAG) $(ALIASING_FLAGS) $(NOEXCEPTION_DFLAGS) $(COVERAGE_FLAGS) \ + $(PICFLAG) $(NOEXCEPTION_DFLAGS) $(COVERAGE_FLAGS) \ $(WARN_DFLAGS) DCOMPILE.base = $(GDC) -c $(ALL_DFLAGS) -o $@ diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 64c1217..7423224 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -393,7 +393,7 @@ Note binutils 2.35 or newer is required for LTO to work correctly with GNU libtool that includes doing a bootstrap with LTO enabled. @item gzip version 1.2.4 (or later) or -@itemx bzip2 version 1.0.2 (or later) +@itemx xz version 5.0 (or later) Necessary to uncompress GCC @command{tar} files when source code is obtained via HTTPS mirror sites. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 105a60d..33ae98c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -388,6 +388,7 @@ Objective-C and Objective-C++ Dialects}. -Winit-self -Winline -Wno-int-conversion -Wint-in-bool-context -Wno-int-to-pointer-cast -Wno-invalid-memory-model -Winvalid-pch -Winvalid-utf8 -Wno-unicode -Wjump-misses-init +-Wkeyword-macro -Wlarger-than=@var{byte-size} -Wleading-whitespace=@var{kind} -Wlogical-not-parentheses -Wlogical-op -Wlong-long -Wno-lto-type-mismatch -Wmain -Wmaybe-uninitialized @@ -3016,8 +3017,9 @@ Version 20, which first appeared in G++ 15, fixes manglings of lambdas in static data member initializers. Version 21, which first appeared in G++ 16, fixes unnecessary captures -in noexcept lambdas (c++/119764) and layout of a base class -with all explicitly defaulted constructors (c++/120012). +in noexcept lambdas (c++/119764), layout of a base class with all explicitly +defaulted constructors (c++/120012), and mangling of class and array +objects with implicitly zero-initialized non-trailing subobjects (c++/121231). See also @option{-Wabi}. @@ -10398,6 +10400,14 @@ Do not warn if certain built-in macros are redefined. This suppresses warnings for redefinition of @code{__TIMESTAMP__}, @code{__TIME__}, @code{__DATE__}, @code{__FILE__}, and @code{__BASE_FILE__}. +@opindex Wkeyword-macro +@opindex Wno-keyword-macro +@item -Wkeyword-macro +Warn if a keyword is defined as a macro or undefined. +For C++ identifiers with special meaning or standard attribute identifiers +are diagnosed as well. This warning is enabled by default for C++26 +if @code{-Wpedantic} and emits a pedwarn in that case. + @opindex Wfree-labels @opindex Wno-free-labels @item -Wfree-labels @r{(C and Objective-C only)} @@ -31336,7 +31346,7 @@ The default is @option{-misa-spec=20191213} unless GCC has been configured with @option{--with-isa-spec=} specifying a different default version. @opindex march -@item -march=@var{ISA-string|Profiles|Profile_ISA-string} +@item -march=@var{ISA-string|Profiles|Profile_ISA-string|help|unset} Generate code for given RISC-V ISA or Profiles or a combination of them (e.g.@: @samp{rv64im} @samp{rvi20u64} @samp{rvi20u64_zbb}). ISA strings and Profiles must be lower-case. Examples include @samp{rv64i}, @samp{rv32g}, @@ -31347,6 +31357,12 @@ at the beginning of the option, then use underline connect ISA-string (e.g.@: @option{help} (@option{-march=help}) is accepted to list all supported extensions. +@samp{-march=unset} causes the compiler to ignore any @samp{-march=@dots{}} options +that appear earlier on the command line, behaving as if the option was never +passed. This is useful for ensuring that the architecture is taken from the +@samp{-mcpu} option, and it will result in an error if no @samp{-mcpu} option +is given when @samp{-march=unset} is used. + The syntax of the ISA string is defined as follows: @table @code 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 45980d6..7e6437b 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -3105,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 @@ -8499,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); diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index b495f43..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) diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index e6c3218..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; @@ -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 4f2f4da..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 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/gengtype-lex.l b/gcc/gengtype-lex.l index e36ca5b..37e4eb0 100644 --- a/gcc/gengtype-lex.l +++ b/gcc/gengtype-lex.l @@ -21,17 +21,6 @@ along with GCC; see the file COPYING3. If not see %option noinput %{ -#ifdef HOST_GENERATOR_FILE -#include "config.h" -#define GENERATOR_FILE 1 -#else -#include "bconfig.h" -#endif -#include "system.h" - -#define malloc xmalloc -#define realloc xrealloc - #include "gengtype.h" #define YY_DECL int yylex (const char **yylval) diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index 8fb7a60..1e434ce 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -76,7 +76,7 @@ enum bitint_prec_kind { /* Caches to speed up bitint_precision_kind. */ static int small_max_prec, mid_min_prec, large_min_prec, huge_min_prec; -static int limb_prec; +static int limb_prec, abi_limb_prec; static bool bitint_big_endian, bitint_extended; /* Categorize _BitInt(PREC) as small, middle, large or huge. */ @@ -109,6 +109,9 @@ bitint_precision_kind (int prec) large_min_prec = MAX_FIXED_MODE_SIZE + 1; if (!limb_prec) limb_prec = GET_MODE_PRECISION (limb_mode); + if (!abi_limb_prec) + abi_limb_prec + = GET_MODE_PRECISION (as_a <scalar_int_mode> (info.abi_limb_mode)); if (!huge_min_prec) { if (4 * limb_prec >= MAX_FIXED_MODE_SIZE) @@ -429,7 +432,7 @@ struct bitint_large_huge void insert_before (gimple *); tree limb_access_type (tree, tree); - tree limb_access (tree, tree, tree, bool); + tree limb_access (tree, tree, tree, bool, bool = false); tree build_bit_field_ref (tree, tree, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT); void if_then (gimple *, profile_probability, edge &, edge &); @@ -610,11 +613,14 @@ bitint_large_huge::limb_access_type (tree type, tree idx) TYPE. If WRITE_P is true, it will be a store, otherwise a read. */ tree -bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) +bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p, + bool abi_load_p) { tree atype = (tree_fits_uhwi_p (idx) ? limb_access_type (type, idx) : m_limb_type); - tree ltype = m_limb_type; + + tree ltype = (bitint_extended && abi_load_p) ? atype : m_limb_type; + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (var)); if (as != TYPE_ADDR_SPACE (ltype)) ltype = build_qualified_type (ltype, TYPE_QUALS (ltype) @@ -651,12 +657,21 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) { unsigned HOST_WIDE_INT nelts = CEIL (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var))), limb_prec); - tree atype = build_array_type_nelts (ltype, nelts); + + /* Build the array type with m_limb_type from the right address + space. */ + tree limb_type_a = m_limb_type; + if (as != TYPE_ADDR_SPACE (m_limb_type)) + limb_type_a = build_qualified_type (m_limb_type, + TYPE_QUALS (m_limb_type) + | ENCODE_QUAL_ADDR_SPACE (as)); + + tree atype = build_array_type_nelts (limb_type_a, nelts); var = build1 (VIEW_CONVERT_EXPR, atype, var); } ret = build4 (ARRAY_REF, ltype, var, idx, NULL_TREE, NULL_TREE); } - if (!write_p && !useless_type_conversion_p (atype, m_limb_type)) + if (!write_p && !useless_type_conversion_p (atype, ltype)) { gimple *g = gimple_build_assign (make_ssa_name (m_limb_type), ret); insert_before (g); @@ -1964,6 +1979,7 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs_type = TREE_TYPE (rhs1); bool eh = stmt_ends_bb_p (stmt); + bool load_bitfield_p = false; edge eh_edge = NULL; gimple *g; @@ -1987,12 +2003,18 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) if (!bitint_big_endian && DECL_OFFSET_ALIGN (fld) >= TYPE_ALIGN (TREE_TYPE (rhs1)) && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % limb_prec) == 0) - goto normal_load; + { + load_bitfield_p = true; + goto normal_load; + } /* Even if DECL_FIELD_BIT_OFFSET (fld) is a multiple of BITS_PER_UNIT, handle it normally for now. */ if (!bitint_big_endian && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % BITS_PER_UNIT) == 0) - goto normal_load; + { + load_bitfield_p = true; + goto normal_load; + } tree repr = DECL_BIT_FIELD_REPRESENTATIVE (fld); poly_int64 bitoffset; poly_uint64 field_offset, repr_offset; @@ -2241,7 +2263,7 @@ normal_load: /* Use write_p = true for loads with EH edges to make sure limb_access doesn't add a cast as separate statement after it. */ - rhs1 = limb_access (rhs_type, rhs1, idx, eh); + rhs1 = limb_access (rhs_type, rhs1, idx, eh, !load_bitfield_p); tree ret = make_ssa_name (TREE_TYPE (rhs1)); g = gimple_build_assign (ret, rhs1); insert_before (g); @@ -2373,7 +2395,7 @@ range_to_prec (tree op, gimple *stmt) from that precision, if it is negative, the operand is sign-extended from -*PREC. If PREC_STORED is NULL, it is the toplevel call, otherwise *PREC_STORED is prec from the innermost call without - range optimizations. */ + range optimizations (0 for uninitialized SSA_NAME). */ tree bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, @@ -2481,7 +2503,7 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, *prec = TYPE_UNSIGNED (TREE_TYPE (op)) ? limb_prec : -limb_prec; precs = *prec; if (prec_stored) - *prec_stored = precs; + *prec_stored = 0; tree var = create_tmp_var (m_limb_type); TREE_ADDRESSABLE (var) = 1; ret = build_fold_addr_expr (var); @@ -2510,6 +2532,13 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, int prec_stored_val = 0; ret = handle_operand_addr (rhs1, g, &prec_stored_val, prec); precs = prec_stored_val; + if (prec_stored) + *prec_stored = prec_stored_val; + if (precs == 0) + { + gcc_assert (*prec == limb_prec || *prec == -limb_prec); + precs = *prec; + } if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (rhs_type)) { if (TYPE_UNSIGNED (lhs_type) @@ -2518,7 +2547,9 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, } else { - if (*prec > 0 && *prec < TYPE_PRECISION (lhs_type)) + if (prec_stored_val == 0) + /* Non-widening cast of uninitialized value. */; + else if (*prec > 0 && *prec < TYPE_PRECISION (lhs_type)) ; else if (TYPE_UNSIGNED (lhs_type)) { @@ -3150,6 +3181,17 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, { tree l = limb_access (nlhs ? NULL_TREE : lhs_type, nlhs ? nlhs : lhs, idx, true); + + if (bitint_extended + && sext + && TYPE_UNSIGNED (lhs_type) + && tree_fits_uhwi_p (idx) + && !nlhs) + { + rhs1 = add_cast (limb_access_type (lhs_type, idx), rhs1); + rhs1 = add_cast (TREE_TYPE (l), rhs1); + } + g = gimple_build_assign (l, rhs1); } insert_before (g); @@ -6669,7 +6711,7 @@ static unsigned int gimple_lower_bitint (void) { small_max_prec = mid_min_prec = large_min_prec = huge_min_prec = 0; - limb_prec = 0; + limb_prec = abi_limb_prec = 0; bitint_big_endian = false; unsigned int i; @@ -7631,7 +7673,20 @@ gimple_lower_bitint (void) from smaller number. */ min_prec = prec; else - min_prec = CEIL (min_prec, limb_prec) * limb_prec; + { + min_prec = CEIL (min_prec, limb_prec) * limb_prec; + if (min_prec > (unsigned) limb_prec + && abi_limb_prec > limb_prec) + { + /* For targets with ABI limb precision higher than + limb precision round to ABI limb precision, + otherwise c can contain padding bits. */ + min_prec + = CEIL (min_prec, abi_limb_prec) * abi_limb_prec; + if (min_prec > prec - rem - 2 * limb_prec) + min_prec = prec; + } + } if (min_prec == 0) c = NULL_TREE; else if (min_prec == prec) 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.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/match.pd b/gcc/match.pd index 82e6e29..06a4a91 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5508,16 +5508,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (convert @0))) /* Strip inner integral conversions that do not change precision or size, or - zero-extend while keeping the same size (for bool-to-char). */ + zero-extend while keeping the same size (for bool-to-char). + However, keep this conversion if the result is an extended _BitInt, + since it may rely on this conversion to extend properly. */ + (simplify (view_convert (convert@0 @1)) + (with { + bool extended_bitint = false; + if (BITINT_TYPE_P (TREE_TYPE (@0))) + { + struct bitint_info info; + extended_bitint + = targetm.c.bitint_type_info (TYPE_PRECISION (TREE_TYPE (@0)), + &info); + extended_bitint = extended_bitint && info.extended; + } + } (if ((INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0))) && (INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1))) + && !extended_bitint && TYPE_SIZE (TREE_TYPE (@0)) == TYPE_SIZE (TREE_TYPE (@1)) && (TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)) || (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1)) && TYPE_UNSIGNED (TREE_TYPE (@1))))) - (view_convert @1))) + (view_convert @1)))) /* Simplify a view-converted empty or single-element constructor. */ (simplify 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/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 399271a..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 \ @@ -203,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 \ @@ -236,12 +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 7f8571a..0000000 --- a/gcc/rust/ast/rust-ast-builder-type.cc +++ /dev/null @@ -1,166 +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 fbc8f27..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 { @@ -490,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) { @@ -531,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> @@ -555,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) { @@ -565,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)); @@ -695,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)); @@ -703,20 +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)); - } + 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 a5115b68..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); @@ -272,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); @@ -289,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 = {}); @@ -302,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 b0e06ab..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" @@ -839,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 @@ -870,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 @@ -1272,7 +1274,13 @@ TokenCollector::visit (BlockExpr &expr) void TokenCollector::visit (AnonConst &expr) { - visit (expr.get_inner_expr ()); + if (!expr.is_deferred ()) + { + visit (expr.get_inner_expr ()); + return; + } + + push (Rust::Token::make_string (expr.get_locus (), "_")); } void @@ -1371,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 ())); @@ -2485,7 +2500,7 @@ TokenCollector::visit (IdentifierPattern &pattern) if (pattern.has_subpattern ()) { push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION)); - visit (pattern.get_pattern_to_bind ()); + visit (pattern.get_subpattern ()); } } @@ -2703,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)); } @@ -2974,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 cec2365..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); @@ -289,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); @@ -377,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); @@ -402,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-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index b410f3a..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; @@ -128,6 +128,7 @@ class RangeFullExpr; class RangeFromToInclExpr; class RangeToInclExpr; class ReturnExpr; +class TryExpr; class UnsafeBlockExpr; class LoopLabel; class BaseLoopExpr; @@ -247,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 02f4f16..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,8 +450,13 @@ 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 ()); } @@ -464,7 +470,8 @@ DefaultASTVisitor::visit (AST::ConstBlock &expr) void DefaultASTVisitor::visit (AST::AnonConst &expr) { - visit (expr.get_inner_expr ()); + if (!expr.is_deferred ()) + visit (expr.get_inner_expr ()); } void @@ -550,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); @@ -594,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 ()); } @@ -942,7 +959,7 @@ DefaultASTVisitor::visit (AST::EnumItem &item) void DefaultASTVisitor::visit (AST::EnumItemTuple &item) { - DefaultASTVisitor::visit (reinterpret_cast<EnumItem &> (item)); + DefaultASTVisitor::visit (static_cast<EnumItem &> (item)); for (auto &field : item.get_tuple_fields ()) visit (field); } @@ -950,7 +967,7 @@ DefaultASTVisitor::visit (AST::EnumItemTuple &item) void DefaultASTVisitor::visit (AST::EnumItemStruct &item) { - DefaultASTVisitor::visit (reinterpret_cast<EnumItem &> (item)); + DefaultASTVisitor::visit (static_cast<EnumItem &> (item)); for (auto &field : item.get_struct_fields ()) visit (field); } @@ -958,7 +975,7 @@ DefaultASTVisitor::visit (AST::EnumItemStruct &item) void DefaultASTVisitor::visit (AST::EnumItemDiscriminant &item) { - DefaultASTVisitor::visit (reinterpret_cast<EnumItem &> (item)); + DefaultASTVisitor::visit (static_cast<EnumItem &> (item)); visit (item.get_expr ()); } @@ -1200,7 +1217,7 @@ void DefaultASTVisitor::visit (AST::IdentifierPattern &pattern) { if (pattern.has_subpattern ()) - visit (pattern.get_pattern_to_bind ()); + visit (pattern.get_subpattern ()); } void @@ -1330,13 +1347,28 @@ DefaultASTVisitor::visit (AST::GroupedPattern &pattern) } void -DefaultASTVisitor::visit (AST::SlicePattern &pattern) +DefaultASTVisitor::visit (AST::SlicePatternItemsNoRest &items) { - for (auto &item : pattern.get_items ()) + for (auto &item : items.get_patterns ()) visit (item); } void +DefaultASTVisitor::visit (AST::SlicePatternItemsHasRest &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 ()) @@ -1474,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 22fd98b..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; @@ -116,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; @@ -211,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; @@ -237,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 }; @@ -266,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; @@ -307,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; @@ -383,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; @@ -406,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 916829f..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 @@ -287,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: @@ -1280,7 +1281,14 @@ BlockExpr::as_string () const std::string AnonConst::as_string () const { - return "AnonConst: " + expr->as_string (); + std::string str = "AnonConst: "; + + if (kind == AnonConst::Kind::DeferredInference) + str += "_"; + else + str += expr.value ()->as_string (); + + return str; } std::string @@ -1637,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 (); @@ -2754,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 @@ -3495,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: @@ -3522,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 @@ -3573,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 (); } @@ -3661,15 +3691,15 @@ 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: { @@ -3681,31 +3711,26 @@ AttributeParser::parse_path_meta_item () } case EQUAL: { - skip_token (); + 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; } } @@ -3715,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; } @@ -3772,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 @@ -4104,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>> @@ -4195,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))); } @@ -4299,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 @@ -4365,7 +4284,7 @@ MetaItemLitExpr::accept_vis (ASTVisitor &vis) } void -MetaItemPathLit::accept_vis (ASTVisitor &vis) +MetaItemPathExpr::accept_vis (ASTVisitor &vis) { vis.visit (*this); } @@ -4605,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); @@ -5042,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 { @@ -5049,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 { @@ -5093,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 cd586c6..2d2c5d0 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -83,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 { @@ -251,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 (); } @@ -1040,7 +1073,7 @@ public: Path, Word, NameValueStr, - PathLit, + PathExpr, Seq, ListPaths, ListNameValueStr, @@ -1058,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; @@ -1275,6 +1308,7 @@ public: LlvmInlineAsm, Identifier, FormatArgs, + OffsetOf, MacroInvocation, Borrow, Dereference, @@ -1286,6 +1320,7 @@ public: TypeCast, Assignment, CompoundAssignment, + Try, }; virtual Kind get_expr_kind () const = 0; @@ -1480,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 () {} @@ -1498,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; @@ -1518,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; @@ -1552,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; } @@ -1560,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; @@ -1625,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-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 8f44d58..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 (); } @@ -1248,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? @@ -1474,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? @@ -1494,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)), @@ -1545,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; } @@ -1777,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 () { @@ -1974,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; @@ -1987,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), @@ -2025,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; } @@ -2086,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: @@ -2095,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)), @@ -2152,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 () @@ -2192,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: @@ -2200,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)), @@ -2256,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 () @@ -2587,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; @@ -2603,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, @@ -2682,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 () @@ -2751,24 +2775,42 @@ 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), expr (std::move (expr)) + : ExprWithBlock (), locus (locus), kind (Kind::Explicit), + expr (std::move (expr)) { - rust_assert (this->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; - expr = other.expr->clone_expr (); + 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; - expr = other.expr->clone_expr (); + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); return *this; } @@ -2778,7 +2820,13 @@ public: Expr::Kind get_expr_kind () const override { return Expr::Kind::ConstExpr; } location_t get_locus () const override { return locus; } - Expr &get_inner_expr () { return *expr; } + + 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 @@ -2799,9 +2847,12 @@ public: void accept_vis (ASTVisitor &vis) override; + bool is_deferred () const { return kind == Kind::DeferredInference; } + private: location_t locus; - std::unique_ptr<Expr> expr; + Kind kind; + tl::optional<std::unique_ptr<Expr>> expr; AnonConst *clone_expr_with_block_impl () const override { @@ -3694,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; @@ -3969,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, @@ -4030,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; } @@ -4317,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; @@ -4325,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)), @@ -4419,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; } @@ -4463,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)) @@ -4520,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 @@ -4533,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)), @@ -4585,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; @@ -4607,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; } 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-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.h b/gcc/rust/ast/rust-path.h index 11f7248..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), @@ -1145,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 @@ -1436,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 62bf6f2..15ab0b7 100644 --- a/gcc/rust/ast/rust-pattern.cc +++ b/gcc/rust/ast/rust-pattern.cc @@ -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 195a08f..4945ec4 100644 --- a/gcc/rust/ast/rust-pattern.h +++ b/gcc/rust/ast/rust-pattern.h @@ -137,8 +137,7 @@ 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_subpattern ()); return *subpattern; @@ -949,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; @@ -1522,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; } @@ -1569,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 6c0652a..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 { @@ -106,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 @@ -127,6 +134,10 @@ protected: { return new ImplTraitType (*this); } + ImplTraitType *reconstruct_impl () const override + { + return new ImplTraitType (reconstruct_vec (type_param_bounds), locus); + } public: ImplTraitType ( @@ -136,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) @@ -191,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 ( @@ -202,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) @@ -258,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 @@ -338,6 +359,10 @@ public: { return new ImplTraitTypeOneBound (*this); } + TypeNoBounds *reconstruct_impl () const override + { + return new ImplTraitTypeOneBound (trait_bound->reconstruct (), locus); + } }; /* A trait object with a single trait bound. The "trait bound" is really just @@ -355,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, @@ -448,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 @@ -464,6 +497,10 @@ protected: { return new NeverType (*this); } + NeverType *reconstruct_impl () const override + { + return new NeverType (locus); + } public: NeverType (location_t locus) : locus (locus) {} @@ -544,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 @@ -622,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; } @@ -671,17 +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; } - // Additional getter for direct access to the size expr unique_ptr - std::unique_ptr<Expr> &get_size_ptr () { return size; } - protected: /* Use covariance to implement clone function as returning this object rather * than base */ @@ -689,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 @@ -739,12 +793,16 @@ public: 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 @@ -755,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) {} @@ -980,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); @@ -999,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 84c4bcd..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); @@ -689,7 +712,7 @@ HIRCompileBase::compile_function ( 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); @@ -807,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.h b/gcc/rust/backend/rust-compile-block.h index 90515f6..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 { @@ -103,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) @@ -192,6 +194,7 @@ 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: diff --git a/gcc/rust/backend/rust-compile-context.cc b/gcc/rust/backend/rust-compile-context.cc index 284a5aa..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 (); 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 d8ddab5..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" @@ -32,7 +34,9 @@ #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 { @@ -376,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; @@ -484,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); @@ -682,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)) { @@ -689,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); @@ -714,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); @@ -756,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); @@ -800,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 (), @@ -862,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 (), @@ -1143,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); @@ -1338,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 @@ -2489,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 bc347bf..b8b4e8d 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -72,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 f9172c5..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.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.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 7627620..450a869 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -437,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); @@ -643,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); @@ -1079,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); @@ -1144,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 3e7ea9a..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.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,23 +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.to_canonical_path (mappings.get_nodeid ()); - } - 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 @@ -209,24 +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 (); - - canonical_path - = nr_ctx.to_canonical_path (function.get_mappings ().get_nodeid ()); - } - else - { - auto path = ctx->get_mappings ().lookup_canonical_path ( - function.get_mappings ().get_nodeid ()); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - 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); @@ -297,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 e19aa67..fe65921 100644 --- a/gcc/rust/backend/rust-compile-pattern.cc +++ b/gcc/rust/backend/rust-compile-pattern.cc @@ -369,31 +369,55 @@ CompilePatternCheckExpr::visit (HIR::TupleStructPattern &pattern) 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; } } @@ -406,8 +430,50 @@ CompilePatternCheckExpr::visit (HIR::TuplePattern &pattern) { case HIR::TuplePatternItems::RANGED: { - // TODO - gcc_unreachable (); + 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; @@ -448,6 +514,85 @@ CompilePatternCheckExpr::visit (HIR::IdentifierPattern &pattern) } } +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 @@ -666,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 (), @@ -765,6 +916,60 @@ CompilePatternBindings::visit (HIR::TuplePattern &pattern) } } +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 diff --git a/gcc/rust/backend/rust-compile-pattern.h b/gcc/rust/backend/rust-compile-pattern.h index 4dd7d55..233799e 100644 --- a/gcc/rust/backend/rust-compile-pattern.h +++ b/gcc/rust/backend/rust-compile-pattern.h @@ -46,6 +46,7 @@ public: 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::WildcardPattern &) override @@ -55,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), @@ -95,6 +95,7 @@ public: 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 {} @@ -102,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 7e56a0f..0622954 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -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; @@ -463,22 +476,8 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type) { tree element_type = TyTyResolveCompile::compile (ctx, type.get_element_type ()); - - 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); + TyTy::ConstType *const_capacity = type.get_capacity (); + tree folded_capacity_expr = const_capacity->get_value (); // build_index_type takes the maximum index, which is one less than // the length. 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/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc index 0799a4e..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 @@ -331,6 +331,10 @@ ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr) {} void +ExprStmtBuilder::visit (HIR::OffsetOf &expr) +{} + +void ExprStmtBuilder::visit (HIR::MethodCallExpr &expr) {} 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 45d3d58..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" @@ -103,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-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h index a5ec569..9108009 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h @@ -216,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-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h index 2e11f63..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 { @@ -156,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-fact-collector.h b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h index e3a1247..4462d77 100644 --- a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h +++ b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h @@ -824,6 +824,7 @@ protected: // Subset helpers. case TyTy::PLACEHOLDER: case TyTy::INFER: case TyTy::PARAM: + case TyTy::CONST: case TyTy::OPAQUE: rust_unreachable (); } @@ -883,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 14f1dd6..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)); } @@ -493,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-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h index 860915e..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" @@ -126,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-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc index e8a6792..4af9639 100644 --- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -277,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; } @@ -314,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 (), diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h index 07eebf6..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" @@ -128,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/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc index 5cbab3d..c40f9db 100644 --- a/gcc/rust/checks/errors/rust-const-checker.cc +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -561,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 2239874..eb63095 100644 --- a/gcc/rust/checks/errors/rust-const-checker.h +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -135,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 ec22a0e..2566971 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc @@ -439,6 +439,10 @@ PatternChecker::visit (LlvmInlineAsm &expr) {} void +PatternChecker::visit (OffsetOf &expr) +{} + +void PatternChecker::visit (TypeParam &) {} diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h index 5766180..dd44abc 100644 --- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h +++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h @@ -109,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 d90088f..405c59b 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.cc +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -694,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 8a9830f..dc3b482 100644 --- a/gcc/rust/checks/errors/rust-unsafe-checker.h +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -117,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 0db6122..58d8071 100644 --- a/gcc/rust/expand/rust-cfg-strip.cc +++ b/gcc/rust/expand/rust-cfg-strip.cc @@ -1765,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 @@ -2267,7 +2268,7 @@ CfgStrip::visit (AST::IdentifierPattern &pattern) 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"); @@ -2477,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-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-default.cc b/gcc/rust/expand/rust-derive-default.cc index 1b497b5..26ee546 100644 --- a/gcc/rust/expand/rust-derive-default.cc +++ b/gcc/rust/expand/rust-derive-default.cc @@ -98,7 +98,7 @@ DeriveDefault::visit_struct (StructStruct &item) for (auto &field : item.get_fields ()) { auto name = field.get_field_name ().as_string (); - auto type = Builder::new_type (field.get_field_type ()); + auto type = field.get_field_type ().reconstruct (); auto expr = default_call (std::move (type)); cloned_fields.emplace_back ( @@ -120,7 +120,7 @@ DeriveDefault::visit_tuple (TupleStruct &tuple_item) for (auto &field : tuple_item.get_fields ()) { - auto type = Builder::new_type (field.get_field_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 9765127..7da137f 100644 --- a/gcc/rust/expand/rust-derive-eq.cc +++ b/gcc/rust/expand/rust-derive-eq.cc @@ -142,10 +142,7 @@ DeriveEq::visit_tuple (TupleStruct &item) auto types = std::vector<std::unique_ptr<Type>> (); for (auto &field : item.get_fields ()) - { - auto type = Builder::new_type (field.get_field_type ()); - types.emplace_back (std::move (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 (), @@ -158,10 +155,7 @@ DeriveEq::visit_struct (StructStruct &item) auto types = std::vector<std::unique_ptr<Type>> (); for (auto &field : item.get_fields ()) - { - auto type = Builder::new_type (field.get_field_type ()); - types.emplace_back (std::move (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 (), @@ -186,10 +180,7 @@ DeriveEq::visit_enum (Enum &item) auto &tuple = static_cast<EnumItemTuple &> (*variant); for (auto &field : tuple.get_tuple_fields ()) - { - auto type = Builder::new_type (field.get_field_type ()); - types.emplace_back (std::move (type)); - } + types.emplace_back (field.get_field_type ().reconstruct ()); break; } case EnumItem::Kind::Struct: @@ -197,10 +188,7 @@ DeriveEq::visit_enum (Enum &item) auto &tuple = static_cast<EnumItemStruct &> (*variant); for (auto &field : tuple.get_struct_fields ()) - { - auto type = Builder::new_type (field.get_field_type ()); - types.emplace_back (std::move (type)); - } + types.emplace_back (field.get_field_type ().reconstruct ()); break; } @@ -218,10 +206,7 @@ DeriveEq::visit_union (Union &item) auto types = std::vector<std::unique_ptr<Type>> (); for (auto &field : item.get_variants ()) - { - auto type = Builder::new_type (field.get_field_type ()); - types.emplace_back (std::move (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-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-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 22368bc..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> (); + auto fields = SelfOther::indexes (builder, item.get_fields ()); - for (size_t idx = 0; idx < item.get_fields ().size (); idx++) - fields.emplace_back (tuple_indexes (idx)); - - 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> (); - - for (auto &field : item.get_fields ()) - fields.emplace_back ( - field_acccesses (field.get_field_name ().as_string ())); + auto fields = SelfOther::fields (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 ()); @@ -295,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: - cases.emplace_back ( - match_enum_struct (variant_path, - static_cast<EnumItemStruct &> (*variant))); + 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 12d793d..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 { @@ -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,6 +61,9 @@ private: MatchCase match_enum_struct (PathInExpression variant_path, const EnumItemStruct &variant); + 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; diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc index 0e8a67c..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 (); }; } @@ -106,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)); @@ -117,16 +120,18 @@ DeriveVisitor::setup_impl_generics ( case GenericParam::Kind::Const: { - rust_unreachable (); + 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 ff4f427..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{}; @@ -159,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{}; @@ -230,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{}; @@ -253,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-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc index ba7bac1..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 @@ -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 b82040c..845e10c 100644 --- a/gcc/rust/expand/rust-expand-visitor.h +++ b/gcc/rust/expand/rust-expand-visitor.h @@ -105,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); @@ -121,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 ();) { @@ -138,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)); @@ -209,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 850c8dd..61222db 100644 --- a/gcc/rust/expand/rust-macro-builtins-asm.cc +++ b/gcc/rust/expand/rust-macro-builtins-asm.cc @@ -384,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")) { @@ -401,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; @@ -414,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: @@ -432,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 // } @@ -819,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"); @@ -923,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-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-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 475ad56..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) 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 5b35052..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 &) @@ -251,12 +272,6 @@ void ASTLoweringBase::visit (AST::WhileLoopExpr &) {} void -ASTLoweringBase::visit (AST::WhileLetLoopExpr &) -{} -void -ASTLoweringBase::visit (AST::ForLoopExpr &) -{} -void ASTLoweringBase::visit (AST::IfExpr &) {} void @@ -480,6 +495,12 @@ void ASTLoweringBase::visit (AST::GroupedPattern &) {} void +ASTLoweringBase::visit (AST::SlicePatternItemsNoRest &) +{} +void +ASTLoweringBase::visit (AST::SlicePatternItemsHasRest &) +{} +void ASTLoweringBase::visit (AST::SlicePattern &) {} void @@ -557,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) diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h index 51912be..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; @@ -147,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; @@ -233,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; @@ -261,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 3f3d600..4ed51d9 100644 --- a/gcc/rust/hir/rust-ast-lower-expr.cc +++ b/gcc/rust/hir/rust-ast-lower-expr.cc @@ -24,6 +24,7 @@ #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" @@ -130,17 +131,24 @@ ASTLoweringExpr::visit (AST::BlockExpr &expr) void ASTLoweringExpr::visit (AST::AnonConst &expr) { - auto inner_expr = ASTLoweringExpr::translate (expr.get_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::AnonConst (std::move (mapping), - std::unique_ptr<Expr> (inner_expr), - expr.get_locus ()); + 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 @@ -627,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; @@ -1048,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 9d1bf68..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 { @@ -110,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; @@ -126,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-implitem.cc b/gcc/rust/hir/rust-ast-lower-implitem.cc index fc9fe1a..5db11cb 100644 --- a/gcc/rust/hir/rust-ast-lower-implitem.cc +++ b/gcc/rust/hir/rust-ast-lower-implitem.cc @@ -275,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 (), @@ -301,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 acec008..4e5a747 100644 --- a/gcc/rust/hir/rust-ast-lower-item.cc +++ b/gcc/rust/hir/rust-ast-lower-item.cc @@ -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 (), @@ -732,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 9baf81d..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) @@ -53,7 +55,7 @@ ASTLoweringPattern::visit (AST::IdentifierPattern &pattern) if (pattern.has_subpattern ()) { subpattern = std::unique_ptr<Pattern> ( - ASTLoweringPattern::translate (pattern.get_pattern_to_bind ())); + ASTLoweringPattern::translate (pattern.get_subpattern ())); } translated = new HIR::IdentifierPattern (mapping, pattern.get_ident (), @@ -321,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.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-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc index 38079c7..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. @@ -1302,7 +1302,10 @@ Dump::visit (AnonConst &e) begin ("AnonConst"); do_expr (e); - visit_field ("inner", e.get_inner_expr ()); + if (e.is_deferred ()) + put_field ("inner", "_"); + else + visit_field ("inner", e.get_inner_expr ()); end ("AnonConst"); } @@ -1529,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"); @@ -1926,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"); } @@ -2196,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"); } @@ -2314,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 8c39f48..3e6ae30 100644 --- a/gcc/rust/hir/rust-hir-dump.h +++ b/gcc/rust/hir/rust-hir-dump.h @@ -169,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; diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h index 8272a828..371daa8 100644 --- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h +++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h @@ -74,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 93dcec2..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" @@ -793,22 +795,33 @@ BlockExpr::operator= (BlockExpr const &other) AnonConst::AnonConst (Analysis::NodeMapping mappings, std::unique_ptr<Expr> &&expr, location_t locus) : ExprWithBlock (std::move (mappings), {}), locus (locus), - expr (std::move (expr)) + kind (Kind::Explicit), expr (std::move (expr)) { - rust_assert (this->expr); + rust_assert (this->expr.value ()); } -AnonConst::AnonConst (const AnonConst &other) - : ExprWithBlock (other), locus (other.locus), expr (other.expr->clone_expr ()) +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; - expr = other.expr->clone_expr (); + kind = other.kind; + + if (other.expr) + expr = other.expr.value ()->clone_expr (); return *this; } @@ -1321,37 +1334,40 @@ 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 ()) {} InlineAsmOperand::In::In ( @@ -1510,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 bf278d6..61e3590 100644 --- a/gcc/rust/hir/tree/rust-hir-expr.h +++ b/gcc/rust/hir/tree/rust-hir-expr.h @@ -27,6 +27,7 @@ #include "rust-hir-attrs.h" #include "rust-expr.h" #include "rust-hir-map.h" +#include "rust-mapping-common.h" namespace Rust { namespace HIR { @@ -1805,8 +1806,16 @@ 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); @@ -1821,12 +1830,25 @@ public: } location_t get_locus () const override { return locus; } - Expr &get_inner_expr () { return *expr; } - const Expr &get_inner_expr () const { return *expr; } + + 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; - std::unique_ptr<Expr> expr; + Kind kind; + tl::optional<std::unique_ptr<Expr>> expr; AnonConst *clone_expr_with_block_impl () const override { @@ -2698,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 @@ -2890,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 @@ -2897,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; }; @@ -3047,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; @@ -3092,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 @@ -3145,7 +3208,7 @@ 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; } @@ -3173,6 +3236,42 @@ public: 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 2905117..57b3a4d 100644 --- a/gcc/rust/hir/tree/rust-hir-full-decls.h +++ b/gcc/rust/hir/tree/rust-hir-full-decls.h @@ -128,6 +128,7 @@ class InlineAsmRegClass; 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.h b/gcc/rust/hir/tree/rust-hir-item.h index d610277..d9df602 100644 --- a/gcc/rust/hir/tree/rust-hir-item.h +++ b/gcc/rust/hir/tree/rust-hir-item.h @@ -209,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; } @@ -402,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; } @@ -1797,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-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 43f00dd..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 { @@ -87,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; @@ -155,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: @@ -226,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 {} @@ -449,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 dc94fb5..a802e8c 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -1055,7 +1055,10 @@ AnonConst::as_string () const std::string istr = indent_spaces (enter); std::string str = istr + "AnonConst:\n" + istr; - str += get_inner_expr ().as_string (); + if (expr.has_value ()) + str += get_inner_expr ().as_string (); + else + str += "_"; str += "\n" + indent_spaces (out); 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/parse/rust-parse-impl-lexer.cc b/gcc/rust/parse/rust-parse-impl-lexer.cc new file mode 100644 index 0000000..fec91e8 --- /dev/null +++ b/gcc/rust/parse/rust-parse-impl-lexer.cc @@ -0,0 +1,25 @@ +// 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" + +namespace Rust { + +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 9c9208f..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" @@ -654,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 ()) @@ -685,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 ()); } @@ -2807,58 +2809,10 @@ 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: { // rebind UseTree type @@ -2899,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", @@ -3363,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 () @@ -3381,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; @@ -5604,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 @@ -5803,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 @@ -7264,6 +7277,27 @@ 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> @@ -7568,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> @@ -9812,8 +9874,9 @@ Parser<ManagedTokenSource>::parse_slice_or_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"); @@ -9828,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 @@ -10900,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) @@ -10931,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) @@ -10941,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 (); } @@ -10951,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 @@ -11808,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)); } @@ -12506,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 ()); diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 4fab60f..8253885 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -34,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, @@ -166,6 +173,8 @@ 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); @@ -227,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 (); @@ -649,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); @@ -767,6 +779,10 @@ 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, @@ -785,7 +801,4 @@ 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 71c4c48..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 @@ -284,6 +284,10 @@ ResolverBase::visit (AST::ReturnExpr &) {} void +ResolverBase::visit (AST::TryExpr &) +{} + +void ResolverBase::visit (AST::UnsafeBlockExpr &) {} @@ -580,6 +584,14 @@ ResolverBase::visit (AST::GroupedPattern &) {} void +ResolverBase::visit (AST::SlicePatternItemsNoRest &) +{} + +void +ResolverBase::visit (AST::SlicePatternItemsHasRest &) +{} + +void ResolverBase::visit (AST::SlicePattern &) {} @@ -671,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 e17bdcb..89c5c35 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -21,6 +21,7 @@ #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" @@ -57,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 &); @@ -99,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 &); @@ -184,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 &); @@ -210,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-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index 0937d65..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 diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc index 2b5e2bf..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 (), @@ -383,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-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 01906cf..f1c0e5c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -111,17 +111,42 @@ DefaultResolver::visit (AST::IfLetExpr &expr) } void +DefaultResolver::visit (AST::IfLetExprConseqElse &expr) +{ + DefaultResolver::visit (static_cast<AST::IfLetExpr &> (expr)); + visit (expr.get_else_block ()); +} + +void DefaultResolver::visit (AST::Trait &trait) { - auto inner_fn_1 - = [this, &trait] () { AST::DefaultASTVisitor::visit (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_1)); + std::move (inner_fn_2)); }; - ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn_2, + ctx.scoped (Rib::Kind::Generics, trait.get_node_id (), inner_fn_3, trait.get_identifier () /* FIXME: Is that valid?*/); } @@ -343,19 +368,15 @@ DefaultResolver::visit (AST::MatchExpr &expr) void DefaultResolver::visit (AST::ConstantItem &item) { - if (item.has_expr ()) - { - auto expr_vis_1 - = [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)); - }; + 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); - } + // FIXME: Why do we need a Rib here? + ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis_2); } void @@ -380,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 99fd8e7..cf0df68 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -49,6 +49,7 @@ public: 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 &) {} @@ -58,6 +59,9 @@ public: 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; 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 c10379a..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" @@ -75,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; @@ -252,6 +256,11 @@ Early::visit (AST::MacroInvocation &invoc) { 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 ()) pending_invoc->accept_vis (*this); @@ -275,12 +284,14 @@ Early::visit (AST::MacroInvocation &invoc) if (!definition.has_value ()) 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; } @@ -394,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 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.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 8721386..1ed87b3 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -297,6 +297,10 @@ ForeverStack<N>::get (Node &start, const Identifier &name) // TODO: Can we improve the API? have `reverse_iter` return an optional? 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 ( @@ -549,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) { @@ -675,7 +687,7 @@ ForeverStack<N>::resolve_path ( if (!res) res = get_lang_prelude (seg.as_string ()); - if (!res && N == Namespace::Types) + if (N == Namespace::Types && !res) { if (seg.is_crate_path_seg ()) { @@ -707,6 +719,26 @@ ForeverStack<N>::resolve_path ( // 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 ()) @@ -739,6 +771,26 @@ ForeverStack<N>::resolve_path ( if (!res) res = get_lang_prelude (seg_name); + 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 ()); 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 62829e0..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" @@ -141,7 +142,10 @@ 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 ()); } @@ -208,10 +212,32 @@ Late::visit (AST::LetStmt &let) // let.get_node_id (), [] () {}); } +void +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) + 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 @@ -232,7 +258,7 @@ visit_identifier_as_pattern (NameResolutionContext &ctx, return; } - ctx.bindings.peek ().insert_ident (ident); + ctx.bindings.peek ().insert_ident (ident.as_string (), locus, is_ref, is_mut); if (ctx.bindings.peek ().is_or_bound (ident)) { @@ -251,9 +277,13 @@ visit_identifier_as_pattern (NameResolutionContext &ctx, 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_node_id (), + identifier.get_is_ref (), + identifier.get_is_mut ()); } void @@ -284,7 +314,8 @@ void Late::visit (AST::StructPatternFieldIdent &field) { visit_identifier_as_pattern (ctx, field.get_identifier (), field.get_locus (), - field.get_node_id ()); + field.get_node_id (), field.is_ref (), + field.is_mut ()); } void @@ -612,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); 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 f2907c9..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; @@ -66,7 +67,6 @@ public: 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_closure_params (AST::ClosureExpr &) override; diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 34615ed..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) { - bindings.back ().set.insert (value); + 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) + { + 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 diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index bb8519a..558b3ca 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -158,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 @@ -166,9 +182,12 @@ struct Binding Or, } kind; - std::unordered_set<Identifier> set; + // used to check the correctness of or-bindings + bool has_expected_bindings; + + std::unordered_map<std::string, std::pair<location_t, IdentifierMode>> idents; - Binding (Binding::Kind kind) : kind (kind) {} + Binding (Binding::Kind kind) : kind (kind), has_expected_bindings (false) {} }; /** @@ -179,6 +198,7 @@ enum class BindingSource Match, Let, IfLet, + WhileLet, For, /* Closure param or function param */ Param @@ -208,7 +228,8 @@ 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 (); 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 3e5ed53..0930f96 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -101,34 +101,11 @@ TopLevel::go (AST::Crate &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 @@ -173,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); @@ -193,40 +161,27 @@ TopLevel::visit (AST::ExternCrate &crate) auto derive_macros = mappings.lookup_derive_proc_macros (num); - auto sub_visitor_1 = [&] () { - // 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); - } - }; - - auto sub_visitor_2 = [&] () { - ctx.canonical_ctx.scope_crate (crate.get_node_id (), - crate.get_referenced_crate (), - std::move (sub_visitor_1)); - }; + // 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_2, - crate.get_as_clause ()); - else - ctx.scoped (Rib::Kind::Module, crate.get_node_id (), sub_visitor_2, - crate.get_referenced_crate ()); + visit (crate); } static bool @@ -384,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 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 0dfd654..8d3da92 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h @@ -176,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-backend.h b/gcc/rust/rust-backend.h index a0df217..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,21 +44,23 @@ class Bvariable; namespace Backend { +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) {} }; @@ -133,7 +137,7 @@ tree array_type (tree element_type, tree length); // 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); @@ -172,6 +176,9 @@ tree char_constant_expression (char c); // Get a char literal 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); @@ -238,6 +245,10 @@ tree array_initializer (tree, tree, tree, tree, tree, tree *, location_t); // fixed-length array, not a slice. 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, @@ -314,8 +325,7 @@ void 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, +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); @@ -339,18 +349,18 @@ void 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 *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 @@ -369,10 +379,10 @@ Bvariable *temporary_variable (tree fndecl, tree bind_tree, tree type, // 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 @@ -387,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. @@ -408,12 +424,12 @@ 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++: diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h index 0b83e8c..09d5e24 100644 --- a/gcc/rust/rust-diagnostics.h +++ b/gcc/rust/rust-diagnostics.h @@ -183,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) @@ -191,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, @@ -206,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) diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index f440f79..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, @@ -1924,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 (); @@ -1936,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 @@ -1945,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; @@ -1989,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) @@ -2010,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; @@ -2027,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; @@ -2124,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); @@ -2140,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; } @@ -2179,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)) @@ -2187,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; @@ -2236,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); @@ -2343,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 35003ab..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) diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc index d42ae6a..17f9c06 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -22,6 +22,7 @@ #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" @@ -619,10 +620,6 @@ Session::compile_crate (const char *filename) expansion (parsed_crate, name_resolution_ctx); - AST::DesugarForLoops ().go (parsed_crate); - AST::DesugarQuestionMark ().go (parsed_crate); - AST::DesugarApit ().go (parsed_crate); - rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) { @@ -685,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 (); @@ -732,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 @@ -762,7 +759,7 @@ Session::compile_crate (const char *filename) } // pass to GCC middle-end - ctx.write_to_backend (); + ctx->write_to_backend (); } void @@ -986,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 @@ -1179,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/typecheck/rust-autoderef.cc b/gcc/rust/typecheck/rust-autoderef.cc index 8256074..10a59bd 100644 --- a/gcc/rust/typecheck/rust-autoderef.cc +++ b/gcc/rust/typecheck/rust-autoderef.cc @@ -247,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 d0a9f5d..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 (); } @@ -329,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 @@ -346,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 50c74ed..fd12839 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -204,8 +204,9 @@ TypeCoercionRules::coerce_unsafe_ptr (TyTy::BaseType *receiver, default: { - // FIXME this can probably turn into a unify_and - if (receiver->can_eq (expected, false)) + if (types_compatable (TyTy::TyWithLocation (receiver), + TyTy::TyWithLocation (expected), UNKNOWN_LOCATION, + false)) return CoercionResult{{}, expected->clone ()}; return CoercionResult::get_error (); @@ -280,9 +281,6 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, default: { - // FIXME - // we might be able to replace this with a can_eq because we default - // back to a final unity anyway rust_debug ("coerce_borrowed_pointer -- unify"); TyTy::BaseType *result = unify_site_and (receiver->get_ref (), 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 35c9b0a..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; } @@ -288,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 (); @@ -444,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 ()); } @@ -582,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 (); } @@ -611,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); @@ -628,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); 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 6d5806f..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 @@ -287,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 (), @@ -439,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) @@ -471,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 ()); @@ -480,10 +518,34 @@ 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; @@ -499,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; @@ -510,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 2dbd84d..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.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.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.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.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 81d95c8..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) { @@ -649,7 +663,22 @@ TypeCheckExpr::visit (HIR::BlockExpr &expr) void TypeCheckExpr::visit (HIR::AnonConst &expr) { - infered = TypeCheckExpr::Resolve (expr.get_inner_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 @@ -880,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; @@ -983,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) { @@ -1029,8 +1074,13 @@ 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: @@ -1039,22 +1089,20 @@ TypeCheckExpr::visit (HIR::ArrayExpr &expr) = 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; @@ -1092,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 @@ -1432,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; @@ -1726,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 ()}; + + if (context->have_function_context ()) + { + TypeCheckContextItem current_context = context->peek_context (); + TyTy::FnType *current_context_fndecl + = current_context.get_context_type (); - // get from parent context - std::vector<TyTy::SubstitutionParamMapping> subst_refs - = current_context_fndecl->clone_substs (); + 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 ()) @@ -1787,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); @@ -1850,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}); @@ -1869,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 (); @@ -1913,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 @@ -2064,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; @@ -2086,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; @@ -2118,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 (""); @@ -2244,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 e0a3278..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; @@ -73,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 {} @@ -109,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 00f0cc6..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 ()) @@ -338,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.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 (), @@ -412,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 ()); diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 5595dad..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,24 +195,11 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) // get the path - auto path = CanonicalPath::create_empty (); - - // FIXME: HACK: ARTHUR: Disgusting - if (flag_name_resolution_2_0) - { - auto &nr_ctx - = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); + auto &nr_ctx + = Resolver2_0::ImmutableNameResolutionContext::get ().resolver (); - path - = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ()); - } - 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 ()}; @@ -254,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 ()) @@ -275,23 +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 (); - path - = nr_ctx.to_canonical_path (struct_decl.get_mappings ().get_nodeid ()); - } - 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 ()}; @@ -332,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 (); @@ -362,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.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 @@ -404,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 ()) @@ -426,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.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; @@ -564,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 ()) @@ -602,21 +558,11 @@ TypeCheckItem::visit (HIR::Function &function) TyTy::FnParam (param.get_param_name ().clone_pattern (), param_tyty)); } - 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.to_canonical_path (function.get_mappings ().get_nodeid ()); - } - 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 ()}; @@ -737,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 15d8620..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; @@ -463,6 +450,17 @@ 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: @@ -470,19 +468,9 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) 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 (), @@ -507,11 +495,53 @@ TypeCheckPattern::visit (HIR::TuplePattern &pattern) case HIR::TuplePatternItems::ItemType::RANGED: { - // HIR::TuplePatternItemsRanged &ref - // = *static_cast<HIR::TuplePatternItemsRanged *> ( - // pattern.get_items ().get ()); - // TODO - rust_unreachable (); + 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; } @@ -520,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 @@ -593,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 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 e3a08e6..4ef8348 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc @@ -362,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 18e0458..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); @@ -1076,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 27879e3..aba4ab5 100644 --- a/gcc/rust/typecheck/rust-hir-type-check.cc +++ b/gcc/rust/typecheck/rust-hir-type-check.cc @@ -26,9 +26,6 @@ #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); namespace Rust { @@ -164,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); } @@ -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.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 356c558..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); @@ -271,6 +312,7 @@ 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; @@ -283,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; @@ -308,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 bdfde55..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 ()); 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 a549449..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,7 +38,6 @@ bool query_type (HirId reference, TyTy::BaseType **result) { auto &mappings = Analysis::Mappings::get (); - auto &resolver = *Resolver::get (); TypeCheckContext *context = TypeCheckContext::get (); if (context->lookup_type (reference, result)) @@ -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-typecheck-context.cc b/gcc/rust/typecheck/rust-typecheck-context.cc index 7b35848..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,10 +611,38 @@ 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 emit_error) { - // default inference variables if possible + iterate_deferred_operator_overloads ( + [&] (HirId id, DeferredOpOverload &op) mutable -> bool { + return compute_ambigious_op_overload (id, op); + }); + iterate ([&] (HirId id, TyTy::BaseType *ty) mutable -> bool { return compute_infer_var (id, ty, emit_error); }); diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 5d42f80..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 @@ -329,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 (), @@ -510,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) @@ -531,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 @@ -568,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); } } @@ -701,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); @@ -748,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 @@ -810,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.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 aeefaa9..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 ()), @@ -1606,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 28d311a..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,25 +58,25 @@ 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::TypeParam & +const HIR::GenericParam & SubstitutionParamMapping::get_generic_param () const { return generic; @@ -84,6 +88,12 @@ 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 { @@ -93,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 (); } @@ -115,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); @@ -130,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; @@ -151,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; @@ -197,12 +234,6 @@ SubstitutionArg::operator= (const SubstitutionArg &other) } BaseType * -SubstitutionArg::get_tyty () -{ - return argument; -} - -const BaseType * SubstitutionArg::get_tyty () const { return argument; @@ -214,7 +245,7 @@ SubstitutionArg::get_param_mapping () const return param; } -const ParamType * +const BaseGeneric * SubstitutionArg::get_param_ty () const { return original_param; @@ -319,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; @@ -671,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, @@ -685,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, @@ -708,15 +750,31 @@ SubstitutionRef::get_mappings_from_generic_args ( } const auto ¶m_mapping = substitutions.at (offs); - const auto &type_param = param_mapping.get_generic_param (); - if (type_param.from_impl_trait ()) + const auto &generic = param_mapping.get_generic_param (); + if (generic.get_kind () == HIR::GenericParam::GenericKind::TYPE) { - 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 (); + 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); @@ -724,6 +782,62 @@ SubstitutionRef::get_mappings_from_generic_args ( 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)); + } + // we must need to fill out defaults size_t left_over = num_required_substitutions () - min_required_substitutions (); @@ -771,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 (); @@ -779,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 { @@ -922,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 (); @@ -936,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 2f5de23..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,23 +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 (); - const HIR::TypeParam &get_generic_param () const; + 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 @@ -77,8 +80,8 @@ public: bool need_substitution () const; private: - HIR::TypeParam &generic; - ParamType *param; + HIR::GenericParam &generic; + BaseGeneric *param; }; /** @@ -148,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 (); @@ -166,7 +167,7 @@ public: private: const SubstitutionParamMapping *param; - const ParamType *original_param; + const BaseGeneric *original_param; BaseType *argument; }; @@ -206,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-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 91c68ef..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; @@ -440,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> ()) { @@ -574,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> ()) @@ -823,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> ()) { @@ -852,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> () @@ -890,6 +904,7 @@ BaseType::has_substitutions_defined () const case TUPLE: case PARAM: case PLACEHOLDER: + case CONST: case OPAQUE: return false; @@ -956,6 +971,7 @@ BaseType::needs_generic_substitutions () const case TUPLE: case PARAM: case PLACEHOLDER: + case CONST: case OPAQUE: return false; @@ -1816,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; } } @@ -2145,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; } @@ -2486,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 @@ -2525,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 ()); } @@ -2542,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; } @@ -3398,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 { @@ -3475,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 ()); } @@ -3545,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 @@ -3572,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, diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index c759521..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, @@ -164,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 @@ -364,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> ()); @@ -388,13 +406,11 @@ public: BaseType *clone () const final override; - std::string get_symbol () const; + std::string get_symbol () const override final; - HIR::GenericParam &get_generic_param (); + bool can_resolve () const override final; - bool can_resolve () const; - - BaseType *resolve () const; + BaseType *resolve () const override final; std::string get_name () const override final; @@ -408,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 @@ -538,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; @@ -593,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; @@ -1153,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; @@ -1184,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 9144f2e..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 { @@ -325,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); } @@ -419,6 +425,7 @@ UnifyRules::expect_inference_variable (TyTy::InferType *ltype, case TyTy::PROJECTION: case TyTy::DYNAMIC: case TyTy::CLOSURE: + case TyTy::CONST: case TyTy::OPAQUE: { bool is_valid = (ltype->get_infer_kind () @@ -545,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); } @@ -591,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); } @@ -662,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); } @@ -733,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); } @@ -797,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); } @@ -825,14 +837,25 @@ UnifyRules::expect_array (TyTy::ArrayType *ltype, TyTy::BaseType *rtype) = 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::ArrayType (type.get_ref (), type.get_ty_ref (), - type.get_ident ().locus, - type.get_capacity_expr (), - TyTy::TyVar ( - element_unify->get_ref ())); - } + 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; @@ -858,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); } @@ -918,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); } @@ -1007,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); } @@ -1098,6 +1124,43 @@ UnifyRules::expect_fnptr (TyTy::FnPtr *ltype, TyTy::BaseType *rtype) } 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); + } + } + + return ltype->clone (); + } + break; + case TyTy::TUPLE: case TyTy::BOOL: case TyTy::CHAR: @@ -1117,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); } @@ -1190,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); } @@ -1239,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); } @@ -1288,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); } @@ -1345,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); } @@ -1402,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); } @@ -1459,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); } @@ -1508,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); } @@ -1557,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); } @@ -1629,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); } @@ -1678,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); } @@ -1739,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); } @@ -1810,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); } @@ -1862,5 +1937,72 @@ UnifyRules::expect_opaque (TyTy::OpaqueType *ltype, TyTy::BaseType *rtype) 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 ()); + } + + 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); +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-unify.h b/gcc/rust/typecheck/rust-unify.h index f64f0ed..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, 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-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 9bf4f77..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 () @@ -389,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-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/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f9f3de6..df2c843 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,667 @@ +2025-08-06 Sam James <sam@gentoo.org> + + * g++.dg/cpp26/constexpr-new3.C: Escape '[' and ']'. + +2025-08-06 Alexandre Oliva <oliva@adacore.com> + + * gcc.dg/torture/hardbool-ai.c: New. + * gcc.dg/torture/hardbool-vi.c: New. + * gcc.dg/torture/hardbool.c: Handle NO_BITFIELDS. + (add1, preinc, postinc, sub1, predec, postdec): New. + (main): Exercise them. + +2025-08-06 Martin Uecker <uecker@tugraz.at> + + PR c/108931 + * gcc.dg/vla-tert-1.c: New test. + +2025-08-06 Patrick Palka <ppalka@redhat.com> + + PR c++/121231 + PR c++/119688 + PR c++/94511 + * g++.dg/abi/mangle82.C: New test. + * g++.dg/cpp2a/nontype-class73.C: New test. + +2025-08-06 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp26/constexpr-new3.C: Tweak diagnostic. + +2025-08-06 Richard Biener <rguenther@suse.de> + + * gcc.dg/vect/vect-gather-1.c: Adjust to hide N. + +2025-08-06 Tejas Belagod <tejas.belagod@arm.com> + + * gcc.target/aarch64/sve/acle/general/cops.c: Fix test. + +2025-08-06 Yang Yujie <yangyujie@loongson.cn> + + * gcc.dg/torture/bitint-84.c: New test. + +2025-08-06 Yang Yujie <yangyujie@loongson.cn> + + * gcc.dg/torture/bitint-83.c: New test. + +2025-08-06 Yang Yujie <yangyujie@loongson.cn> + + * gcc.dg/bitintext.h (BEXTC1): Define. Convert the copied + object back to the original type before comparison. + (BEXTC): Use BEXTC1 for both the signed and the unsigned case. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/121413 + * gcc.dg/torture/bitint-85.c: New test. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/121127 + * gcc.dg/bitint-125.c: New test. + +2025-08-06 Yuao Ma <c8ef@outlook.com> + + * gfortran.dg/c_f_pointer_shape_tests_2.f03: Use the new driver. + * gfortran.dg/c_f_pointer_shape_tests_4.f03: Ditto. + * gfortran.dg/c_f_pointer_shape_tests_4_driver.c: Removed. + * gfortran.dg/c_f_pointer_shape_tests_2_driver.c: Renamed to ... + * gfortran.dg/c_f_pointer_shape_tests_driver.c: ... this; format + with gcc style. + +2025-08-06 Jakub Jelinek <jakub@redhat.com> + + PR preprocessor/120778 + * c-c++-common/cpp/comment-ff-1.c: New test. + * c-c++-common/cpp/comment-vtab-1.c: New test. + +2025-08-06 Martin Uecker <uecker@tugraz.at> + + PR c/121217 + * gcc.dg/pr121217.c: New test. + +2025-08-06 Kito Cheng <kito.cheng@sifive.com> + + * gcc.target/riscv/arch-unset-1.c: New test. + * gcc.target/riscv/arch-unset-2.c: New test. + * gcc.target/riscv/arch-unset-3.c: New test. + * gcc.target/riscv/arch-unset-4.c: New test. + * gcc.target/riscv/arch-unset-5.c: New test. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + + * c-c++-common/gomp/target-update-iterators-1.c: New. + * c-c++-common/gomp/target-update-iterators-2.c: New. + * c-c++-common/gomp/target-update-iterators-3.c: New. + +2025-08-06 Kwok Cheung Yeung <kcyeung@baylibre.com> + Andrew Stubbs <ams@baylibre.com> + + * c-c++-common/gomp/map-6.c (foo): Amend expected error message. + * c-c++-common/gomp/target-map-iterators-1.c: New. + * c-c++-common/gomp/target-map-iterators-2.c: New. + * c-c++-common/gomp/target-map-iterators-3.c: New. + * c-c++-common/gomp/target-map-iterators-4.c: New. + +2025-08-06 Jerry DeLisle <jvdelisle@gcc.gnu.org> + + PR libfortran/121234 + * gfortran.dg/pr121234.f90: New test. + +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 diff --git a/gcc/testsuite/c-c++-common/cpp/comment-ff-1.c b/gcc/testsuite/c-c++-common/cpp/comment-ff-1.c new file mode 100644 index 0000000..0d071b1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/comment-ff-1.c @@ -0,0 +1,12 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// Test that form-feed followed by non-whitespace +// in line comments are accepted. +// { dg-do compile } +// { dg-options "-pedantic-errors -Wall -W" } + +// +int a; +// +int b; +// comment +int c; diff --git a/gcc/testsuite/c-c++-common/cpp/comment-vtab-1.c b/gcc/testsuite/c-c++-common/cpp/comment-vtab-1.c new file mode 100644 index 0000000..03feb73 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/comment-vtab-1.c @@ -0,0 +1,12 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// Test that vertical tab followed by non-whitespace +// in line comments are accepted. +// { dg-do compile } +// { dg-options "-pedantic-errors -Wall -W" } + +// +int a; +// +int b; +// comment +int c; 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/dr2575.C b/gcc/testsuite/g++.dg/DRs/dr2575.C new file mode 100644 index 0000000..f350282 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2575.C @@ -0,0 +1,51 @@ +// DR 2575 - Undefined behavior when macro-replacing "defined" operator +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A defined +#if !A(A) // { dg-error "this use of 'defined' may not be portable" } +#error +#endif +#if A(B) // { dg-error "this use of 'defined' may not be portable" } +#error +#endif +#if !A A // { dg-error "this use of 'defined' may not be portable" } +#error +#endif +#if A B // { dg-error "this use of 'defined' may not be portable" } +#error +#endif +#if defined A + B +#else +#error +#endif +#if defined +B // { dg-error "operator 'defined' requires an identifier" } +#endif // { dg-error "missing binary operator before token 'B'" "" { target *-*-* } .-1 } +#if defined 1 // { dg-error "operator 'defined' requires an identifier" } +#endif +#if defined // { dg-error "operator 'defined' requires an identifier" } +#endif +#if defined (A + B) // { dg-error "missing '\\\)' after 'defined'" } +#endif // { dg-error "missing binary operator before token 'B'" "" { target *-*-* } .-1 } +#if defined (+B) // { dg-error "operator 'defined' requires an identifier" } +#endif // { dg-error "missing binary operator before token 'B'" "" { target *-*-* } .-1 } +#if defined (1) // { dg-error "operator 'defined' requires an identifier" } +#endif // { dg-error "missing '\\\(' in expression" "" { target *-*-* } .-1 } +#if defined () // { dg-error "operator 'defined' requires an identifier" } +#endif +#if defined A, B // { dg-error "comma operator in operand of #if" } +#endif +#if defined (A), B // { dg-error "comma operator in operand of #if" } +#endif +#if (defined A), B // { dg-error "comma operator in operand of #if" } +#endif +#if defined (A, B) // { dg-error "missing '\\\)' after 'defined'" } +#endif // { dg-error "missing binary operator before token 'B'" "" { target *-*-* } .-1 } +#if defined (A) + B +#else +#error +#endif +#if (defined A) + B +#else +#error +#endif diff --git a/gcc/testsuite/g++.dg/DRs/dr2576.C b/gcc/testsuite/g++.dg/DRs/dr2576.C new file mode 100644 index 0000000..ed53a08 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2576.C @@ -0,0 +1,47 @@ +// DR 2576 - Undefined behavior with macro-expanded #include directives +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A <cstddef> +#include A +#define B "cstddef" +#include B +#define C(x) #x +#define D(x) C(x) +#include D(cstddef) +#include "cstddef" "" // { dg-error "extra tokens at end of '#include' directive" } +#include "cstddef"".h" // { dg-error "extra tokens at end of '#include' directive" } +#include // { dg-error "'#include' expects '\"FILENAME\"' or '<FILENAME>'" } +#include E // { dg-error "'#include' expects '\"FILENAME\"' or '<FILENAME>'" } +#include <cstddef + // { dg-error "missing terminating '>' character" "" { target *-*-* } .-1 } +#include "cstddef + // { dg-error "missing terminating \" character" "" { target *-*-* } .-1 } + // { dg-error "'#include' expects '\"FILENAME\"' or '<FILENAME>'" "" { target *-*-* } .-2 } +#define F cstddef +#include F // { dg-error "'#include' expects '\"FILENAME\"' or '<FILENAME>'" } +// There is implementation divergence on the following cases (G H through M N) +// between e.g. GCC and clang++. clang++ fails on trying to include ' cstddef' +// and 'cstd def' and 'stddef .h' and 'cstddef ' headers. +// https://eel.is/c++draft/cpp.include#7.sentence-3 makes the whitespace +// handling implementation defined and the way GCC handles it can allow +// certain use cases which aren't otherwise possible. One can still +// insert spaces into the <> filenames if it is from the same macro. +#define G < +#define H cstddef> +#include G H +#define I <cstd +#define J def> +#include I J +#define K <stddef +#define L .h> +#include K L +#define M <cstddef +#define N > +#include M N +#define O <cstddef> <cstddef> +#include O // { dg-error "extra tokens at end of '#include' directive" } +#define P "cstddef" "" +#include P // { dg-error "extra tokens at end of '#include' directive" } +#define Q "cstddef"".h" +#include Q // { dg-error "extra tokens at end of '#include' directive" } diff --git a/gcc/testsuite/g++.dg/DRs/dr2577-1.C b/gcc/testsuite/g++.dg/DRs/dr2577-1.C new file mode 100644 index 0000000..784b6a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2577-1.C @@ -0,0 +1,40 @@ +// DR 2577 - Undefined behavior for preprocessing directives in macro arguments +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A(x) +#define B(x, y) +A( +#if 1 // { dg-error "embedding a directive within macro arguments is not portable" } +1 +#else // { dg-error "embedding a directive within macro arguments is not portable" } +2 +#endif // { dg-error "embedding a directive within macro arguments is not portable" } +) +B(1, +#line 234 // { dg-error "embedding a directive within macro arguments is not portable" } +) +#line 18 +A( +#define C 1 // { dg-error "embedding a directive within macro arguments is not portable" } +) +A( +#undef C // { dg-error "embedding a directive within macro arguments is not portable" } +) +B(42, +# 234 "dr2577-1.C" // { dg-error "embedding a directive within macro arguments is not portable" } +) // { dg-error "style of line directive is a GCC extension" "" { target *-*-* } .-1 } +#line 28 "dr2577-1.C" +B( +#warning "foobar" // { dg-error "embedding a directive within macro arguments is not portable" } +, 12) // { dg-error "'#warning' before C\\\+\\\+23 is a GCC extension" "" { target c++20_down } .-1 } + // { dg-warning "#warning \"foobar\"" "" { target *-*-* } .-2 } +A( +#pragma GCC diagnostics push // { dg-error "embedding a directive within macro arguments is not portable" } +) +B(5, +#pragma GCC diagnostics pop // { dg-error "embedding a directive within macro arguments is not portable" } +) +A( +#error foobar // { dg-error "embedding a directive within macro arguments is not portable" } +) // { dg-error "#error foobar" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/DRs/dr2577-2.C b/gcc/testsuite/g++.dg/DRs/dr2577-2.C new file mode 100644 index 0000000..e54006a --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2577-2.C @@ -0,0 +1,13 @@ +// DR 2577 - Undefined behavior for preprocessing directives in macro arguments +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A(x, y, z) x + y + z +int a = A( +#include "dr2577-2.h" // { dg-error "embedding a directive within macro arguments is not portable" } +, +#include "dr2577-2.h" +, +#include "dr2577-2.h" +); +// { dg-error "unterminated argument list invoking macro 'A'" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/g++.dg/DRs/dr2577-2.h b/gcc/testsuite/g++.dg/DRs/dr2577-2.h new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2577-2.h @@ -0,0 +1 @@ +1 diff --git a/gcc/testsuite/g++.dg/DRs/dr2577-3.C b/gcc/testsuite/g++.dg/DRs/dr2577-3.C new file mode 100644 index 0000000..6ebf419 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2577-3.C @@ -0,0 +1,7 @@ +// DR 2577 - Undefined behavior for preprocessing directives in macro arguments +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#define A(x) x +int a = A( +#include "dr2577-3.h" // { dg-error "embedding a directive within macro arguments is not portable" } diff --git a/gcc/testsuite/g++.dg/DRs/dr2577-3.h b/gcc/testsuite/g++.dg/DRs/dr2577-3.h new file mode 100644 index 0000000..5e36ce0 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2577-3.h @@ -0,0 +1 @@ +1) diff --git a/gcc/testsuite/g++.dg/abi/mangle82.C b/gcc/testsuite/g++.dg/abi/mangle82.C new file mode 100644 index 0000000..39dd581 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle82.C @@ -0,0 +1,85 @@ +// Test mangling of C++20 class NTTP objects with implicitly zeroed +// non-trailing subojects. +// PR c++/121231 +// { dg-do compile { target c++20 } } + +struct A { + int x, y, z; + + static constexpr A make(int x, int y, int z) { + A a{}; + if (x != 0) + a.x = x; + if (y != 0) + a.y = y; + if (z != 0) + a.z = z; + return a; + } +}; + +struct B : A { + int w; + + static constexpr B make(int x, int y, int z, int w) { + B b{}; + if (x != 0 || y != 0 || z != 0) + static_cast<A&>(b) = A::make(x, y, z); + if (w != 0) + b.w = w; + return b; + } +}; + +struct C { + int xyz[3]; + + static constexpr C make(int x, int y, int z) { + C c{}; + if (x != 0) + c.xyz[0] = x; + if (y != 0) + c.xyz[1] = y; + if (z != 0) + c.xyz[2] = z; + return c; + } +}; + +template<int N, A a> void f(); +template<int N, B b> void g(); +template<int N, C c> void h(); + +int main() { + f<0, A::make(0, 0, 1)>(); // void f<0, A{0, 0, 1}>() + f<1, A::make(0, 1, 0)>(); // void f<1, A{0, 1}>() + f<2, A::make(0, 0, 0)>(); // void f<2, A{}>() + f<3, A::make(1, 0, 1)>(); // void f<3, A{1, 0, 1}>() + + g<0, B::make(0, 0, 0, 1)>(); // void g<0, B{A{}, 1}>() + g<1, B::make(0, 0, 1, 0)>(); // void g<1, B{A{0, 0, 1}}>() + g<2, B::make(0, 1, 0, 0)>(); // void g<2, B{A{0, 1}}>() + g<3, B::make(0, 0, 0, 0)>(); // void g<3, B{}>() + g<4, B::make(1, 0, 1, 0)>(); // void g<4, B{A{1, 0, 1}}>() + + h<0, C::make(0, 0, 1)>(); // void h<0, C{int [3]{0, 0, 1}}>() + h<1, C::make(0, 1, 0)>(); // void h<1, C{int [3]{0, 1}}>() + h<2, C::make(0, 0, 0)>(); // void h<2, C{}>() + h<3, C::make(1, 0, 1)>(); // void h<3, C{int [3]{1, 0, 1}}>() +} + +// { dg-final { scan-assembler "_Z1fILi0EXtl1ALi0ELi0ELi1EEEEvv" } } +// { dg-final { scan-assembler "_Z1fILi1EXtl1ALi0ELi1EEEEvv" } } +// { dg-final { scan-assembler "_Z1fILi2EXtl1AEEEvv" } } +// { dg-final { scan-assembler "_Z1fILi3EXtl1ALi1ELi0ELi1EEEEvv" } } + +// { dg-final { scan-assembler "_Z1gILi0EXtl1Btl1AELi1EEEEvv" } } +// { dg-final { scan-assembler "_Z1gILi1EXtl1Btl1ALi0ELi0ELi1EEEEEvv" } } +// { dg-final { scan-assembler "_Z1gILi2EXtl1Btl1ALi0ELi1EEEEEvv" } } +// { dg-final { scan-assembler "_Z1gILi3EXtl1BEEEvv" } } +// { dg-final { scan-assembler "_Z1gILi4EXtl1Btl1ALi1ELi0ELi1EEEEEvv" } } + +// { dg-final { scan-assembler "_Z1hILi0EXtl1CtlA3_iLi0ELi0ELi1EEEEEvv" } } +// { dg-final { scan-assembler "_Z1hILi1EXtl1CtlA3_iLi0ELi1EEEEEvv" } } +// { dg-final { scan-assembler "_Z1hILi2EXtl1CEEEvv" } } +// { dg-final { scan-assembler "_Z1hILi3EXtl1CtlA3_iLi1ELi0ELi1EEEEEvv" } } diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C index 6a06a6e..c79060f 100644 --- a/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C @@ -37,7 +37,7 @@ baz () { std::allocator<int> a; auto b = a.allocate (2); - new (b) long (42); // { dg-error "accessing value of 'heap ' through a 'long int' glvalue in a constant expression" } + new (b) long (42); // { dg-error "accessing value of 'int \\\[2\\\]' object through a 'long int' glvalue in a constant expression" } a.deallocate (b, 2); return true; } 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/nontype-class73.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class73.C new file mode 100644 index 0000000..7f27cad --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class73.C @@ -0,0 +1,30 @@ +// PR c++/119688 +// { dg-do compile { target c++20 } } + +template<int N> +struct builder { + bool value[256]{}; + constexpr builder(char const (&s)[N]) { + for(int i = 0 ; i < N; ++i) + value[static_cast<unsigned char>(s[i])] = true; + } +}; + +template<builder A> +constexpr auto operator""_ar() { + return A.value; +} + +constexpr auto first = "ab"_ar; +static_assert( first['a']); +static_assert( first['b']); +static_assert(!first['c']); +static_assert(!first['d']); +static_assert(!first['z']); + +constexpr auto second = "cd"_ar; +static_assert(!second['a']); +static_assert(!second['b']); +static_assert(!second['z']); +static_assert( second['c']); +static_assert( second['d']); diff --git a/gcc/testsuite/g++.dg/modules/atom-preamble-3.C b/gcc/testsuite/g++.dg/modules/atom-preamble-3.C index 74dba7d..915fa74 100644 --- a/gcc/testsuite/g++.dg/modules/atom-preamble-3.C +++ b/gcc/testsuite/g++.dg/modules/atom-preamble-3.C @@ -1,4 +1,4 @@ -// { dg-additional-options "-fmodules-ts" } +// { dg-additional-options "-fmodules-ts -Wno-keyword-macro" } #define import import import malcolm; // { dg-error "object-like macro" } // { dg-error "failed to read" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/g++.dg/opt/pr82577.C b/gcc/testsuite/g++.dg/opt/pr82577.C index 1a06897..8a4f36d 100644 --- a/gcc/testsuite/g++.dg/opt/pr82577.C +++ b/gcc/testsuite/g++.dg/opt/pr82577.C @@ -3,7 +3,9 @@ #if __cplusplus > 201500L // register is no longer a keyword in C++17. -#define register +#define reg +#else +#define reg register #endif class a { @@ -14,8 +16,8 @@ struct c { int d; a e; } f; -void fn1(register c *g) { - register int *h; +void fn1(reg c *g) { + reg int *h; do (h) = g->e.b() + (g)->d; while (&f); diff --git a/gcc/testsuite/g++.dg/template/sfinae17.C b/gcc/testsuite/g++.dg/template/sfinae17.C index eb043cb..8628726 100644 --- a/gcc/testsuite/g++.dg/template/sfinae17.C +++ b/gcc/testsuite/g++.dg/template/sfinae17.C @@ -1,7 +1,7 @@ // The conversion from D* to B* is ambiguous, but that should not produce // an error, it should remove the first f overload by SFINAE. -#define static_assert(TEST,STR) \ +#define my_static_assert(TEST,STR) \ do { int ar[(TEST)?1:-1]; } while (0); struct B {}; @@ -23,6 +23,6 @@ template <class T> int main() { - static_assert(sizeof f<int>(0) == sizeof(two), ""); - static_assert(sizeof f<B *>(0) == sizeof(two), ""); + my_static_assert(sizeof f<int>(0) == sizeof(two), ""); + my_static_assert(sizeof f<B *>(0) == sizeof(two), ""); } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-1.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-1.C new file mode 100644 index 0000000..f47de7a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-1.C @@ -0,0 +1,112 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } +// { dg-additional-options "-fmodules" { target c++20 } } + +// [lex.key] +#define alignas 1 // { dg-error "keyword 'alignas' defined as macro" "" { target c++26 } } +#define alignof 1 // { dg-error "keyword 'alignof' defined as macro" "" { target c++26 } } +#define asm 1 // { dg-error "keyword 'asm' defined as macro" "" { target c++26 } } +#define auto 1 // { dg-error "keyword 'auto' defined as macro" "" { target c++26 } } +#define bool 1 // { dg-error "keyword 'bool' defined as macro" "" { target c++26 } } +#define break 1 // { dg-error "keyword 'break' defined as macro" "" { target c++26 } } +#define case 1 // { dg-error "keyword 'case' defined as macro" "" { target c++26 } } +#define catch 1 // { dg-error "keyword 'catch' defined as macro" "" { target c++26 } } +#define char 1 // { dg-error "keyword 'char' defined as macro" "" { target c++26 } } +#define char16_t 1 // { dg-error "keyword 'char16_t' defined as macro" "" { target c++26 } } +#define char32_t 1 // { dg-error "keyword 'char32_t' defined as macro" "" { target c++26 } } +#define char8_t 1 // { dg-error "keyword 'char8_t' defined as macro" "" { target c++26 } } +#define class 1 // { dg-error "keyword 'class' defined as macro" "" { target c++26 } } +#define co_await 1 // { dg-error "keyword 'co_await' defined as macro" "" { target c++26 } } +#define concept 1 // { dg-error "keyword 'concept' defined as macro" "" { target c++26 } } +#define const 1 // { dg-error "keyword 'const' defined as macro" "" { target c++26 } } +#define const_cast 1 // { dg-error "keyword 'const_cast' defined as macro" "" { target c++26 } } +#define consteval 1 // { dg-error "keyword 'consteval' defined as macro" "" { target c++26 } } +#define constexpr 1 // { dg-error "keyword 'constexpr' defined as macro" "" { target c++26 } } +#define constinit 1 // { dg-error "keyword 'constinit' defined as macro" "" { target c++26 } } +#define continue 1 // { dg-error "keyword 'continue' defined as macro" "" { target c++26 } } +#define contract_assert 1 +#define co_return 1 // { dg-error "keyword 'co_return' defined as macro" "" { target c++26 } } +#define co_yield 1 // { dg-error "keyword 'co_yield' defined as macro" "" { target c++26 } } +#define decltype 1 // { dg-error "keyword 'decltype' defined as macro" "" { target c++26 } } +#define default 1 // { dg-error "keyword 'default' defined as macro" "" { target c++26 } } +#define delete 1 // { dg-error "keyword 'delete' defined as macro" "" { target c++26 } } +#define do 1 // { dg-error "keyword 'do' defined as macro" "" { target c++26 } } +#define double 1 // { dg-error "keyword 'double' defined as macro" "" { target c++26 } } +#define dynamic_cast 1 // { dg-error "keyword 'dynamic_cast' defined as macro" "" { target c++26 } } +#define else 1 // { dg-error "keyword 'else' defined as macro" "" { target c++26 } } +#define enum 1 // { dg-error "keyword 'enum' defined as macro" "" { target c++26 } } +#define explicit 1 // { dg-error "keyword 'explicit' defined as macro" "" { target c++26 } } +#define export 1 // { dg-error "keyword 'export' defined as macro" "" { target c++26 } } +#define extern 1 // { dg-error "keyword 'extern' defined as macro" "" { target c++26 } } +#define false 1 // { dg-error "keyword 'false' defined as macro" "" { target c++26 } } +#define float 1 // { dg-error "keyword 'float' defined as macro" "" { target c++26 } } +#define for 1 // { dg-error "keyword 'for' defined as macro" "" { target c++26 } } +#define friend 1 // { dg-error "keyword 'friend' defined as macro" "" { target c++26 } } +#define goto 1 // { dg-error "keyword 'goto' defined as macro" "" { target c++26 } } +#define if 1 // { dg-error "keyword 'if' defined as macro" "" { target c++26 } } +#define inline 1 // { dg-error "keyword 'inline' defined as macro" "" { target c++26 } } +#define int 1 // { dg-error "keyword 'int' defined as macro" "" { target c++26 } } +#define long 1 // { dg-error "keyword 'long' defined as macro" "" { target c++26 } } +#define mutable 1 // { dg-error "keyword 'mutable' defined as macro" "" { target c++26 } } +#define namespace 1 // { dg-error "keyword 'namespace' defined as macro" "" { target c++26 } } +#define new 1 // { dg-error "keyword 'new' defined as macro" "" { target c++26 } } +#define noexcept 1 // { dg-error "keyword 'noexcept' defined as macro" "" { target c++26 } } +#define nullptr 1 // { dg-error "keyword 'nullptr' defined as macro" "" { target c++26 } } +#define operator 1 // { dg-error "keyword 'operator' defined as macro" "" { target c++26 } } +#define private 1 // { dg-error "keyword 'private' defined as macro" "" { target c++26 } } +#define protected 1 // { dg-error "keyword 'protected' defined as macro" "" { target c++26 } } +#define public 1 // { dg-error "keyword 'public' defined as macro" "" { target c++26 } } +#define register 1 // { dg-error "keyword 'register' defined as macro" "" { target c++26 } } +#define reinterpret_cast 1 // { dg-error "keyword 'reinterpret_cast' defined as macro" "" { target c++26 } } +#define requires 1 // { dg-error "keyword 'requires' defined as macro" "" { target c++26 } } +#define return 1 // { dg-error "keyword 'return' defined as macro" "" { target c++26 } } +#define short 1 // { dg-error "keyword 'short' defined as macro" "" { target c++26 } } +#define signed 1 // { dg-error "keyword 'signed' defined as macro" "" { target c++26 } } +#define sizeof 1 // { dg-error "keyword 'sizeof' defined as macro" "" { target c++26 } } +#define static 1 // { dg-error "keyword 'static' defined as macro" "" { target c++26 } } +#define static_assert 1 // { dg-error "keyword 'static_assert' defined as macro" "" { target c++26 } } +#define static_cast 1 // { dg-error "keyword 'static_cast' defined as macro" "" { target c++26 } } +#define struct 1 // { dg-error "keyword 'struct' defined as macro" "" { target c++26 } } +#define switch 1 // { dg-error "keyword 'switch' defined as macro" "" { target c++26 } } +#define template 1 // { dg-error "keyword 'template' defined as macro" "" { target c++26 } } +#define this 1 // { dg-error "keyword 'this' defined as macro" "" { target c++26 } } +#define thread_local 1 // { dg-error "keyword 'thread_local' defined as macro" "" { target c++26 } } +#define throw 1 // { dg-error "keyword 'throw' defined as macro" "" { target c++26 } } +#define true 1 // { dg-error "keyword 'true' defined as macro" "" { target c++26 } } +#define try 1 // { dg-error "keyword 'try' defined as macro" "" { target c++26 } } +#define typedef 1 // { dg-error "keyword 'typedef' defined as macro" "" { target c++26 } } +#define typeid 1 // { dg-error "keyword 'typeid' defined as macro" "" { target c++26 } } +#define typename 1 // { dg-error "keyword 'typename' defined as macro" "" { target c++26 } } +#define union 1 // { dg-error "keyword 'union' defined as macro" "" { target c++26 } } +#define unsigned 1 // { dg-error "keyword 'unsigned' defined as macro" "" { target c++26 } } +#define using 1 // { dg-error "keyword 'using' defined as macro" "" { target c++26 } } +#define virtual 1 // { dg-error "keyword 'virtual' defined as macro" "" { target c++26 } } +#define void 1 // { dg-error "keyword 'void' defined as macro" "" { target c++26 } } +#define volatile 1 // { dg-error "keyword 'volatile' defined as macro" "" { target c++26 } } +#define wchar_t 1 // { dg-error "keyword 'wchar_t' defined as macro" "" { target c++26 } } +#define while 1 // { dg-error "keyword 'while' defined as macro" "" { target c++26 } } + +// [lex.name] +#define final 1 // { dg-error "keyword 'final' defined as macro" "" { target c++26 } } +#define import 1 // { dg-error "keyword 'import' defined as macro" "" { target c++26 } } +#define module 1 // { dg-error "keyword 'module' defined as macro" "" { target c++26 } } +#define override 1 // { dg-error "keyword 'override' defined as macro" "" { target c++26 } } +#define post 1 +#define pre 1 +#define replaceable_if_eligible 1 // { dg-error "keyword 'replaceable_if_eligible' defined as macro" "" { target c++26 } } +#define trivially_relocatable_if_eligible 1 // { dg-error "keyword 'trivially_relocatable_if_eligible' defined as macro" "" { target c++26 } } + +// [dcl.attr] +#define assume 1 // { dg-error "keyword 'assume' defined as macro" "" { target c++26 } } +#define carries_dependency 1 +#define deprecated 1 // { dg-error "keyword 'deprecated' defined as macro" "" { target c++26 } } +#define fallthrough 1 // { dg-error "keyword 'fallthrough' defined as macro" "" { target c++26 } } +#define indeterminate 1 +#define likely 1 // { dg-error "keyword 'likely' defined as macro" "" { target c++26 } } +#define maybe_unused 1 // { dg-error "keyword 'maybe_unused' defined as macro" "" { target c++26 } } +#define nodiscard 1 // { dg-error "keyword 'nodiscard' defined as macro" "" { target c++26 } } +#define noreturn 1 // { dg-error "keyword 'noreturn' defined as macro" "" { target c++26 } } +#define no_unique_address 1 // { dg-error "keyword 'no_unique_address' defined as macro" "" { target c++26 } } +#define unlikely 1 // { dg-error "keyword 'unlikely' defined as macro" "" { target c++26 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-10.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-10.C new file mode 100644 index 0000000..e6fafcd --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-10.C @@ -0,0 +1,23 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro" } + +#undef for // { dg-warning "undefining keyword 'for'" } +#define for for // { dg-warning "keyword 'for' defined as macro" } +#undef for // { dg-warning "undefining keyword 'for'" } +#define while do // { dg-warning "keyword 'while' defined as macro" } +#define while do // { dg-warning "keyword 'while' defined as macro" } +#define while for // { dg-warning "keyword 'while' defined as macro" } + // { dg-warning "'while' redefined" "" { target *-*-* } .-1 } +#undef while // { dg-warning "undefining keyword 'while'" } +#define while while // { dg-warning "keyword 'while' defined as macro" } +#define private public // { dg-warning "keyword 'private' defined as macro" } +#define inline // { dg-warning "keyword 'inline' defined as macro" } +#undef inline // { dg-warning "undefining keyword 'inline'" } +#define inline __inline__ __attribute__((__always_inline__)) // { dg-warning "keyword 'inline' defined as macro" } +#define likely(a) a +#undef likely // { dg-warning "undefining keyword 'likely'" "" { target c++20 } } +#define unlikely(a, b, c) a + b + c +#define unlikely(a, b, c) a + b + c +#undef unlikely // { dg-warning "undefining keyword 'unlikely'" "" { target c++20 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-2.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-2.C new file mode 100644 index 0000000..b1a9aa2 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-2.C @@ -0,0 +1,112 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-pedantic" } +// { dg-additional-options "-fmodules" { target c++20 } } + +// [lex.key] +#define alignas 1 // { dg-warning "keyword 'alignas' defined as macro" "" { target c++26 } } +#define alignof 1 // { dg-warning "keyword 'alignof' defined as macro" "" { target c++26 } } +#define asm 1 // { dg-warning "keyword 'asm' defined as macro" "" { target c++26 } } +#define auto 1 // { dg-warning "keyword 'auto' defined as macro" "" { target c++26 } } +#define bool 1 // { dg-warning "keyword 'bool' defined as macro" "" { target c++26 } } +#define break 1 // { dg-warning "keyword 'break' defined as macro" "" { target c++26 } } +#define case 1 // { dg-warning "keyword 'case' defined as macro" "" { target c++26 } } +#define catch 1 // { dg-warning "keyword 'catch' defined as macro" "" { target c++26 } } +#define char 1 // { dg-warning "keyword 'char' defined as macro" "" { target c++26 } } +#define char16_t 1 // { dg-warning "keyword 'char16_t' defined as macro" "" { target c++26 } } +#define char32_t 1 // { dg-warning "keyword 'char32_t' defined as macro" "" { target c++26 } } +#define char8_t 1 // { dg-warning "keyword 'char8_t' defined as macro" "" { target c++26 } } +#define class 1 // { dg-warning "keyword 'class' defined as macro" "" { target c++26 } } +#define co_await 1 // { dg-warning "keyword 'co_await' defined as macro" "" { target c++26 } } +#define concept 1 // { dg-warning "keyword 'concept' defined as macro" "" { target c++26 } } +#define const 1 // { dg-warning "keyword 'const' defined as macro" "" { target c++26 } } +#define const_cast 1 // { dg-warning "keyword 'const_cast' defined as macro" "" { target c++26 } } +#define consteval 1 // { dg-warning "keyword 'consteval' defined as macro" "" { target c++26 } } +#define constexpr 1 // { dg-warning "keyword 'constexpr' defined as macro" "" { target c++26 } } +#define constinit 1 // { dg-warning "keyword 'constinit' defined as macro" "" { target c++26 } } +#define continue 1 // { dg-warning "keyword 'continue' defined as macro" "" { target c++26 } } +#define contract_assert 1 +#define co_return 1 // { dg-warning "keyword 'co_return' defined as macro" "" { target c++26 } } +#define co_yield 1 // { dg-warning "keyword 'co_yield' defined as macro" "" { target c++26 } } +#define decltype 1 // { dg-warning "keyword 'decltype' defined as macro" "" { target c++26 } } +#define default 1 // { dg-warning "keyword 'default' defined as macro" "" { target c++26 } } +#define delete 1 // { dg-warning "keyword 'delete' defined as macro" "" { target c++26 } } +#define do 1 // { dg-warning "keyword 'do' defined as macro" "" { target c++26 } } +#define double 1 // { dg-warning "keyword 'double' defined as macro" "" { target c++26 } } +#define dynamic_cast 1 // { dg-warning "keyword 'dynamic_cast' defined as macro" "" { target c++26 } } +#define else 1 // { dg-warning "keyword 'else' defined as macro" "" { target c++26 } } +#define enum 1 // { dg-warning "keyword 'enum' defined as macro" "" { target c++26 } } +#define explicit 1 // { dg-warning "keyword 'explicit' defined as macro" "" { target c++26 } } +#define export 1 // { dg-warning "keyword 'export' defined as macro" "" { target c++26 } } +#define extern 1 // { dg-warning "keyword 'extern' defined as macro" "" { target c++26 } } +#define false 1 // { dg-warning "keyword 'false' defined as macro" "" { target c++26 } } +#define float 1 // { dg-warning "keyword 'float' defined as macro" "" { target c++26 } } +#define for 1 // { dg-warning "keyword 'for' defined as macro" "" { target c++26 } } +#define friend 1 // { dg-warning "keyword 'friend' defined as macro" "" { target c++26 } } +#define goto 1 // { dg-warning "keyword 'goto' defined as macro" "" { target c++26 } } +#define if 1 // { dg-warning "keyword 'if' defined as macro" "" { target c++26 } } +#define inline 1 // { dg-warning "keyword 'inline' defined as macro" "" { target c++26 } } +#define int 1 // { dg-warning "keyword 'int' defined as macro" "" { target c++26 } } +#define long 1 // { dg-warning "keyword 'long' defined as macro" "" { target c++26 } } +#define mutable 1 // { dg-warning "keyword 'mutable' defined as macro" "" { target c++26 } } +#define namespace 1 // { dg-warning "keyword 'namespace' defined as macro" "" { target c++26 } } +#define new 1 // { dg-warning "keyword 'new' defined as macro" "" { target c++26 } } +#define noexcept 1 // { dg-warning "keyword 'noexcept' defined as macro" "" { target c++26 } } +#define nullptr 1 // { dg-warning "keyword 'nullptr' defined as macro" "" { target c++26 } } +#define operator 1 // { dg-warning "keyword 'operator' defined as macro" "" { target c++26 } } +#define private 1 // { dg-warning "keyword 'private' defined as macro" "" { target c++26 } } +#define protected 1 // { dg-warning "keyword 'protected' defined as macro" "" { target c++26 } } +#define public 1 // { dg-warning "keyword 'public' defined as macro" "" { target c++26 } } +#define register 1 // { dg-warning "keyword 'register' defined as macro" "" { target c++26 } } +#define reinterpret_cast 1 // { dg-warning "keyword 'reinterpret_cast' defined as macro" "" { target c++26 } } +#define requires 1 // { dg-warning "keyword 'requires' defined as macro" "" { target c++26 } } +#define return 1 // { dg-warning "keyword 'return' defined as macro" "" { target c++26 } } +#define short 1 // { dg-warning "keyword 'short' defined as macro" "" { target c++26 } } +#define signed 1 // { dg-warning "keyword 'signed' defined as macro" "" { target c++26 } } +#define sizeof 1 // { dg-warning "keyword 'sizeof' defined as macro" "" { target c++26 } } +#define static 1 // { dg-warning "keyword 'static' defined as macro" "" { target c++26 } } +#define static_assert 1 // { dg-warning "keyword 'static_assert' defined as macro" "" { target c++26 } } +#define static_cast 1 // { dg-warning "keyword 'static_cast' defined as macro" "" { target c++26 } } +#define struct 1 // { dg-warning "keyword 'struct' defined as macro" "" { target c++26 } } +#define switch 1 // { dg-warning "keyword 'switch' defined as macro" "" { target c++26 } } +#define template 1 // { dg-warning "keyword 'template' defined as macro" "" { target c++26 } } +#define this 1 // { dg-warning "keyword 'this' defined as macro" "" { target c++26 } } +#define thread_local 1 // { dg-warning "keyword 'thread_local' defined as macro" "" { target c++26 } } +#define throw 1 // { dg-warning "keyword 'throw' defined as macro" "" { target c++26 } } +#define true 1 // { dg-warning "keyword 'true' defined as macro" "" { target c++26 } } +#define try 1 // { dg-warning "keyword 'try' defined as macro" "" { target c++26 } } +#define typedef 1 // { dg-warning "keyword 'typedef' defined as macro" "" { target c++26 } } +#define typeid 1 // { dg-warning "keyword 'typeid' defined as macro" "" { target c++26 } } +#define typename 1 // { dg-warning "keyword 'typename' defined as macro" "" { target c++26 } } +#define union 1 // { dg-warning "keyword 'union' defined as macro" "" { target c++26 } } +#define unsigned 1 // { dg-warning "keyword 'unsigned' defined as macro" "" { target c++26 } } +#define using 1 // { dg-warning "keyword 'using' defined as macro" "" { target c++26 } } +#define virtual 1 // { dg-warning "keyword 'virtual' defined as macro" "" { target c++26 } } +#define void 1 // { dg-warning "keyword 'void' defined as macro" "" { target c++26 } } +#define volatile 1 // { dg-warning "keyword 'volatile' defined as macro" "" { target c++26 } } +#define wchar_t 1 // { dg-warning "keyword 'wchar_t' defined as macro" "" { target c++26 } } +#define while 1 // { dg-warning "keyword 'while' defined as macro" "" { target c++26 } } + +// [lex.name] +#define final 1 // { dg-warning "keyword 'final' defined as macro" "" { target c++26 } } +#define import 1 // { dg-warning "keyword 'import' defined as macro" "" { target c++26 } } +#define module 1 // { dg-warning "keyword 'module' defined as macro" "" { target c++26 } } +#define override 1 // { dg-warning "keyword 'override' defined as macro" "" { target c++26 } } +#define post 1 +#define pre 1 +#define replaceable_if_eligible 1 // { dg-warning "keyword 'replaceable_if_eligible' defined as macro" "" { target c++26 } } +#define trivially_relocatable_if_eligible 1 // { dg-warning "keyword 'trivially_relocatable_if_eligible' defined as macro" "" { target c++26 } } + +// [dcl.attr] +#define assume 1 // { dg-warning "keyword 'assume' defined as macro" "" { target c++26 } } +#define carries_dependency 1 +#define deprecated 1 // { dg-warning "keyword 'deprecated' defined as macro" "" { target c++26 } } +#define fallthrough 1 // { dg-warning "keyword 'fallthrough' defined as macro" "" { target c++26 } } +#define indeterminate 1 +#define likely 1 // { dg-warning "keyword 'likely' defined as macro" "" { target c++26 } } +#define maybe_unused 1 // { dg-warning "keyword 'maybe_unused' defined as macro" "" { target c++26 } } +#define nodiscard 1 // { dg-warning "keyword 'nodiscard' defined as macro" "" { target c++26 } } +#define noreturn 1 // { dg-warning "keyword 'noreturn' defined as macro" "" { target c++26 } } +#define no_unique_address 1 // { dg-warning "keyword 'no_unique_address' defined as macro" "" { target c++26 } } +#define unlikely 1 // { dg-warning "keyword 'unlikely' defined as macro" "" { target c++26 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-3.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-3.C new file mode 100644 index 0000000..8576b64 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-3.C @@ -0,0 +1,7 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "" } +// { dg-additional-options "-fmodules" { target c++20 } } + +#include "Wkeyword-macro-1.C" diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-4.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-4.C new file mode 100644 index 0000000..9ff974d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-4.C @@ -0,0 +1,112 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } +// { dg-additional-options "-fmodules" { target c++20 } } + +// [lex.key] +#undef alignas // { dg-error "undefining keyword 'alignas'" "" { target c++26 } } +#undef alignof // { dg-error "undefining keyword 'alignof'" "" { target c++26 } } +#undef asm // { dg-error "undefining keyword 'asm'" "" { target c++26 } } +#undef auto // { dg-error "undefining keyword 'auto'" "" { target c++26 } } +#undef bool // { dg-error "undefining keyword 'bool'" "" { target c++26 } } +#undef break // { dg-error "undefining keyword 'break'" "" { target c++26 } } +#undef case // { dg-error "undefining keyword 'case'" "" { target c++26 } } +#undef catch // { dg-error "undefining keyword 'catch'" "" { target c++26 } } +#undef char // { dg-error "undefining keyword 'char'" "" { target c++26 } } +#undef char16_t // { dg-error "undefining keyword 'char16_t'" "" { target c++26 } } +#undef char32_t // { dg-error "undefining keyword 'char32_t'" "" { target c++26 } } +#undef char8_t // { dg-error "undefining keyword 'char8_t'" "" { target c++26 } } +#undef class // { dg-error "undefining keyword 'class'" "" { target c++26 } } +#undef co_await // { dg-error "undefining keyword 'co_await'" "" { target c++26 } } +#undef concept // { dg-error "undefining keyword 'concept'" "" { target c++26 } } +#undef const // { dg-error "undefining keyword 'const'" "" { target c++26 } } +#undef const_cast // { dg-error "undefining keyword 'const_cast'" "" { target c++26 } } +#undef consteval // { dg-error "undefining keyword 'consteval'" "" { target c++26 } } +#undef constexpr // { dg-error "undefining keyword 'constexpr'" "" { target c++26 } } +#undef constinit // { dg-error "undefining keyword 'constinit'" "" { target c++26 } } +#undef continue // { dg-error "undefining keyword 'continue'" "" { target c++26 } } +#undef contract_assert +#undef co_return // { dg-error "undefining keyword 'co_return'" "" { target c++26 } } +#undef co_yield // { dg-error "undefining keyword 'co_yield'" "" { target c++26 } } +#undef decltype // { dg-error "undefining keyword 'decltype'" "" { target c++26 } } +#undef default // { dg-error "undefining keyword 'default'" "" { target c++26 } } +#undef delete // { dg-error "undefining keyword 'delete'" "" { target c++26 } } +#undef do // { dg-error "undefining keyword 'do'" "" { target c++26 } } +#undef double // { dg-error "undefining keyword 'double'" "" { target c++26 } } +#undef dynamic_cast // { dg-error "undefining keyword 'dynamic_cast'" "" { target c++26 } } +#undef else // { dg-error "undefining keyword 'else'" "" { target c++26 } } +#undef enum // { dg-error "undefining keyword 'enum'" "" { target c++26 } } +#undef explicit // { dg-error "undefining keyword 'explicit'" "" { target c++26 } } +#undef export // { dg-error "undefining keyword 'export'" "" { target c++26 } } +#undef extern // { dg-error "undefining keyword 'extern'" "" { target c++26 } } +#undef false // { dg-error "undefining keyword 'false'" "" { target c++26 } } +#undef float // { dg-error "undefining keyword 'float'" "" { target c++26 } } +#undef for // { dg-error "undefining keyword 'for'" "" { target c++26 } } +#undef friend // { dg-error "undefining keyword 'friend'" "" { target c++26 } } +#undef goto // { dg-error "undefining keyword 'goto'" "" { target c++26 } } +#undef if // { dg-error "undefining keyword 'if'" "" { target c++26 } } +#undef inline // { dg-error "undefining keyword 'inline'" "" { target c++26 } } +#undef int // { dg-error "undefining keyword 'int'" "" { target c++26 } } +#undef long // { dg-error "undefining keyword 'long'" "" { target c++26 } } +#undef mutable // { dg-error "undefining keyword 'mutable'" "" { target c++26 } } +#undef namespace // { dg-error "undefining keyword 'namespace'" "" { target c++26 } } +#undef new // { dg-error "undefining keyword 'new'" "" { target c++26 } } +#undef noexcept // { dg-error "undefining keyword 'noexcept'" "" { target c++26 } } +#undef nullptr // { dg-error "undefining keyword 'nullptr'" "" { target c++26 } } +#undef operator // { dg-error "undefining keyword 'operator'" "" { target c++26 } } +#undef private // { dg-error "undefining keyword 'private'" "" { target c++26 } } +#undef protected // { dg-error "undefining keyword 'protected'" "" { target c++26 } } +#undef public // { dg-error "undefining keyword 'public'" "" { target c++26 } } +#undef register // { dg-error "undefining keyword 'register'" "" { target c++26 } } +#undef reinterpret_cast // { dg-error "undefining keyword 'reinterpret_cast'" "" { target c++26 } } +#undef requires // { dg-error "undefining keyword 'requires'" "" { target c++26 } } +#undef return // { dg-error "undefining keyword 'return'" "" { target c++26 } } +#undef short // { dg-error "undefining keyword 'short'" "" { target c++26 } } +#undef signed // { dg-error "undefining keyword 'signed'" "" { target c++26 } } +#undef sizeof // { dg-error "undefining keyword 'sizeof'" "" { target c++26 } } +#undef static // { dg-error "undefining keyword 'static'" "" { target c++26 } } +#undef static_assert // { dg-error "undefining keyword 'static_assert'" "" { target c++26 } } +#undef static_cast // { dg-error "undefining keyword 'static_cast'" "" { target c++26 } } +#undef struct // { dg-error "undefining keyword 'struct'" "" { target c++26 } } +#undef switch // { dg-error "undefining keyword 'switch'" "" { target c++26 } } +#undef template // { dg-error "undefining keyword 'template'" "" { target c++26 } } +#undef this // { dg-error "undefining keyword 'this'" "" { target c++26 } } +#undef thread_local // { dg-error "undefining keyword 'thread_local'" "" { target c++26 } } +#undef throw // { dg-error "undefining keyword 'throw'" "" { target c++26 } } +#undef true // { dg-error "undefining keyword 'true'" "" { target c++26 } } +#undef try // { dg-error "undefining keyword 'try'" "" { target c++26 } } +#undef typedef // { dg-error "undefining keyword 'typedef'" "" { target c++26 } } +#undef typeid // { dg-error "undefining keyword 'typeid'" "" { target c++26 } } +#undef typename // { dg-error "undefining keyword 'typename'" "" { target c++26 } } +#undef union // { dg-error "undefining keyword 'union'" "" { target c++26 } } +#undef unsigned // { dg-error "undefining keyword 'unsigned'" "" { target c++26 } } +#undef using // { dg-error "undefining keyword 'using'" "" { target c++26 } } +#undef virtual // { dg-error "undefining keyword 'virtual'" "" { target c++26 } } +#undef void // { dg-error "undefining keyword 'void'" "" { target c++26 } } +#undef volatile // { dg-error "undefining keyword 'volatile'" "" { target c++26 } } +#undef wchar_t // { dg-error "undefining keyword 'wchar_t'" "" { target c++26 } } +#undef while // { dg-error "undefining keyword 'while'" "" { target c++26 } } + +// [lex.name] +#undef final // { dg-error "undefining keyword 'final'" "" { target c++26 } } +#undef import // { dg-error "undefining keyword 'import'" "" { target c++26 } } +#undef module // { dg-error "undefining keyword 'module'" "" { target c++26 } } +#undef override // { dg-error "undefining keyword 'override'" "" { target c++26 } } +#undef post +#undef pre +#undef replaceable_if_eligible // { dg-error "undefining keyword 'replaceable_if_eligible'" "" { target c++26 } } +#undef trivially_relocatable_if_eligible // { dg-error "undefining keyword 'trivially_relocatable_if_eligible'" "" { target c++26 } } + +// [dcl.attr] +#undef assume // { dg-error "undefining keyword 'assume'" "" { target c++26 } } +#undef carries_dependency +#undef deprecated // { dg-error "undefining keyword 'deprecated'" "" { target c++26 } } +#undef fallthrough // { dg-error "undefining keyword 'fallthrough'" "" { target c++26 } } +#undef indeterminate +#undef likely // { dg-error "undefining keyword 'likely'" "" { target c++26 } } +#undef maybe_unused // { dg-error "undefining keyword 'maybe_unused'" "" { target c++26 } } +#undef nodiscard // { dg-error "undefining keyword 'nodiscard'" "" { target c++26 } } +#undef noreturn // { dg-error "undefining keyword 'noreturn'" "" { target c++26 } } +#undef no_unique_address // { dg-error "undefining keyword 'no_unique_address'" "" { target c++26 } } +#undef unlikely // { dg-error "undefining keyword 'unlikely'" "" { target c++26 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-5.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-5.C new file mode 100644 index 0000000..657797b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-5.C @@ -0,0 +1,112 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-pedantic" } +// { dg-additional-options "-fmodules" { target c++20 } } + +// [lex.key] +#undef alignas // { dg-warning "undefining keyword 'alignas'" "" { target c++26 } } +#undef alignof // { dg-warning "undefining keyword 'alignof'" "" { target c++26 } } +#undef asm // { dg-warning "undefining keyword 'asm'" "" { target c++26 } } +#undef auto // { dg-warning "undefining keyword 'auto'" "" { target c++26 } } +#undef bool // { dg-warning "undefining keyword 'bool'" "" { target c++26 } } +#undef break // { dg-warning "undefining keyword 'break'" "" { target c++26 } } +#undef case // { dg-warning "undefining keyword 'case'" "" { target c++26 } } +#undef catch // { dg-warning "undefining keyword 'catch'" "" { target c++26 } } +#undef char // { dg-warning "undefining keyword 'char'" "" { target c++26 } } +#undef char16_t // { dg-warning "undefining keyword 'char16_t'" "" { target c++26 } } +#undef char32_t // { dg-warning "undefining keyword 'char32_t'" "" { target c++26 } } +#undef char8_t // { dg-warning "undefining keyword 'char8_t'" "" { target c++26 } } +#undef class // { dg-warning "undefining keyword 'class'" "" { target c++26 } } +#undef co_await // { dg-warning "undefining keyword 'co_await'" "" { target c++26 } } +#undef concept // { dg-warning "undefining keyword 'concept'" "" { target c++26 } } +#undef const // { dg-warning "undefining keyword 'const'" "" { target c++26 } } +#undef const_cast // { dg-warning "undefining keyword 'const_cast'" "" { target c++26 } } +#undef consteval // { dg-warning "undefining keyword 'consteval'" "" { target c++26 } } +#undef constexpr // { dg-warning "undefining keyword 'constexpr'" "" { target c++26 } } +#undef constinit // { dg-warning "undefining keyword 'constinit'" "" { target c++26 } } +#undef continue // { dg-warning "undefining keyword 'continue'" "" { target c++26 } } +#undef contract_assert +#undef co_return // { dg-warning "undefining keyword 'co_return'" "" { target c++26 } } +#undef co_yield // { dg-warning "undefining keyword 'co_yield'" "" { target c++26 } } +#undef decltype // { dg-warning "undefining keyword 'decltype'" "" { target c++26 } } +#undef default // { dg-warning "undefining keyword 'default'" "" { target c++26 } } +#undef delete // { dg-warning "undefining keyword 'delete'" "" { target c++26 } } +#undef do // { dg-warning "undefining keyword 'do'" "" { target c++26 } } +#undef double // { dg-warning "undefining keyword 'double'" "" { target c++26 } } +#undef dynamic_cast // { dg-warning "undefining keyword 'dynamic_cast'" "" { target c++26 } } +#undef else // { dg-warning "undefining keyword 'else'" "" { target c++26 } } +#undef enum // { dg-warning "undefining keyword 'enum'" "" { target c++26 } } +#undef explicit // { dg-warning "undefining keyword 'explicit'" "" { target c++26 } } +#undef export // { dg-warning "undefining keyword 'export'" "" { target c++26 } } +#undef extern // { dg-warning "undefining keyword 'extern'" "" { target c++26 } } +#undef false // { dg-warning "undefining keyword 'false'" "" { target c++26 } } +#undef float // { dg-warning "undefining keyword 'float'" "" { target c++26 } } +#undef for // { dg-warning "undefining keyword 'for'" "" { target c++26 } } +#undef friend // { dg-warning "undefining keyword 'friend'" "" { target c++26 } } +#undef goto // { dg-warning "undefining keyword 'goto'" "" { target c++26 } } +#undef if // { dg-warning "undefining keyword 'if'" "" { target c++26 } } +#undef inline // { dg-warning "undefining keyword 'inline'" "" { target c++26 } } +#undef int // { dg-warning "undefining keyword 'int'" "" { target c++26 } } +#undef long // { dg-warning "undefining keyword 'long'" "" { target c++26 } } +#undef mutable // { dg-warning "undefining keyword 'mutable'" "" { target c++26 } } +#undef namespace // { dg-warning "undefining keyword 'namespace'" "" { target c++26 } } +#undef new // { dg-warning "undefining keyword 'new'" "" { target c++26 } } +#undef noexcept // { dg-warning "undefining keyword 'noexcept'" "" { target c++26 } } +#undef nullptr // { dg-warning "undefining keyword 'nullptr'" "" { target c++26 } } +#undef operator // { dg-warning "undefining keyword 'operator'" "" { target c++26 } } +#undef private // { dg-warning "undefining keyword 'private'" "" { target c++26 } } +#undef protected // { dg-warning "undefining keyword 'protected'" "" { target c++26 } } +#undef public // { dg-warning "undefining keyword 'public'" "" { target c++26 } } +#undef register // { dg-warning "undefining keyword 'register'" "" { target c++26 } } +#undef reinterpret_cast // { dg-warning "undefining keyword 'reinterpret_cast'" "" { target c++26 } } +#undef requires // { dg-warning "undefining keyword 'requires'" "" { target c++26 } } +#undef return // { dg-warning "undefining keyword 'return'" "" { target c++26 } } +#undef short // { dg-warning "undefining keyword 'short'" "" { target c++26 } } +#undef signed // { dg-warning "undefining keyword 'signed'" "" { target c++26 } } +#undef sizeof // { dg-warning "undefining keyword 'sizeof'" "" { target c++26 } } +#undef static // { dg-warning "undefining keyword 'static'" "" { target c++26 } } +#undef static_assert // { dg-warning "undefining keyword 'static_assert'" "" { target c++26 } } +#undef static_cast // { dg-warning "undefining keyword 'static_cast'" "" { target c++26 } } +#undef struct // { dg-warning "undefining keyword 'struct'" "" { target c++26 } } +#undef switch // { dg-warning "undefining keyword 'switch'" "" { target c++26 } } +#undef template // { dg-warning "undefining keyword 'template'" "" { target c++26 } } +#undef this // { dg-warning "undefining keyword 'this'" "" { target c++26 } } +#undef thread_local // { dg-warning "undefining keyword 'thread_local'" "" { target c++26 } } +#undef throw // { dg-warning "undefining keyword 'throw'" "" { target c++26 } } +#undef true // { dg-warning "undefining keyword 'true'" "" { target c++26 } } +#undef try // { dg-warning "undefining keyword 'try'" "" { target c++26 } } +#undef typedef // { dg-warning "undefining keyword 'typedef'" "" { target c++26 } } +#undef typeid // { dg-warning "undefining keyword 'typeid'" "" { target c++26 } } +#undef typename // { dg-warning "undefining keyword 'typename'" "" { target c++26 } } +#undef union // { dg-warning "undefining keyword 'union'" "" { target c++26 } } +#undef unsigned // { dg-warning "undefining keyword 'unsigned'" "" { target c++26 } } +#undef using // { dg-warning "undefining keyword 'using'" "" { target c++26 } } +#undef virtual // { dg-warning "undefining keyword 'virtual'" "" { target c++26 } } +#undef void // { dg-warning "undefining keyword 'void'" "" { target c++26 } } +#undef volatile // { dg-warning "undefining keyword 'volatile'" "" { target c++26 } } +#undef wchar_t // { dg-warning "undefining keyword 'wchar_t'" "" { target c++26 } } +#undef while // { dg-warning "undefining keyword 'while'" "" { target c++26 } } + +// [lex.name] +#undef final // { dg-warning "undefining keyword 'final'" "" { target c++26 } } +#undef import // { dg-warning "undefining keyword 'import'" "" { target c++26 } } +#undef module // { dg-warning "undefining keyword 'module'" "" { target c++26 } } +#undef override // { dg-warning "undefining keyword 'override'" "" { target c++26 } } +#undef post +#undef pre +#undef replaceable_if_eligible // { dg-warning "undefining keyword 'replaceable_if_eligible'" "" { target c++26 } } +#undef trivially_relocatable_if_eligible // { dg-warning "undefining keyword 'trivially_relocatable_if_eligible'" "" { target c++26 } } + +// [dcl.attr] +#undef assume // { dg-warning "undefining keyword 'assume'" "" { target c++26 } } +#undef carries_dependency +#undef deprecated // { dg-warning "undefining keyword 'deprecated'" "" { target c++26 } } +#undef fallthrough // { dg-warning "undefining keyword 'fallthrough'" "" { target c++26 } } +#undef indeterminate +#undef likely // { dg-warning "undefining keyword 'likely'" "" { target c++26 } } +#undef maybe_unused // { dg-warning "undefining keyword 'maybe_unused'" "" { target c++26 } } +#undef nodiscard // { dg-warning "undefining keyword 'nodiscard'" "" { target c++26 } } +#undef noreturn // { dg-warning "undefining keyword 'noreturn'" "" { target c++26 } } +#undef no_unique_address // { dg-warning "undefining keyword 'no_unique_address'" "" { target c++26 } } +#undef unlikely // { dg-warning "undefining keyword 'unlikely'" "" { target c++26 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-6.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-6.C new file mode 100644 index 0000000..881df8b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-6.C @@ -0,0 +1,7 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "" } +// { dg-additional-options "-fmodules" { target c++20 } } + +#include "Wkeyword-macro-4.C" diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-7.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-7.C new file mode 100644 index 0000000..30a2c8d --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-7.C @@ -0,0 +1,112 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro" } +// { dg-additional-options "-fmodules" { target c++20 } } + +// [lex.key] +#define alignas 1 // { dg-warning "keyword 'alignas' defined as macro" "" { target c++11 } } +#define alignof 1 // { dg-warning "keyword 'alignof' defined as macro" "" { target c++11 } } +#define asm 1 // { dg-warning "keyword 'asm' defined as macro" } +#define auto 1 // { dg-warning "keyword 'auto' defined as macro" } +#define bool 1 // { dg-warning "keyword 'bool' defined as macro" } +#define break 1 // { dg-warning "keyword 'break' defined as macro" } +#define case 1 // { dg-warning "keyword 'case' defined as macro" } +#define catch 1 // { dg-warning "keyword 'catch' defined as macro" } +#define char 1 // { dg-warning "keyword 'char' defined as macro" } +#define char16_t 1 // { dg-warning "keyword 'char16_t' defined as macro" "" { target c++11 } } +#define char32_t 1 // { dg-warning "keyword 'char32_t' defined as macro" "" { target c++11 } } +#define char8_t 1 // { dg-warning "keyword 'char8_t' defined as macro" "" { target c++20 } } +#define class 1 // { dg-warning "keyword 'class' defined as macro" } +#define co_await 1 // { dg-warning "keyword 'co_await' defined as macro" "" { target c++20 } } +#define concept 1 // { dg-warning "keyword 'concept' defined as macro" "" { target c++20 } } +#define const 1 // { dg-warning "keyword 'const' defined as macro" } +#define const_cast 1 // { dg-warning "keyword 'const_cast' defined as macro" } +#define consteval 1 // { dg-warning "keyword 'consteval' defined as macro" "" { target c++20 } } +#define constexpr 1 // { dg-warning "keyword 'constexpr' defined as macro" "" { target c++11 } } +#define constinit 1 // { dg-warning "keyword 'constinit' defined as macro" "" { target c++20 } } +#define continue 1 // { dg-warning "keyword 'continue' defined as macro" } +#define contract_assert 1 +#define co_return 1 // { dg-warning "keyword 'co_return' defined as macro" "" { target c++20 } } +#define co_yield 1 // { dg-warning "keyword 'co_yield' defined as macro" "" { target c++20 } } +#define decltype 1 // { dg-warning "keyword 'decltype' defined as macro" "" { target c++11 } } +#define default 1 // { dg-warning "keyword 'default' defined as macro" } +#define delete 1 // { dg-warning "keyword 'delete' defined as macro" } +#define do 1 // { dg-warning "keyword 'do' defined as macro" } +#define double 1 // { dg-warning "keyword 'double' defined as macro" } +#define dynamic_cast 1 // { dg-warning "keyword 'dynamic_cast' defined as macro" } +#define else 1 // { dg-warning "keyword 'else' defined as macro" } +#define enum 1 // { dg-warning "keyword 'enum' defined as macro" } +#define explicit 1 // { dg-warning "keyword 'explicit' defined as macro" } +#define export 1 // { dg-warning "keyword 'export' defined as macro" } +#define extern 1 // { dg-warning "keyword 'extern' defined as macro" } +#define false 1 // { dg-warning "keyword 'false' defined as macro" } +#define float 1 // { dg-warning "keyword 'float' defined as macro" } +#define for 1 // { dg-warning "keyword 'for' defined as macro" } +#define friend 1 // { dg-warning "keyword 'friend' defined as macro" } +#define goto 1 // { dg-warning "keyword 'goto' defined as macro" } +#define if 1 // { dg-warning "keyword 'if' defined as macro" } +#define inline 1 // { dg-warning "keyword 'inline' defined as macro" } +#define int 1 // { dg-warning "keyword 'int' defined as macro" } +#define long 1 // { dg-warning "keyword 'long' defined as macro" } +#define mutable 1 // { dg-warning "keyword 'mutable' defined as macro" } +#define namespace 1 // { dg-warning "keyword 'namespace' defined as macro" } +#define new 1 // { dg-warning "keyword 'new' defined as macro" } +#define noexcept 1 // { dg-warning "keyword 'noexcept' defined as macro" "" { target c++11 } } +#define nullptr 1 // { dg-warning "keyword 'nullptr' defined as macro" "" { target c++11 } } +#define operator 1 // { dg-warning "keyword 'operator' defined as macro" } +#define private 1 // { dg-warning "keyword 'private' defined as macro" } +#define protected 1 // { dg-warning "keyword 'protected' defined as macro" } +#define public 1 // { dg-warning "keyword 'public' defined as macro" } +#define register 1 // { dg-warning "keyword 'register' defined as macro" } +#define reinterpret_cast 1 // { dg-warning "keyword 'reinterpret_cast' defined as macro" } +#define requires 1 // { dg-warning "keyword 'requires' defined as macro" "" { target c++20 } } +#define return 1 // { dg-warning "keyword 'return' defined as macro" } +#define short 1 // { dg-warning "keyword 'short' defined as macro" } +#define signed 1 // { dg-warning "keyword 'signed' defined as macro" } +#define sizeof 1 // { dg-warning "keyword 'sizeof' defined as macro" } +#define static 1 // { dg-warning "keyword 'static' defined as macro" } +#define static_assert 1 // { dg-warning "keyword 'static_assert' defined as macro" "" { target c++11 } } +#define static_cast 1 // { dg-warning "keyword 'static_cast' defined as macro" } +#define struct 1 // { dg-warning "keyword 'struct' defined as macro" } +#define switch 1 // { dg-warning "keyword 'switch' defined as macro" } +#define template 1 // { dg-warning "keyword 'template' defined as macro" } +#define this 1 // { dg-warning "keyword 'this' defined as macro" } +#define thread_local 1 // { dg-warning "keyword 'thread_local' defined as macro" "" { target c++11 } } +#define throw 1 // { dg-warning "keyword 'throw' defined as macro" } +#define true 1 // { dg-warning "keyword 'true' defined as macro" } +#define try 1 // { dg-warning "keyword 'try' defined as macro" } +#define typedef 1 // { dg-warning "keyword 'typedef' defined as macro" } +#define typeid 1 // { dg-warning "keyword 'typeid' defined as macro" } +#define typename 1 // { dg-warning "keyword 'typename' defined as macro" } +#define union 1 // { dg-warning "keyword 'union' defined as macro" } +#define unsigned 1 // { dg-warning "keyword 'unsigned' defined as macro" } +#define using 1 // { dg-warning "keyword 'using' defined as macro" } +#define virtual 1 // { dg-warning "keyword 'virtual' defined as macro" } +#define void 1 // { dg-warning "keyword 'void' defined as macro" } +#define volatile 1 // { dg-warning "keyword 'volatile' defined as macro" } +#define wchar_t 1 // { dg-warning "keyword 'wchar_t' defined as macro" } +#define while 1 // { dg-warning "keyword 'while' defined as macro" } + +// [lex.name] +#define final 1 // { dg-warning "keyword 'final' defined as macro" "" { target c++11 } } +#define import 1 // { dg-warning "keyword 'import' defined as macro" "" { target c++20 } } +#define module 1 // { dg-warning "keyword 'module' defined as macro" "" { target c++20 } } +#define override 1 // { dg-warning "keyword 'override' defined as macro" "" { target c++11 } } +#define post 1 +#define pre 1 +#define replaceable_if_eligible 1 // { dg-warning "keyword 'replaceable_if_eligible' defined as macro" "" { target c++26 } } +#define trivially_relocatable_if_eligible 1 // { dg-warning "keyword 'trivially_relocatable_if_eligible' defined as macro" "" { target c++26 } } + +// [dcl.attr] +#define assume 1 // { dg-warning "keyword 'assume' defined as macro" "" { target c++23 } } +#define carries_dependency 1 // { dg-warning "keyword 'carries_dependency' defined as macro" "" { target { c++11 && c++23_down } } } +#define deprecated 1 // { dg-warning "keyword 'deprecated' defined as macro" "" { target c++14 } } +#define fallthrough 1 // { dg-warning "keyword 'fallthrough' defined as macro" "" { target c++17 } } +#define indeterminate 1 +#define likely 1 // { dg-warning "keyword 'likely' defined as macro" "" { target c++20 } } +#define maybe_unused 1 // { dg-warning "keyword 'maybe_unused' defined as macro" "" { target c++17 } } +#define nodiscard 1 // { dg-warning "keyword 'nodiscard' defined as macro" "" { target c++17 } } +#define noreturn 1 // { dg-warning "keyword 'noreturn' defined as macro" "" { target c++11 } } +#define no_unique_address 1 // { dg-warning "keyword 'no_unique_address' defined as macro" "" { target c++20 } } +#define unlikely 1 // { dg-warning "keyword 'unlikely' defined as macro" "" { target c++20 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-8.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-8.C new file mode 100644 index 0000000..7dcc377 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-8.C @@ -0,0 +1,112 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro" } +// { dg-additional-options "-fmodules" { target c++20 } } + +// [lex.key] +#undef alignas // { dg-warning "undefining keyword 'alignas'" "" { target c++11 } } +#undef alignof // { dg-warning "undefining keyword 'alignof'" "" { target c++11 } } +#undef asm // { dg-warning "undefining keyword 'asm'" } +#undef auto // { dg-warning "undefining keyword 'auto'" } +#undef bool // { dg-warning "undefining keyword 'bool'" } +#undef break // { dg-warning "undefining keyword 'break'" } +#undef case // { dg-warning "undefining keyword 'case'" } +#undef catch // { dg-warning "undefining keyword 'catch'" } +#undef char // { dg-warning "undefining keyword 'char'" } +#undef char16_t // { dg-warning "undefining keyword 'char16_t'" "" { target c++11 } } +#undef char32_t // { dg-warning "undefining keyword 'char32_t'" "" { target c++11 } } +#undef char8_t // { dg-warning "undefining keyword 'char8_t'" "" { target c++20 } } +#undef class // { dg-warning "undefining keyword 'class'" } +#undef co_await // { dg-warning "undefining keyword 'co_await'" "" { target c++20 } } +#undef concept // { dg-warning "undefining keyword 'concept'" "" { target c++20 } } +#undef const // { dg-warning "undefining keyword 'const'" } +#undef const_cast // { dg-warning "undefining keyword 'const_cast'" } +#undef consteval // { dg-warning "undefining keyword 'consteval'" "" { target c++20 } } +#undef constexpr // { dg-warning "undefining keyword 'constexpr'" "" { target c++11 } } +#undef constinit // { dg-warning "undefining keyword 'constinit'" "" { target c++20 } } +#undef continue // { dg-warning "undefining keyword 'continue'" } +#undef contract_assert +#undef co_return // { dg-warning "undefining keyword 'co_return'" "" { target c++20 } } +#undef co_yield // { dg-warning "undefining keyword 'co_yield'" "" { target c++20 } } +#undef decltype // { dg-warning "undefining keyword 'decltype'" "" { target c++11 } } +#undef default // { dg-warning "undefining keyword 'default'" } +#undef delete // { dg-warning "undefining keyword 'delete'" } +#undef do // { dg-warning "undefining keyword 'do'" } +#undef double // { dg-warning "undefining keyword 'double'" } +#undef dynamic_cast // { dg-warning "undefining keyword 'dynamic_cast'" } +#undef else // { dg-warning "undefining keyword 'else'" } +#undef enum // { dg-warning "undefining keyword 'enum'" } +#undef explicit // { dg-warning "undefining keyword 'explicit'" } +#undef export // { dg-warning "undefining keyword 'export'" } +#undef extern // { dg-warning "undefining keyword 'extern'" } +#undef false // { dg-warning "undefining keyword 'false'" } +#undef float // { dg-warning "undefining keyword 'float'" } +#undef for // { dg-warning "undefining keyword 'for'" } +#undef friend // { dg-warning "undefining keyword 'friend'" } +#undef goto // { dg-warning "undefining keyword 'goto'" } +#undef if // { dg-warning "undefining keyword 'if'" } +#undef inline // { dg-warning "undefining keyword 'inline'" } +#undef int // { dg-warning "undefining keyword 'int'" } +#undef long // { dg-warning "undefining keyword 'long'" } +#undef mutable // { dg-warning "undefining keyword 'mutable'" } +#undef namespace // { dg-warning "undefining keyword 'namespace'" } +#undef new // { dg-warning "undefining keyword 'new'" } +#undef noexcept // { dg-warning "undefining keyword 'noexcept'" "" { target c++11 } } +#undef nullptr // { dg-warning "undefining keyword 'nullptr'" "" { target c++11 } } +#undef operator // { dg-warning "undefining keyword 'operator'" } +#undef private // { dg-warning "undefining keyword 'private'" } +#undef protected // { dg-warning "undefining keyword 'protected'" } +#undef public // { dg-warning "undefining keyword 'public'" } +#undef register // { dg-warning "undefining keyword 'register'" } +#undef reinterpret_cast // { dg-warning "undefining keyword 'reinterpret_cast'" } +#undef requires // { dg-warning "undefining keyword 'requires'" "" { target c++20 } } +#undef return // { dg-warning "undefining keyword 'return'" } +#undef short // { dg-warning "undefining keyword 'short'" } +#undef signed // { dg-warning "undefining keyword 'signed'" } +#undef sizeof // { dg-warning "undefining keyword 'sizeof'" } +#undef static // { dg-warning "undefining keyword 'static'" } +#undef static_assert // { dg-warning "undefining keyword 'static_assert'" "" { target c++11 } } +#undef static_cast // { dg-warning "undefining keyword 'static_cast'" } +#undef struct // { dg-warning "undefining keyword 'struct'" } +#undef switch // { dg-warning "undefining keyword 'switch'" } +#undef template // { dg-warning "undefining keyword 'template'" } +#undef this // { dg-warning "undefining keyword 'this'" } +#undef thread_local // { dg-warning "undefining keyword 'thread_local'" "" { target c++11 } } +#undef throw // { dg-warning "undefining keyword 'throw'" } +#undef true // { dg-warning "undefining keyword 'true'" } +#undef try // { dg-warning "undefining keyword 'try'" } +#undef typedef // { dg-warning "undefining keyword 'typedef'" } +#undef typeid // { dg-warning "undefining keyword 'typeid'" } +#undef typename // { dg-warning "undefining keyword 'typename'" } +#undef union // { dg-warning "undefining keyword 'union'" } +#undef unsigned // { dg-warning "undefining keyword 'unsigned'" } +#undef using // { dg-warning "undefining keyword 'using'" } +#undef virtual // { dg-warning "undefining keyword 'virtual'" } +#undef void // { dg-warning "undefining keyword 'void'" } +#undef volatile // { dg-warning "undefining keyword 'volatile'" } +#undef wchar_t // { dg-warning "undefining keyword 'wchar_t'" } +#undef while // { dg-warning "undefining keyword 'while'" } + +// [lex.name] +#undef final // { dg-warning "undefining keyword 'final'" "" { target c++11 } } +#undef import // { dg-warning "undefining keyword 'import'" "" { target c++20 } } +#undef module // { dg-warning "undefining keyword 'module'" "" { target c++20 } } +#undef override // { dg-warning "undefining keyword 'override'" "" { target c++11 } } +#undef post +#undef pre +#undef replaceable_if_eligible // { dg-warning "undefining keyword 'replaceable_if_eligible'" "" { target c++26 } } +#undef trivially_relocatable_if_eligible // { dg-warning "undefining keyword 'trivially_relocatable_if_eligible'" "" { target c++26 } } + +// [dcl.attr] +#undef assume // { dg-warning "undefining keyword 'assume'" "" { target c++23 } } +#undef carries_dependency // { dg-warning "undefining keyword 'carries_dependency'" "" { target { c++11 && c++23_down } } } +#undef deprecated // { dg-warning "undefining keyword 'deprecated'" "" { target c++14 } } +#undef fallthrough // { dg-warning "undefining keyword 'fallthrough'" "" { target c++17 } } +#undef indeterminate +#undef likely // { dg-warning "undefining keyword 'likely'" "" { target c++20 } } +#undef maybe_unused // { dg-warning "undefining keyword 'maybe_unused'" "" { target c++17 } } +#undef nodiscard // { dg-warning "undefining keyword 'nodiscard'" "" { target c++17 } } +#undef noreturn // { dg-warning "undefining keyword 'noreturn'" "" { target c++11 } } +#undef no_unique_address // { dg-warning "undefining keyword 'no_unique_address'" "" { target c++20 } } +#undef unlikely // { dg-warning "undefining keyword 'unlikely'" "" { target c++20 } } diff --git a/gcc/testsuite/g++.dg/warn/Wkeyword-macro-9.C b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-9.C new file mode 100644 index 0000000..741cdee --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wkeyword-macro-9.C @@ -0,0 +1,22 @@ +// C++26 P2843R3 - Preprocessing is never undefined +// [cpp.replace.general]/9 +// { dg-do preprocess } +// { dg-options "-pedantic-errors" } + +#undef for // { dg-error "undefining keyword 'for'" "" { target c++26 } } +#define for for // { dg-error "keyword 'for' defined as macro" "" { target c++26 } } +#undef for // { dg-error "undefining keyword 'for'" "" { target c++26 } } +#define while do // { dg-error "keyword 'while' defined as macro" "" { target c++26 } } +#define while do // { dg-error "keyword 'while' defined as macro" "" { target c++26 } } +#define while for // { dg-error "keyword 'while' defined as macro" "" { target c++26 } } + // { dg-error "'while' redefined" "" { target *-*-* } .-1 } +#undef while // { dg-error "undefining keyword 'while'" "" { target c++26 } } +#define while while // { dg-error "keyword 'while' defined as macro" "" { target c++26 } } +#define private public // { dg-error "keyword 'private' defined as macro" "" { target c++26 } } +#define inline // { dg-error "keyword 'inline' defined as macro" "" { target c++26 } } +#undef inline // { dg-error "undefining keyword 'inline'" "" { target c++26 } } +#define inline __inline__ __attribute__((__always_inline__)) // { dg-error "keyword 'inline' defined as macro" "" { target c++26 } } +#define likely(a) a +#undef likely // { dg-error "undefining keyword 'likely'" "" { target c++26 } } +#define unlikely(a, b, c) a + b + c +#define unlikely(a, b, c) a + b + c diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-1.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-1.c new file mode 100644 index 0000000..0b2d78f --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-1.c @@ -0,0 +1,62 @@ +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro -std=c23" } + +#define _Alignas 1 // { dg-warning "keyword '_Alignas' defined as macro" } +#define _Alignof 1 // { dg-warning "keyword '_Alignof' defined as macro" } +#define _Atomic 1 // { dg-warning "keyword '_Atomic' defined as macro" } +#define _BitInt 1 // { dg-warning "keyword '_BitInt' defined as macro" } +#define _Bool 1 // { dg-warning "keyword '_Bool' defined as macro" } +#define _Complex 1 // { dg-warning "keyword '_Complex' defined as macro" } +#define _Decimal128 1 // { dg-warning "keyword '_Decimal128' defined as macro" } +#define _Decimal32 1 // { dg-warning "keyword '_Decimal32' defined as macro" } +#define _Decimal64 1 // { dg-warning "keyword '_Decimal64' defined as macro" } +#define _Generic 1 // { dg-warning "keyword '_Generic' defined as macro" } +#define _Imaginary 1 // { dg-warning "keyword '_Imaginary' defined as macro" } +#define _Noreturn 1 // { dg-warning "keyword '_Noreturn' defined as macro" } +#define _Static_assert 1 // { dg-warning "keyword '_Static_assert' defined as macro" } +#define _Thread_local 1 // { dg-warning "keyword '_Thread_local' defined as macro" } +#define alignas 1 // { dg-warning "keyword 'alignas' defined as macro" } +#define alignof 1 // { dg-warning "keyword 'alignof' defined as macro" } +#define auto 1 // { dg-warning "keyword 'auto' defined as macro" } +#define bool 1 // { dg-warning "keyword 'bool' defined as macro" } +#define break 1 // { dg-warning "keyword 'break' defined as macro" } +#define case 1 // { dg-warning "keyword 'case' defined as macro" } +#define char 1 // { dg-warning "keyword 'char' defined as macro" } +#define const 1 // { dg-warning "keyword 'const' defined as macro" } +#define constexpr 1 // { dg-warning "keyword 'constexpr' defined as macro" } +#define continue 1 // { dg-warning "keyword 'continue' defined as macro" } +#define default 1 // { dg-warning "keyword 'default' defined as macro" } +#define do 1 // { dg-warning "keyword 'do' defined as macro" } +#define double 1 // { dg-warning "keyword 'double' defined as macro" } +#define else 1 // { dg-warning "keyword 'else' defined as macro" } +#define enum 1 // { dg-warning "keyword 'enum' defined as macro" } +#define extern 1 // { dg-warning "keyword 'extern' defined as macro" } +#define false 1 // { dg-warning "keyword 'false' defined as macro" } +#define float 1 // { dg-warning "keyword 'float' defined as macro" } +#define for 1 // { dg-warning "keyword 'for' defined as macro" } +#define goto 1 // { dg-warning "keyword 'goto' defined as macro" } +#define if 1 // { dg-warning "keyword 'if' defined as macro" } +#define inline 1 // { dg-warning "keyword 'inline' defined as macro" } +#define int 1 // { dg-warning "keyword 'int' defined as macro" } +#define long 1 // { dg-warning "keyword 'long' defined as macro" } +#define nullptr 1 // { dg-warning "keyword 'nullptr' defined as macro" } +#define register 1 // { dg-warning "keyword 'register' defined as macro" } +#define restrict 1 // { dg-warning "keyword 'restrict' defined as macro" } +#define return 1 // { dg-warning "keyword 'return' defined as macro" } +#define short 1 // { dg-warning "keyword 'short' defined as macro" } +#define signed 1 // { dg-warning "keyword 'signed' defined as macro" } +#define sizeof 1 // { dg-warning "keyword 'sizeof' defined as macro" } +#define static 1 // { dg-warning "keyword 'static' defined as macro" } +#define static_assert 1 // { dg-warning "keyword 'static_assert' defined as macro" } +#define struct 1 // { dg-warning "keyword 'struct' defined as macro" } +#define switch 1 // { dg-warning "keyword 'switch' defined as macro" } +#define thread_local 1 // { dg-warning "keyword 'thread_local' defined as macro" } +#define true 1 // { dg-warning "keyword 'true' defined as macro" } +#define typedef 1 // { dg-warning "keyword 'typedef' defined as macro" } +#define typeof 1 // { dg-warning "keyword 'typeof' defined as macro" } +#define typeof_unqual 1 // { dg-warning "keyword 'typeof_unqual' defined as macro" } +#define union 1 // { dg-warning "keyword 'union' defined as macro" } +#define unsigned 1 // { dg-warning "keyword 'unsigned' defined as macro" } +#define void 1 // { dg-warning "keyword 'void' defined as macro" } +#define volatile 1 // { dg-warning "keyword 'volatile' defined as macro" } +#define while 1 // { dg-warning "keyword 'while' defined as macro" } diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-2.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-2.c new file mode 100644 index 0000000..329a55a --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-2.c @@ -0,0 +1,4 @@ +// { dg-do preprocess } +// { dg-options "-std=c23" } + +#include "Wkeyword-macro-1.c" diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-3.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-3.c new file mode 100644 index 0000000..f631b8e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-3.c @@ -0,0 +1,62 @@ +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro -std=c23" } + +#undef _Alignas // { dg-warning "undefining keyword '_Alignas'" } +#undef _Alignof // { dg-warning "undefining keyword '_Alignof'" } +#undef _Atomic // { dg-warning "undefining keyword '_Atomic'" } +#undef _BitInt // { dg-warning "undefining keyword '_BitInt'" } +#undef _Bool // { dg-warning "undefining keyword '_Bool'" } +#undef _Complex // { dg-warning "undefining keyword '_Complex'" } +#undef _Decimal128 // { dg-warning "undefining keyword '_Decimal128'" } +#undef _Decimal32 // { dg-warning "undefining keyword '_Decimal32'" } +#undef _Decimal64 // { dg-warning "undefining keyword '_Decimal64'" } +#undef _Generic // { dg-warning "undefining keyword '_Generic'" } +#undef _Imaginary // { dg-warning "undefining keyword '_Imaginary'" } +#undef _Noreturn // { dg-warning "undefining keyword '_Noreturn'" } +#undef _Static_assert // { dg-warning "undefining keyword '_Static_assert'" } +#undef _Thread_local // { dg-warning "undefining keyword '_Thread_local'" } +#undef alignas // { dg-warning "undefining keyword 'alignas'" } +#undef alignof // { dg-warning "undefining keyword 'alignof'" } +#undef auto // { dg-warning "undefining keyword 'auto'" } +#undef bool // { dg-warning "undefining keyword 'bool'" } +#undef break // { dg-warning "undefining keyword 'break'" } +#undef case // { dg-warning "undefining keyword 'case'" } +#undef char // { dg-warning "undefining keyword 'char'" } +#undef const // { dg-warning "undefining keyword 'const'" } +#undef constexpr // { dg-warning "undefining keyword 'constexpr'" } +#undef continue // { dg-warning "undefining keyword 'continue'" } +#undef default // { dg-warning "undefining keyword 'default'" } +#undef do // { dg-warning "undefining keyword 'do'" } +#undef double // { dg-warning "undefining keyword 'double'" } +#undef else // { dg-warning "undefining keyword 'else'" } +#undef enum // { dg-warning "undefining keyword 'enum'" } +#undef extern // { dg-warning "undefining keyword 'extern'" } +#undef false // { dg-warning "undefining keyword 'false'" } +#undef float // { dg-warning "undefining keyword 'float'" } +#undef for // { dg-warning "undefining keyword 'for'" } +#undef goto // { dg-warning "undefining keyword 'goto'" } +#undef if // { dg-warning "undefining keyword 'if'" } +#undef inline // { dg-warning "undefining keyword 'inline'" } +#undef int // { dg-warning "undefining keyword 'int'" } +#undef long // { dg-warning "undefining keyword 'long'" } +#undef nullptr // { dg-warning "undefining keyword 'nullptr'" } +#undef register // { dg-warning "undefining keyword 'register'" } +#undef restrict // { dg-warning "undefining keyword 'restrict'" } +#undef return // { dg-warning "undefining keyword 'return'" } +#undef short // { dg-warning "undefining keyword 'short'" } +#undef signed // { dg-warning "undefining keyword 'signed'" } +#undef sizeof // { dg-warning "undefining keyword 'sizeof'" } +#undef static // { dg-warning "undefining keyword 'static'" } +#undef static_assert // { dg-warning "undefining keyword 'static_assert'" } +#undef struct // { dg-warning "undefining keyword 'struct'" } +#undef switch // { dg-warning "undefining keyword 'switch'" } +#undef thread_local // { dg-warning "undefining keyword 'thread_local'" } +#undef true // { dg-warning "undefining keyword 'true'" } +#undef typedef // { dg-warning "undefining keyword 'typedef'" } +#undef typeof // { dg-warning "undefining keyword 'typeof'" } +#undef typeof_unqual // { dg-warning "undefining keyword 'typeof_unqual'" } +#undef union // { dg-warning "undefining keyword 'union'" } +#undef unsigned // { dg-warning "undefining keyword 'unsigned'" } +#undef void // { dg-warning "undefining keyword 'void'" } +#undef volatile // { dg-warning "undefining keyword 'volatile'" } +#undef while // { dg-warning "undefining keyword 'while'" } diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-4.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-4.c new file mode 100644 index 0000000..796d654 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-4.c @@ -0,0 +1,4 @@ +// { dg-do preprocess } +// { dg-options "-std=c23" } + +#include "Wkeyword-macro-3.c" diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-5.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-5.c new file mode 100644 index 0000000..c61a1ce --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-5.c @@ -0,0 +1,47 @@ +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro -std=c17" } + +#define _Alignas 1 // { dg-warning "keyword '_Alignas' defined as macro" } +#define _Alignof 1 // { dg-warning "keyword '_Alignof' defined as macro" } +#define _Atomic 1 // { dg-warning "keyword '_Atomic' defined as macro" } +#define _Bool 1 // { dg-warning "keyword '_Bool' defined as macro" } +#define _Complex 1 // { dg-warning "keyword '_Complex' defined as macro" } +#define _Generic 1 // { dg-warning "keyword '_Generic' defined as macro" } +#define _Imaginary 1 // { dg-warning "keyword '_Imaginary' defined as macro" } +#define _Noreturn 1 // { dg-warning "keyword '_Noreturn' defined as macro" } +#define _Static_assert 1 // { dg-warning "keyword '_Static_assert' defined as macro" } +#define _Thread_local 1 // { dg-warning "keyword '_Thread_local' defined as macro" } +#define auto 1 // { dg-warning "keyword 'auto' defined as macro" } +#define break 1 // { dg-warning "keyword 'break' defined as macro" } +#define case 1 // { dg-warning "keyword 'case' defined as macro" } +#define char 1 // { dg-warning "keyword 'char' defined as macro" } +#define const 1 // { dg-warning "keyword 'const' defined as macro" } +#define continue 1 // { dg-warning "keyword 'continue' defined as macro" } +#define default 1 // { dg-warning "keyword 'default' defined as macro" } +#define do 1 // { dg-warning "keyword 'do' defined as macro" } +#define double 1 // { dg-warning "keyword 'double' defined as macro" } +#define else 1 // { dg-warning "keyword 'else' defined as macro" } +#define enum 1 // { dg-warning "keyword 'enum' defined as macro" } +#define extern 1 // { dg-warning "keyword 'extern' defined as macro" } +#define float 1 // { dg-warning "keyword 'float' defined as macro" } +#define for 1 // { dg-warning "keyword 'for' defined as macro" } +#define goto 1 // { dg-warning "keyword 'goto' defined as macro" } +#define if 1 // { dg-warning "keyword 'if' defined as macro" } +#define inline 1 // { dg-warning "keyword 'inline' defined as macro" } +#define int 1 // { dg-warning "keyword 'int' defined as macro" } +#define long 1 // { dg-warning "keyword 'long' defined as macro" } +#define register 1 // { dg-warning "keyword 'register' defined as macro" } +#define restrict 1 // { dg-warning "keyword 'restrict' defined as macro" } +#define return 1 // { dg-warning "keyword 'return' defined as macro" } +#define short 1 // { dg-warning "keyword 'short' defined as macro" } +#define signed 1 // { dg-warning "keyword 'signed' defined as macro" } +#define sizeof 1 // { dg-warning "keyword 'sizeof' defined as macro" } +#define static 1 // { dg-warning "keyword 'static' defined as macro" } +#define struct 1 // { dg-warning "keyword 'struct' defined as macro" } +#define switch 1 // { dg-warning "keyword 'switch' defined as macro" } +#define typedef 1 // { dg-warning "keyword 'typedef' defined as macro" } +#define union 1 // { dg-warning "keyword 'union' defined as macro" } +#define unsigned 1 // { dg-warning "keyword 'unsigned' defined as macro" } +#define void 1 // { dg-warning "keyword 'void' defined as macro" } +#define volatile 1 // { dg-warning "keyword 'volatile' defined as macro" } +#define while 1 // { dg-warning "keyword 'while' defined as macro" } diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-6.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-6.c new file mode 100644 index 0000000..760ece6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-6.c @@ -0,0 +1,4 @@ +// { dg-do preprocess } +// { dg-options "-std=c17" } + +#include "Wkeyword-macro-5.c" diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-7.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-7.c new file mode 100644 index 0000000..dc146d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-7.c @@ -0,0 +1,47 @@ +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro -std=c17" } + +#undef _Alignas // { dg-warning "undefining keyword '_Alignas'" } +#undef _Alignof // { dg-warning "undefining keyword '_Alignof'" } +#undef _Atomic // { dg-warning "undefining keyword '_Atomic'" } +#undef _Bool // { dg-warning "undefining keyword '_Bool'" } +#undef _Complex // { dg-warning "undefining keyword '_Complex'" } +#undef _Generic // { dg-warning "undefining keyword '_Generic'" } +#undef _Imaginary // { dg-warning "undefining keyword '_Imaginary'" } +#undef _Noreturn // { dg-warning "undefining keyword '_Noreturn'" } +#undef _Static_assert // { dg-warning "undefining keyword '_Static_assert'" } +#undef _Thread_local // { dg-warning "undefining keyword '_Thread_local'" } +#undef auto // { dg-warning "undefining keyword 'auto'" } +#undef break // { dg-warning "undefining keyword 'break'" } +#undef case // { dg-warning "undefining keyword 'case'" } +#undef char // { dg-warning "undefining keyword 'char'" } +#undef const // { dg-warning "undefining keyword 'const'" } +#undef continue // { dg-warning "undefining keyword 'continue'" } +#undef default // { dg-warning "undefining keyword 'default'" } +#undef do // { dg-warning "undefining keyword 'do'" } +#undef double // { dg-warning "undefining keyword 'double'" } +#undef else // { dg-warning "undefining keyword 'else'" } +#undef enum // { dg-warning "undefining keyword 'enum'" } +#undef extern // { dg-warning "undefining keyword 'extern'" } +#undef float // { dg-warning "undefining keyword 'float'" } +#undef for // { dg-warning "undefining keyword 'for'" } +#undef goto // { dg-warning "undefining keyword 'goto'" } +#undef if // { dg-warning "undefining keyword 'if'" } +#undef inline // { dg-warning "undefining keyword 'inline'" } +#undef int // { dg-warning "undefining keyword 'int'" } +#undef long // { dg-warning "undefining keyword 'long'" } +#undef register // { dg-warning "undefining keyword 'register'" } +#undef restrict // { dg-warning "undefining keyword 'restrict'" } +#undef return // { dg-warning "undefining keyword 'return'" } +#undef short // { dg-warning "undefining keyword 'short'" } +#undef signed // { dg-warning "undefining keyword 'signed'" } +#undef sizeof // { dg-warning "undefining keyword 'sizeof'" } +#undef static // { dg-warning "undefining keyword 'static'" } +#undef struct // { dg-warning "undefining keyword 'struct'" } +#undef switch // { dg-warning "undefining keyword 'switch'" } +#undef typedef // { dg-warning "undefining keyword 'typedef'" } +#undef union // { dg-warning "undefining keyword 'union'" } +#undef unsigned // { dg-warning "undefining keyword 'unsigned'" } +#undef void // { dg-warning "undefining keyword 'void'" } +#undef volatile // { dg-warning "undefining keyword 'volatile'" } +#undef while // { dg-warning "undefining keyword 'while'" } diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-8.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-8.c new file mode 100644 index 0000000..b209f40 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-8.c @@ -0,0 +1,4 @@ +// { dg-do preprocess } +// { dg-options "-std=c17" } + +#include "Wkeyword-macro-7.c" diff --git a/gcc/testsuite/gcc.dg/Wkeyword-macro-9.c b/gcc/testsuite/gcc.dg/Wkeyword-macro-9.c new file mode 100644 index 0000000..5d6b650 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wkeyword-macro-9.c @@ -0,0 +1,15 @@ +// { dg-do preprocess } +// { dg-options "-Wkeyword-macro" } + +#undef for // { dg-warning "undefining keyword 'for'" } +#define for for // { dg-warning "keyword 'for' defined as macro" } +#undef for // { dg-warning "undefining keyword 'for'" } +#define while do // { dg-warning "keyword 'while' defined as macro" } +#define while do // { dg-warning "keyword 'while' defined as macro" } +#define while for // { dg-warning "keyword 'while' defined as macro" } + // { dg-warning "'while' redefined" "" { target *-*-* } .-1 } +#undef while // { dg-warning "undefining keyword 'while'" } +#define while while // { dg-warning "keyword 'while' defined as macro" } +#define inline // { dg-warning "keyword 'inline' defined as macro" } +#undef inline // { dg-warning "undefining keyword 'inline'" } +#define inline __inline__ __attribute__((__always_inline__)) // { dg-warning "keyword 'inline' defined as macro" } diff --git a/gcc/testsuite/gcc.dg/bitint-125.c b/gcc/testsuite/gcc.dg/bitint-125.c new file mode 100644 index 0000000..5ef0e32 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-125.c @@ -0,0 +1,15 @@ +/* PR tree-optimization/121127 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -w" } */ + +#if __BITINT_MAXWIDTH__ >= 576 +_BitInt(575) +foo (void) +{ + _BitInt(576) d; + _BitInt(575) e = d * 42wb; + return e; +} +#else +int i; +#endif diff --git a/gcc/testsuite/gcc.dg/bitintext.h b/gcc/testsuite/gcc.dg/bitintext.h index d5f2689d..f61cf9a 100644 --- a/gcc/testsuite/gcc.dg/bitintext.h +++ b/gcc/testsuite/gcc.dg/bitintext.h @@ -25,22 +25,20 @@ do_copy (void *p, const void *q, __SIZE_TYPE__ r) /* 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__) +#define BEXTC1(x, uns) \ + do { \ + uns _BitInt(PROMOTED_SIZE (x) * __CHAR_BIT__) __x; \ + do_copy (&__x, &(x), sizeof (__x)); \ + if (__x != (typeof (x)) __x) \ + __builtin_abort (); \ + } while (0) + #define BEXTC(x) \ - do { \ - if ((typeof (x)) -1 < 0) \ - { \ - _BitInt(PROMOTED_SIZE (x) * __CHAR_BIT__) __x; \ - do_copy (&__x, &(x), sizeof (__x)); \ - if (__x != (x)) \ - __builtin_abort (); \ - } \ - else \ - { \ - unsigned _BitInt(PROMOTED_SIZE (x) * __CHAR_BIT__) __x; \ - do_copy (&__x, &(x), sizeof (__x)); \ - if (__x != (x)) \ - __builtin_abort (); \ - } \ + do { \ + if ((typeof (x)) -1 < 0) \ + BEXTC1 ((x), signed); \ + else \ + BEXTC1 ((x), unsigned); \ } while (0) #else #define BEXTC(x) do { (void) (x); } while (0) diff --git a/gcc/testsuite/gcc.dg/pr121217.c b/gcc/testsuite/gcc.dg/pr121217.c new file mode 100644 index 0000000..313f1e3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr121217.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-std=gnu17" } */ + +typedef union{ + char *nordic_ref; + unsigned long long int bit_number; + enum PinMode mode : 2; /* { dg-warning "narrower" } */ + /* { dg-error "field 'mode'" "" { target *-*-* } .-1 } */ + unsigned char value; + } s; typedef struct{ + union{ + char *nordic_ref; + unsigned long long int bit_number; + enum PinMode mode : 2; /* { dg-warning "narrower" } */ + /* { dg-error "field 'mode'" "" { target *-*-* } .-1 } */ + unsigned char value; + } s; +} /* { dg-error "expected identifier" } */ + diff --git a/gcc/testsuite/gcc.dg/torture/bitint-83.c b/gcc/testsuite/gcc.dg/torture/bitint-83.c new file mode 100644 index 0000000..8a9df44 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-83.c @@ -0,0 +1,48 @@ +/* Derived from a test in gcc.dg/torture/bitint-16.c */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#include "../bitintext.h" + +#define BASIC_TESTS \ + TEST(8) \ + TEST(16) \ + TEST(32) + +#if __BITINT_MAXWIDTH__ >= 519 +#define ALL_TESTS \ + BASIC_TESTS \ + TEST(64) \ + TEST(128) \ + TEST(256) \ + TEST(512) +#else +#define ALL_TESTS BASIC_TESTS +#endif + +#define TEST(N) \ +void \ +test##N (unsigned _BitInt(N + 7) *t, _BitInt(N) x) \ +{ \ + *t = -x; \ +} +ALL_TESTS +#undef TEST + +volatile int y = 0; + +int +main (void) +{ +#define TEST(N) \ + { \ + unsigned _BitInt(N + 7) t; \ + _BitInt(N) x = y + N; \ + test##N (&t, x); \ + BEXTC (t); \ + } + ALL_TESTS +#undef TEST +} diff --git a/gcc/testsuite/gcc.dg/torture/bitint-84.c b/gcc/testsuite/gcc.dg/torture/bitint-84.c new file mode 100644 index 0000000..b3ecbef --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-84.c @@ -0,0 +1,18 @@ +/* A simple variant of gcc.dg/torture/bitint-64.c */ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#include "../bitintext.h" + +enum E : char { E22 = 22 } e = E22; + +int +main () +{ + _Atomic _BitInt (5) b = 0; + b += e; + BEXTC (b); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/bitint-85.c b/gcc/testsuite/gcc.dg/torture/bitint-85.c new file mode 100644 index 0000000..43eb6ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/bitint-85.c @@ -0,0 +1,34 @@ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "*" } { "-O0" "-O2" } } */ +/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */ + +#if __BITINT_MAXWIDTH__ >= 1024 +constexpr _BitInt(1024) d = -541140097068598424394740839221562143161511518875518765552323978870598341733206554363735813878577506997168480201818027232521wb; +int c; + +static inline void +foo (_BitInt(1024) b, _BitInt(1024) *r) +{ + if (c) + b = 0; + *r = b; +} + +[[gnu::noipa]] void +bar (_BitInt(1024) y) +{ + if (y != d) + __builtin_abort (); +} +#endif + +int +main () +{ +#if __BITINT_MAXWIDTH__ >= 1024 + _BitInt(1024) x; + foo (d, &x); + bar (x); +#endif +} diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-ai.c b/gcc/testsuite/gcc.dg/torture/hardbool-ai.c new file mode 100644 index 0000000..97569a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-ai.c @@ -0,0 +1,7 @@ +/* { dg-do run } */ + +#define basetype _Atomic int + +#define NO_BITFIELDS 1 + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool-vi.c b/gcc/testsuite/gcc.dg/torture/hardbool-vi.c new file mode 100644 index 0000000..898d395 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/hardbool-vi.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ + +#define basetype volatile int + +#include "hardbool.c" diff --git a/gcc/testsuite/gcc.dg/torture/hardbool.c b/gcc/testsuite/gcc.dg/torture/hardbool.c index 0168495..ed0c598 100644 --- a/gcc/testsuite/gcc.dg/torture/hardbool.c +++ b/gcc/testsuite/gcc.dg/torture/hardbool.c @@ -21,8 +21,12 @@ typedef unsigned char __attribute__ ((__hardbool__ (1, 0))) zbool; struct hs { hbool a[2]; +#ifndef NO_BITFIELDS hbool x:2; hbool y:5; +#else + hbool x, y; +#endif zbool z:1; }; @@ -57,6 +61,30 @@ int ghs(hbool s) { int t = (hbool)2; +hbool add1(hbool *s) { + return *s += 1; +} + +hbool preinc(hbool *s) { + return ++*s; +} + +hbool postinc(hbool *s) { + return (*s)++; +} + +hbool sub1(hbool *s) { + return *s -= 1; +} + +hbool predec(hbool *s) { + return --*s; +} + +hbool postdec(hbool *s) { + return (*s)--; +} + void check_pfalse (hbool *p) { assert (!*p); @@ -114,5 +142,43 @@ int main () { check_vtrue (h2 (2)); check_vtrue (h2 (1)); check_vfalse (h2 (0)); -} + hbool v; + v = 0; + check_vtrue (add1 (&v)); + assert (v); + v = 0; + check_vtrue (preinc (&v)); + assert (v); + v = 0; + check_vfalse (postinc (&v)); + assert (v); + v = 0; + check_vtrue (sub1 (&v)); + assert (v); + v = 0; + check_vtrue (predec (&v)); + assert (v); + v = 0; + check_vfalse (postdec (&v)); + assert (v); + + v = 1; + check_vtrue (add1 (&v)); + assert (v); + v = 1; + check_vtrue (preinc (&v)); + assert (v); + v = 1; + check_vtrue (postinc (&v)); + assert (v); + v = 1; + check_vfalse (sub1 (&v)); + assert (!v); + v = 1; + check_vfalse (predec (&v)); + assert (!v); + v = 1; + check_vtrue (postdec (&v)); + assert (!v); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c new file mode 100644 index 0000000..f80baf3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-107.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +struct vec_char_16 +{ + unsigned char raw[2]; +}; + +static inline struct vec_char_16 +Dup128VecFromValues(unsigned char t0, unsigned char t1) +{ + struct vec_char_16 result; + result.raw[0] = t0; + result.raw[1] = t1; + return result; +} + +int f(unsigned char t0, unsigned char t1) +{ + struct vec_char_16 a = Dup128VecFromValues(t0, t1); + struct vec_char_16 b; + __builtin_memcpy(&b, &a, sizeof(a)); + return b.raw[0] + b.raw[1]; +} + +/* Ideally we'd optimize this at FRE1 time but we only replace + the loads from b.raw[] with BIT_FIELD_REFs which get optimized + only later in the next FRE. */ +/* { dg-final { scan-tree-dump-not "MEM" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-gather-1.c b/gcc/testsuite/gcc.dg/vect/vect-gather-1.c index 5f6640d..6497ab4 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-gather-1.c +++ b/gcc/testsuite/gcc.dg/vect/vect-gather-1.c @@ -3,9 +3,9 @@ #define N 16 void __attribute__((noipa)) -f (int *restrict y, int *restrict x, int *restrict indices) +f (int *restrict y, int *restrict x, int *restrict indices, int n) { - for (int i = 0; i < N; ++i) + for (int i = 0; i < n; ++i) { y[i * 2] = x[indices[i * 2]] + 1; y[i * 2 + 1] = x[indices[i * 2 + 1]] + 2; @@ -49,7 +49,7 @@ main (void) { check_vect (); - f (y, x, indices); + f (y, x, indices, N); #pragma GCC novector for (int i = 0; i < 32; ++i) if (y[i] != expected[i]) diff --git a/gcc/testsuite/gcc.dg/vla-tert-1.c b/gcc/testsuite/gcc.dg/vla-tert-1.c new file mode 100644 index 0000000..dfbb2e6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-tert-1.c @@ -0,0 +1,293 @@ +/* { dg-do run } + * { dg-options "-std=c99" } + * */ + + +// For the conditional operator and variably modified types, +// verify that the size expression on the selected branch +// is evaluated and the correct result is returned. + + +// keep track which side was evaluated. +static int fc[2] = { 0 }; + +static int f(int s, int c) +{ + fc[c]++; + return s; +} + + +int main() +{ + // two VLAs, constant condition + + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(1 ? (char(*)[ f(5, 0) ])0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(0 ? (char(*)[ f(5, 0) ])0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); // fails + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); // fails + + // two VLAs + + int c = 0; + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); // fails + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); + + c = 1; + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // VLA + array of unknown size, VLA side is evaluated, defined + + c = 0; + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(c ? (char(*)[ ])0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); + + c = 1; + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (char(*)[ ])0))) + __builtin_abort(); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // VLA + array of unknown size, VLA side is not evaluated + + c = 1; + fc[0] = fc[1] = 0; + + sizeof(*(c ? (char(*)[ ])0 : (char(*)[ f(3, 1) ])0)); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // without sizeof + + fc[0] = fc[1] = 0; + + (c ? (char(*)[ ])0 : (char(*)[ f(3, 1) ])0); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + c = 0; + fc[0] = fc[1] = 0; + + sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (char(*)[ ])0)); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // without sizeof + + fc[0] = fc[1] = 0; + + (c ? (char(*)[ f(5, 0) ])0 : (char(*)[ ])0); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + + // VLA + array of known size, VLA side is evaluated + + c = 0; + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(c ? (char(*)[3])0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + // sizeof is not evaluated because not a VLA + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + c = 0; + fc[0] = fc[1] = 0; + + // without sizeof + + (c ? (char(*)[3])0 : (char(*)[ f(3, 1) ])0); + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); + + c = 1; + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (char(*)[5])0))) + __builtin_abort(); + + // sizeof is not evaluated because not a VLA + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // without sizeof + + fc[0] = fc[1] = 0; + + (c ? (char(*)[ f(5, 0) ])0 : (char(*)[ 5 ])0); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // VLA + array of known size, VLA side is not evaluated + + c = 0; + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(c ? (char(*)[ f(3, 0) ])0 : (char(*)[ 3 ])0))) + __builtin_abort(); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + c = 1; + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(c ? (char(*)[ 5 ])0 : (char(*)[ f(5, 1) ])0))) + __builtin_abort(); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // VM type on one side, null pointer on the other side + + c = 0; + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(c ? (void*)0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); + + c = 1; + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (void*)0))) + __builtin_abort(); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + +#if 0 + // these cases are not fixable + // VM types on one side, null pointer on the other side + c = 1; + fc[0] = fc[1] = 0; + + if (3 != sizeof(*(c ? (void*)0 : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); + + c = 0; + fc[0] = fc[1] = 0; + + if (5 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : (void*)0))) + __builtin_abort(); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); +#endif + + // VLA + void* + void* p = 0; + c = 0; + fc[0] = fc[1] = 0; + + if (1 != sizeof(*(c ? p : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + // not a VLA or evaluated + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // .. without sizeof + + (c ? p : (char(*)[ f(3, 1) ])0); + + if ((0 != fc[0]) || (1 != fc[1])) + __builtin_abort(); + + c = 1; + fc[0] = fc[1] = 0; + + if (1 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : p))) + __builtin_abort(); + + // not a VLA + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // .. without sizeof + + (c ? (char(*)[ f(5, 0) ])0 : p); + + if ((1 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // VLA + void*, VLA side not evaluated + + c = 1; + fc[0] = fc[1] = 0; + + if (1 != sizeof(*(c ? p : (char(*)[ f(3, 1) ])0))) + __builtin_abort(); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // .. without sizeof + + (c ? p : (char(*)[ f(3, 1) ])0); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + c = 0; + fc[0] = fc[1] = 0; + + if (1 != sizeof(*(c ? (char(*)[ f(5, 0) ])0 : p))) + __builtin_abort(); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + // .. without sizeof + + (c ? (char(*)[ f(5, 0) ])0 : p); + + if ((0 != fc[0]) || (0 != fc[1])) + __builtin_abort(); + + return 0; +} + diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops.c index f0dc9a9..1201ca0 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops.c +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops.c @@ -212,22 +212,22 @@ type init4 = svld1_ ## su ## sz (cmp ## sz, mem); \ \ type res_init1 = func_ ## type ## _init1 (); \ - svbool_t cmp = svcmpne_ ## su ## sz (all_true, init1, res_init1); \ + svbool_t cmp = svcmpne_ ## su ## sz (cmp ## sz, init1, res_init1); \ if (svptest_any (all_true, cmp)) \ __builtin_abort (); \ \ type res_init2 = func_ ## type ## _init2 (); \ - cmp = svcmpne_ ## su ## sz (all_true, init2, res_init2); \ + cmp = svcmpne_ ## su ## sz (cmp ## sz, init2, res_init2); \ if (svptest_any (all_true, cmp)) \ __builtin_abort (); \ \ type res_init3 = func_ ## type ## _init3 (); \ - cmp = svcmpne_ ## su ## sz (all_true, init3, res_init3); \ + cmp = svcmpne_ ## su ## sz (cmp ## sz, init3, res_init3); \ if (svptest_any (all_true, cmp)) \ __builtin_abort (); \ \ type res_init4 = func_ ## type ## _init4 (); \ - cmp = svcmpne_ ## su ## sz (all_true, init4, res_init4); \ + cmp = svcmpne_ ## su ## sz (cmp ## sz, init4, res_init4); \ if (svptest_any (all_true, cmp)) \ __builtin_abort (); \ } diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_11.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_11.c new file mode 100644 index 0000000..feb7ee7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_11.c @@ -0,0 +1,20 @@ +/* Peeling for alignment with masking in VLA modes. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=scalable --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define START 3 +#define END 510 + +int __attribute__((noipa)) +foo (int *a) { + for (signed int i = START; i < END; ++i) { + if (a[i] != 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" "vect" } } */ +/* { dg-final { scan-assembler {\tnot\tp[0-7]\.b, p[0-7]/z, p.*\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_11_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_11_run.c new file mode 100644 index 0000000..b4c267f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_11_run.c @@ -0,0 +1,27 @@ +/* Peeling for alignment with masking in VLA modes. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast -msve-vector-bits=scalable --param aarch64-autovec-preference=sve-only" } */ + +#include "peel_ind_11.c" +#include <stdio.h> +#include <stdlib.h> + +#define N 512 + +int __attribute__ ((optimize (1))) +main (void) +{ + for (int k = 5; k < 30; k++) { + int *a = (int *) malloc (sizeof(int) * N); + + /* Set only one non-zero element for test. */ + for (int i = 5; i < 30; i++) + a[i] = (i == k ? 1 : 0); + + int res = foo (a); + asm volatile (""); + if (res != k) { + __builtin_abort (); + } + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12.c new file mode 100644 index 0000000..260482a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12.c @@ -0,0 +1,21 @@ +/* Peeling for alignment with masking together with versioning in VLA modes. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=scalable --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define START 5 +#define END 509 + +int __attribute__((noipa)) +foo (int *restrict a, int * restrict b) { + for (signed int i = START; i < END; ++i) { + if (a[i] != b[i]) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump "Both peeling and versioning will be applied" "vect" } } */ +/* { dg-final { scan-assembler {\tnot\tp[0-7]\.b, p[0-7]/z, p.*\n} } } */ +/* { dg-final { scan-assembler {\teor\t.*\n} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12_run.c new file mode 100644 index 0000000..ba978fe --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_12_run.c @@ -0,0 +1,29 @@ +/* Peeling for alignment with masking together with versioning in VLA modes. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast -msve-vector-bits=scalable --param aarch64-autovec-preference=sve-only" } */ + +#include "peel_ind_12.c" +#include <stdio.h> +#include <stdlib.h> + +#define N 512 + +int __attribute__ ((optimize (1))) +main (void) { + for (int k = 5; k < 50; k++) { + int *a = (int *) malloc (sizeof(int) * N); + int *b = (int *) malloc (sizeof(int) * N); + + /* Set only one place of different values for test. */ + for (int i = 5; i < 50; i++) { + a[i] = (i == k ? 1 : 0); + b[i] = 0; + } + + int res = foo (a, b); + asm volatile (""); + if (res != k) { + __builtin_abort (); + } + } +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13.c new file mode 100644 index 0000000..730e33e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13.c @@ -0,0 +1,24 @@ +/* Known inbounds DR in VLA modes. */ +/* { dg-do compile } */ +/* { dg-options "-Ofast -msve-vector-bits=scalable --param aarch64-autovec-preference=sve-only -fdump-tree-vect-details" } */ + +#define N 512 +#define START 5 +#define END 509 + +int x[N] __attribute__((aligned(32))); + +int __attribute__((noipa)) +foo (void) +{ + for (signed int i = START; i < END; ++i) + { + if (x[i] == 0) + return i; + } + return -1; +} + +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ +/* { dg-final { scan-tree-dump-not "pfa_iv_offset" "vect" } } */ +/* { dg-final { scan-tree-dump-not "Alignment of access forced using peeling" "vect" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13_run.c b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13_run.c new file mode 100644 index 0000000..83352a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/peel_ind_13_run.c @@ -0,0 +1,15 @@ +/* Known inbounds DR in VLA modes. */ +/* { dg-do run { target aarch64_sve_hw } } */ +/* { dg-options "-Ofast -msve-vector-bits=scalable --param aarch64-autovec-preference=sve-only" } */ + +#include "peel_ind_13.c" + +int __attribute__ ((optimize (1))) +main (void) +{ + int res = foo (); + asm volatile (""); + if (res != START) + __builtin_abort (); + return 0; +} 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/i386/pr90579.c b/gcc/testsuite/gcc.target/i386/pr90579.c index ab48a44..bd2fd33 100644 --- a/gcc/testsuite/gcc.target/i386/pr90579.c +++ b/gcc/testsuite/gcc.target/i386/pr90579.c @@ -16,8 +16,5 @@ loop (int k, double x) return t; } -/* Verify we end up with scalar loads from r for the final sum. */ -/* { dg-final { scan-assembler "vaddsd\tr\\\+40" } } */ -/* { dg-final { scan-assembler "vaddsd\tr\\\+32" } } */ -/* { dg-final { scan-assembler "vaddsd\tr\\\+24" } } */ -/* { dg-final { scan-assembler "vaddsd\tr\\\+16" } } */ +/* Verify we end up with no loads from r. */ +/* { dg-final { scan-assembler-not "v\[ma\]\[^\t \]+\tr" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/arch-unset-1.c b/gcc/testsuite/gcc.target/riscv/arch-unset-1.c new file mode 100644 index 0000000..971b936 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-unset-1.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i -march=unset -mcpu=sifive-x280 -mabi=lp64 -misa-spec=20191213" } */ +int foo() +{ +} + +/* { dg-final { scan-assembler "\.attribute arch, \"rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_v1p0_zicsr2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zfh1p0_zfhmin1p0_zca1p0_zcd1p0_zba1p0_zbb1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvfh1p0_zvl128b1p0_zvl256b1p0_zvl32b1p0_zvl512b1p0_zvl64b1p0\"" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/arch-unset-2.c b/gcc/testsuite/gcc.target/riscv/arch-unset-2.c new file mode 100644 index 0000000..9840658 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-unset-2.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i -march=unset -mcpu=sifive-x280 -march=rv64i -mabi=lp64 -misa-spec=20191213" } */ +int foo() +{ +} + +/* { dg-final { scan-assembler "\.attribute arch, \"rv64i2p1\"" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/arch-unset-3.c b/gcc/testsuite/gcc.target/riscv/arch-unset-3.c new file mode 100644 index 0000000..5ddc224 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-unset-3.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i -march=unset -mcpu=sifive-x280 -march=rv64i -march=unset -mabi=lp64 -misa-spec=20191213" } */ +int foo() +{ +} + +/* { dg-final { scan-assembler "\.attribute arch, \"rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_v1p0_zicsr2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zfh1p0_zfhmin1p0_zca1p0_zcd1p0_zba1p0_zbb1p0_zve32f1p0_zve32x1p0_zve64d1p0_zve64f1p0_zve64x1p0_zvfh1p0_zvl128b1p0_zvl256b1p0_zvl32b1p0_zvl512b1p0_zvl64b1p0\"" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/arch-unset-4.c b/gcc/testsuite/gcc.target/riscv/arch-unset-4.c new file mode 100644 index 0000000..c16821d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-unset-4.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i -march=unset -mcpu=sifive-x280 -march=unset -march=rv64i -march=unset -march=rv64i -mabi=lp64 -misa-spec=20191213" } */ +int foo() +{ +} + +/* { dg-final { scan-assembler "\.attribute arch, \"rv64i2p1\"" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/arch-unset-5.c b/gcc/testsuite/gcc.target/riscv/arch-unset-5.c new file mode 100644 index 0000000..368c129 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/arch-unset-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i -march=unset -mabi=lp64 -misa-spec=20191213" } */ +int foo() +{ +} + +/* { dg-error "At least one valid -mcpu option must be given after -march=unset" "" { target { "riscv*-*-*" } } 0 } */ diff --git a/gcc/testsuite/gcc.target/s390/bitint-1.c b/gcc/testsuite/gcc.target/s390/bitint-1.c new file mode 100644 index 0000000..8bdf2ae --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/bitint-1.c @@ -0,0 +1,83 @@ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-O2 -march=z9-109" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +/* Verify calling convention. */ + +static_assert (sizeof (_BitInt(5)) == 1); +static_assert (sizeof (_BitInt(9)) == 2); +static_assert (sizeof (_BitInt(17)) == 4); +static_assert (sizeof (_BitInt(33)) == 8); + +/* +** bitint5_zero_extend_call: +** lghi %r2,22 +** jg bitint5_zero_extend@PLT +*/ + +void bitint5_zero_extend (unsigned _BitInt(5) x); +void bitint5_zero_extend_call (void) { bitint5_zero_extend (22wbu); } + +/* +** bitint5_sign_extend_call: +** lghi %r2,-10 +** jg bitint5_sign_extend@PLT +*/ + +void bitint5_sign_extend (_BitInt(5) x); +void bitint5_sign_extend_call (void) { bitint5_sign_extend (-10wb); } + +/* +** bitint9_zero_extend_call: +** lghi %r2,422 +** jg bitint9_zero_extend@PLT +*/ + +void bitint9_zero_extend (unsigned _BitInt(9) x); +void bitint9_zero_extend_call (void) { bitint9_zero_extend (422wbu); } + +/* +** bitint9_sign_extend_call: +** lghi %r2,-90 +** jg bitint9_sign_extend@PLT +*/ + +void bitint9_sign_extend (_BitInt(9) x); +void bitint9_sign_extend_call (void) { bitint9_sign_extend (-90wb); } + +/* +** bitint17_zero_extend_call: +** lgfi %r2,108198 +** jg bitint17_zero_extend@PLT +*/ + +void bitint17_zero_extend (unsigned _BitInt(17) x); +void bitint17_zero_extend_call (void) { bitint17_zero_extend (108198wbu); } + +/* +** bitint17_sign_extend_call: +** lghi %r2,-22874 +** jg bitint17_sign_extend@PLT +*/ + +void bitint17_sign_extend (_BitInt(17) x); +void bitint17_sign_extend_call (void) { bitint17_sign_extend (-22874wb); } + +/* +** bitint33_zero_extend_call: +** llihl %r2,1 +** oilf %r2,2795939494 +** jg bitint33_zero_extend@PLT +*/ + +void bitint33_zero_extend (unsigned _BitInt(33) x); +void bitint33_zero_extend_call (void) { bitint33_zero_extend (7090906790wbu); } + +/* +** bitint33_sign_extend_call: +** lgfi %r2,-1499027802 +** jg bitint33_sign_extend@PLT +*/ + +void bitint33_sign_extend (_BitInt(33) x); +void bitint33_sign_extend_call (void) { bitint33_sign_extend (-1499027802wb); } diff --git a/gcc/testsuite/gcc.target/s390/bitint-2.c b/gcc/testsuite/gcc.target/s390/bitint-2.c new file mode 100644 index 0000000..9b0e6b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/bitint-2.c @@ -0,0 +1,32 @@ +/* { dg-do run { target bitint } } */ +/* { dg-options "-std=c23" } */ + +/* Verify calling convention. */ + +static_assert (sizeof (_BitInt(65)) == 16); + +[[gnu::noipa]] void +bitint65_zero_extend (unsigned _BitInt(65) x) +{ + static const char y[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xBA, 0xDC, 0x0F, 0xFE, 0xE0, 0xDD, 0xF0, 0x0D}; + if (__builtin_memcmp (&x, y, 16) != 0) + __builtin_abort (); +} + +[[gnu::noipa]] void +bitint65_sign_extend (signed _BitInt(65) x) +{ + static const char y[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xBA, 0xDC, 0x0F, 0xFE, 0xE0, 0xDD, 0xF0, 0x0D}; + if (__builtin_memcmp (&x, y, 16) != 0) + __builtin_abort (); +} + +int +main (void) +{ + bitint65_zero_extend (0x1BADC0FFEE0DDF00Dwbu); + bitint65_sign_extend (0x1BADC0FFEE0DDF00Dwb); + return 0; +} diff --git a/gcc/testsuite/gcc.target/s390/bitint-3.c b/gcc/testsuite/gcc.target/s390/bitint-3.c new file mode 100644 index 0000000..9132028 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/bitint-3.c @@ -0,0 +1,28 @@ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-march=z9-109 -fdump-rtl-expand" } */ + +/* Verify calling convention. */ + +/* { dg-final { scan-rtl-dump-times "zero_extend:DI.*reg:QI" 1 "expand" } } */ +void bitint5_zero_extend (unsigned _BitInt(5) x); +void bitint5_zero_extend_call (unsigned _BitInt(5) x) { bitint5_zero_extend (x + 1); } + +/* { dg-final { scan-rtl-dump-times "sign_extend:DI.*reg:QI" 1 "expand" } } */ +void bitint5_sign_extend (_BitInt(5) x); +void bitint5_sign_extend_call (_BitInt(5) x) { bitint5_sign_extend (x + 1); } + +/* { dg-final { scan-rtl-dump-times "zero_extend:DI.*reg:HI" 1 "expand" } } */ +void bitint9_zero_extend (unsigned _BitInt(9) x); +void bitint9_zero_extend_call (unsigned _BitInt(9) x) { bitint9_zero_extend (x + 1); } + +/* { dg-final { scan-rtl-dump-times "sign_extend:DI.*reg:HI" 1 "expand" } } */ +void bitint9_sign_extend (_BitInt(9) x); +void bitint9_sign_extend_call (_BitInt(9) x) { bitint9_sign_extend (x + 1); } + +/* { dg-final { scan-rtl-dump-times "zero_extend:DI.*reg:SI" 1 "expand" } } */ +void bitint17_zero_extend (unsigned _BitInt(17) x); +void bitint17_zero_extend_call (unsigned _BitInt(17) x) { bitint17_zero_extend (x + 1); } + +/* { dg-final { scan-rtl-dump-times "sign_extend:DI.*reg:SI" 1 "expand" } } */ +void bitint17_sign_extend (_BitInt(17) x); +void bitint17_sign_extend_call (_BitInt(17) x) { bitint17_sign_extend (x + 1); } diff --git a/gcc/testsuite/gcc.target/s390/bitint-4.c b/gcc/testsuite/gcc.target/s390/bitint-4.c new file mode 100644 index 0000000..dce72d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/bitint-4.c @@ -0,0 +1,71 @@ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-march=z9-109 -O2" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +/* Verify calling convention. */ + +struct s_bitint5 { + short a; + unsigned _BitInt(5) b; + char c; +}; + +static_assert (sizeof (struct s_bitint5) == 4); + +/* +** s_bitint5_call: +** iilf %r2,2758168 +** jg s_bitint5@PLT +*/ + +void s_bitint5 (struct s_bitint5 x); +void s_bitint5_call (void) { s_bitint5 ((struct s_bitint5){42, 22wbu, 24}); } + +struct s_bitint9 { + short a; + unsigned _BitInt(9) b; +}; + +static_assert (sizeof (struct s_bitint9) == 4); + +/* +** s_bitint9_call: +** iilf %r2,2752934 +** jg s_bitint9@PLT +*/ + +void s_bitint9 (struct s_bitint9 x); +void s_bitint9_call (void) { s_bitint9 ((struct s_bitint9){42, 422wbu}); } + +struct s_bitint17 { + int a; + unsigned _BitInt(17) b; +}; + +static_assert (sizeof (struct s_bitint17) == 8); + +/* +** s_bitint17_call: +** llihl %r2,42 +** oilf %r2,108198 +** jg s_bitint17@PLT +*/ + +void s_bitint17 (struct s_bitint17 x); +void s_bitint17_call (void) { s_bitint17 ((struct s_bitint17){42, 108198wbu}); } + +struct s_bitint33 { + unsigned _BitInt(33) b; +}; + +static_assert (sizeof (struct s_bitint33) == 8); + +/* +** s_bitint33_call: +** llihl %r2,1 +** oilf %r2,2795939494 +** jg s_bitint33@PLT +*/ + +void s_bitint33 (struct s_bitint33 x); +void s_bitint33_call (void) { s_bitint33 ((struct s_bitint33){7090906790wbu}); } diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2.f03 b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2.f03 index 79cf2c1..da20835 100644 --- a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2.f03 +++ b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2.f03 @@ -1,5 +1,5 @@ ! { dg-do run } -! { dg-additional-sources c_f_pointer_shape_tests_2_driver.c } +! { dg-additional-sources c_f_pointer_shape_tests_driver.c } ! Verify that the optional SHAPE parameter to c_f_pointer can be of any ! valid integer kind. We don't test all kinds here since it would be ! difficult to know what kinds are valid for the architecture we're running on. diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2_driver.c b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2_driver.c deleted file mode 100644 index 1282beb..0000000 --- a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_2_driver.c +++ /dev/null @@ -1,46 +0,0 @@ -#define NUM_ELEMS 10 -#define NUM_ROWS 2 -#define NUM_COLS 3 - -void test_long_long_1d(int *array, int num_elems); -void test_long_long_2d(int *array, int num_rows, int num_cols); -void test_long_1d(int *array, int num_elems); -void test_int_1d(int *array, int num_elems); -void test_short_1d(int *array, int num_elems); -void test_mixed(int *array, int num_elems); - -int main(int argc, char **argv) -{ - int my_array[NUM_ELEMS]; - int my_2d_array[NUM_ROWS][NUM_COLS]; - int i, j; - - for(i = 0; i < NUM_ELEMS; i++) - my_array[i] = i; - - for(i = 0; i < NUM_ROWS; i++) - for(j = 0; j < NUM_COLS; j++) - my_2d_array[i][j] = (i*NUM_COLS) + j; - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_long_long. */ - test_long_long_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_long_long. - The indices are transposed for Fortran. */ - test_long_long_2d(my_2d_array[0], NUM_COLS, NUM_ROWS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_long. */ - test_long_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_int. */ - test_int_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_short. */ - test_short_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_int and - kind=c_long_long. */ - test_mixed(my_array, NUM_ELEMS); - - return 0; -} diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4.f03 b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4.f03 index 3f60f17..519087a 100644 --- a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4.f03 +++ b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4.f03 @@ -1,5 +1,5 @@ ! { dg-do run } -! { dg-additional-sources c_f_pointer_shape_tests_2_driver.c } +! { dg-additional-sources c_f_pointer_shape_tests_driver.c } ! Verify that the optional SHAPE parameter to c_f_pointer can be of any ! valid integer kind. We don't test all kinds here since it would be ! difficult to know what kinds are valid for the architecture we're running on. diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4_driver.c b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4_driver.c deleted file mode 100644 index 1282beb..0000000 --- a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_4_driver.c +++ /dev/null @@ -1,46 +0,0 @@ -#define NUM_ELEMS 10 -#define NUM_ROWS 2 -#define NUM_COLS 3 - -void test_long_long_1d(int *array, int num_elems); -void test_long_long_2d(int *array, int num_rows, int num_cols); -void test_long_1d(int *array, int num_elems); -void test_int_1d(int *array, int num_elems); -void test_short_1d(int *array, int num_elems); -void test_mixed(int *array, int num_elems); - -int main(int argc, char **argv) -{ - int my_array[NUM_ELEMS]; - int my_2d_array[NUM_ROWS][NUM_COLS]; - int i, j; - - for(i = 0; i < NUM_ELEMS; i++) - my_array[i] = i; - - for(i = 0; i < NUM_ROWS; i++) - for(j = 0; j < NUM_COLS; j++) - my_2d_array[i][j] = (i*NUM_COLS) + j; - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_long_long. */ - test_long_long_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_long_long. - The indices are transposed for Fortran. */ - test_long_long_2d(my_2d_array[0], NUM_COLS, NUM_ROWS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_long. */ - test_long_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_int. */ - test_int_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_short. */ - test_short_1d(my_array, NUM_ELEMS); - - /* Test c_f_pointer where SHAPE is of type integer, kind=c_int and - kind=c_long_long. */ - test_mixed(my_array, NUM_ELEMS); - - return 0; -} diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_driver.c b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_driver.c new file mode 100644 index 0000000..70e7d56 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/c_f_pointer_shape_tests_driver.c @@ -0,0 +1,47 @@ +#define NUM_ELEMS 10 +#define NUM_ROWS 2 +#define NUM_COLS 3 + +void test_long_long_1d (int *array, int num_elems); +void test_long_long_2d (int *array, int num_rows, int num_cols); +void test_long_1d (int *array, int num_elems); +void test_int_1d (int *array, int num_elems); +void test_short_1d (int *array, int num_elems); +void test_mixed (int *array, int num_elems); + +int +main (int argc, char **argv) +{ + int my_array[NUM_ELEMS]; + int my_2d_array[NUM_ROWS][NUM_COLS]; + int i, j; + + for (i = 0; i < NUM_ELEMS; i++) + my_array[i] = i; + + for (i = 0; i < NUM_ROWS; i++) + for (j = 0; j < NUM_COLS; j++) + my_2d_array[i][j] = (i * NUM_COLS) + j; + + /* Test c_f_pointer where SHAPE is of type integer, kind=c_long_long. */ + test_long_long_1d (my_array, NUM_ELEMS); + + /* Test c_f_pointer where SHAPE is of type integer, kind=c_long_long. + The indices are transposed for Fortran. */ + test_long_long_2d (my_2d_array[0], NUM_COLS, NUM_ROWS); + + /* Test c_f_pointer where SHAPE is of type integer, kind=c_long. */ + test_long_1d (my_array, NUM_ELEMS); + + /* Test c_f_pointer where SHAPE is of type integer, kind=c_int. */ + test_int_1d (my_array, NUM_ELEMS); + + /* Test c_f_pointer where SHAPE is of type integer, kind=c_short. */ + test_short_1d (my_array, NUM_ELEMS); + + /* Test c_f_pointer where SHAPE is of type integer, kind=c_int and + kind=c_long_long. */ + test_mixed (my_array, NUM_ELEMS); + + return 0; +} 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/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/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 bd91729..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 -frust-compile-until=compilation" } - #[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/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-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-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 index 9728613..3bf2c7e 100644 --- a/gcc/testsuite/rust/compile/issue-3618.rs +++ b/gcc/testsuite/rust/compile/issue-3618.rs @@ -1 +1,2 @@ -static _X: () = loop {}; // { dg-error "loop iteration count exceeds limit" } +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-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/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-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 31d7a26..0000000 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ /dev/null @@ -1,9 +0,0 @@ -issue-3315-2.rs -torture/alt_patterns1.rs -torture/name_resolve1.rs -issue-3652.rs -issue-1487.rs -issue-2015.rs -issue-3454.rs -impl_trait_generic_arg.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 44989a8..2afbeb4 100644 --- a/gcc/testsuite/rust/compile/pub_restricted_1.rs +++ b/gcc/testsuite/rust/compile/pub_restricted_1.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - pub mod foo { pub mod bar { pub fn baz() {} diff --git a/gcc/testsuite/rust/compile/pub_restricted_2.rs b/gcc/testsuite/rust/compile/pub_restricted_2.rs index 91f072e..fea9379 100644 --- a/gcc/testsuite/rust/compile/pub_restricted_2.rs +++ b/gcc/testsuite/rust/compile/pub_restricted_2.rs @@ -1,4 +1,4 @@ -// { dg-additional-options "-w -frust-name-resolution-2.0" } +// { dg-additional-options "-w" } mod foo { mod bar { diff --git a/gcc/testsuite/rust/compile/self-in-impl.rs b/gcc/testsuite/rust/compile/self-in-impl.rs index f888162..a567897 100644 --- a/gcc/testsuite/rust/compile/self-in-impl.rs +++ b/gcc/testsuite/rust/compile/self-in-impl.rs @@ -1,5 +1,3 @@ -// { dg-additional-options "-frust-name-resolution-2.0" } - // 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 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/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/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/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 index efb825b..0431629 100644 --- a/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs +++ b/gcc/testsuite/rust/execute/torture/basic_partial_ord1.rs @@ -103,6 +103,19 @@ impl PartialOrd for i32 { 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 {} diff --git a/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs b/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs index b8c3672..b6a9695 100644 --- a/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs +++ b/gcc/testsuite/rust/execute/torture/basic_partial_ord2.rs @@ -104,6 +104,19 @@ impl PartialOrd for i32 { 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 {} 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/derive-partialeq2.rs b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs index 70ed7dc..e316017 100644 --- a/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs +++ b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs @@ -2,6 +2,20 @@ #![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 {} diff --git a/gcc/testsuite/rust/execute/torture/impl_trait3.rs b/gcc/testsuite/rust/execute/torture/impl_trait3.rs index 97e2972..c1cec07 100644 --- a/gcc/testsuite/rust/execute/torture/impl_trait3.rs +++ b/gcc/testsuite/rust/execute/torture/impl_trait3.rs @@ -18,7 +18,6 @@ struct Console; impl Printer for Console { fn print(&self, input: impl Speak) { - // { dg-warning "unused name .self." "" { target *-*-* } .-1 } unsafe { let a = input.speak(); let b = a as *const str; 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-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/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/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/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-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 00315d1..1c113f8 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -5633,6 +5633,28 @@ visit_nary_op (tree lhs, gassign *stmt) } } break; + case BIT_FIELD_REF: + if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == SSA_NAME) + { + tree op0 = TREE_OPERAND (rhs1, 0); + gassign *ass = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (op0)); + if (ass + && !gimple_has_volatile_ops (ass) + && vn_get_stmt_kind (ass) == VN_REFERENCE) + { + tree last_vuse = gimple_vuse (ass); + tree op = build3 (BIT_FIELD_REF, TREE_TYPE (rhs1), + gimple_assign_rhs1 (ass), + TREE_OPERAND (rhs1, 1), TREE_OPERAND (rhs1, 2)); + tree result = vn_reference_lookup (op, gimple_vuse (ass), + default_vn_walk_kind, + NULL, true, &last_vuse); + if (result + && useless_type_conversion_p (type, TREE_TYPE (result))) + return set_ssa_val_to (lhs, result); + } + } + break; case TRUNC_DIV_EXPR: if (TYPE_UNSIGNED (type)) break; diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc index dc82bf6..a3d3b3e 100644 --- a/gcc/tree-vect-data-refs.cc +++ b/gcc/tree-vect-data-refs.cc @@ -1448,17 +1448,20 @@ vect_compute_data_ref_alignment (vec_info *vinfo, dr_vec_info *dr_info, if (loop_vinfo && dr_safe_speculative_read_required (stmt_info)) { - poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); - auto vectype_size + /* The required target alignment must be a power-of-2 value and is + computed as the product of vector element size, VF and group size. + We compute the constant part first as VF may be a variable. For + variable VF, the power-of-2 check of VF is deferred to runtime. */ + auto align_factor_c = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))); - poly_uint64 new_alignment = vf * vectype_size; - /* If we have a grouped access we require that the alignment be N * elem. */ if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) - new_alignment *= DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info)); + align_factor_c *= DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info)); + + poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); + poly_uint64 new_alignment = vf * align_factor_c; - unsigned HOST_WIDE_INT target_alignment; - if (new_alignment.is_constant (&target_alignment) - && pow2p_hwi (target_alignment)) + if ((vf.is_constant () && pow2p_hwi (new_alignment.to_constant ())) + || (!vf.is_constant () && pow2p_hwi (align_factor_c))) { if (dump_enabled_p ()) { @@ -1467,7 +1470,7 @@ vect_compute_data_ref_alignment (vec_info *vinfo, dr_vec_info *dr_info, dump_dec (MSG_NOTE, new_alignment); dump_printf (MSG_NOTE, " bytes.\n"); } - vector_alignment = target_alignment; + vector_alignment = new_alignment; } } @@ -2438,6 +2441,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) - The cost of peeling (the extra runtime checks, the increase in code size). */ + poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); FOR_EACH_VEC_ELT (datarefs, i, dr) { dr_vec_info *dr_info = loop_vinfo->lookup_dr (dr); @@ -2446,9 +2450,18 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) stmt_vec_info stmt_info = dr_info->stmt; tree vectype = STMT_VINFO_VECTYPE (stmt_info); - do_peeling - = vector_alignment_reachable_p (dr_info, - LOOP_VINFO_VECT_FACTOR (loop_vinfo)); + + /* With variable VF, unsafe speculative read can be avoided for known + inbounds DRs as long as partial vectors are used. */ + if (!vf.is_constant () + && dr_safe_speculative_read_required (stmt_info) + && DR_SCALAR_KNOWN_BOUNDS (dr_info)) + { + dr_set_safe_speculative_read_required (stmt_info, false); + LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true; + } + + do_peeling = vector_alignment_reachable_p (dr_info, vf); if (do_peeling) { if (known_alignment_for_access_p (dr_info, vectype)) @@ -2488,7 +2501,6 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) poly_uint64 nscalars = npeel_tmp; if (unlimited_cost_model (LOOP_VINFO_LOOP (loop_vinfo))) { - poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); unsigned group_size = 1; if (STMT_SLP_TYPE (stmt_info) && STMT_VINFO_GROUPED_ACCESS (stmt_info)) @@ -2911,14 +2923,12 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) 2) there is at least one unsupported misaligned data ref with an unknown misalignment, and 3) all misaligned data refs with a known misalignment are supported, and - 4) the number of runtime alignment checks is within reason. - 5) the vectorization factor is a constant. */ + 4) the number of runtime alignment checks is within reason. */ do_versioning = (optimize_loop_nest_for_speed_p (loop) && !loop->inner /* FORNOW */ - && loop_cost_model (loop) > VECT_COST_MODEL_CHEAP) - && LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (); + && loop_cost_model (loop) > VECT_COST_MODEL_CHEAP); if (do_versioning) { @@ -2965,25 +2975,22 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) ?? We could actually unroll the loop to achieve the required overall step alignment, and forcing the alignment could be done by doing some iterations of the non-vectorized loop. */ - if (!multiple_p (LOOP_VINFO_VECT_FACTOR (loop_vinfo) - * DR_STEP_ALIGNMENT (dr), + if (!multiple_p (vf * DR_STEP_ALIGNMENT (dr), DR_TARGET_ALIGNMENT (dr_info))) { do_versioning = false; break; } - /* The rightmost bits of an aligned address must be zeros. - Construct the mask needed for this test. For example, - GET_MODE_SIZE for the vector mode V4SI is 16 bytes so the - mask must be 15 = 0xf. */ - gcc_assert (DR_TARGET_ALIGNMENT (dr_info).is_constant ()); - int mask = DR_TARGET_ALIGNMENT (dr_info).to_constant () - 1; + /* Use "mask = DR_TARGET_ALIGNMENT - 1" to test rightmost address + bits for runtime alignment check. For example, for 16 bytes + target alignment the mask is 15 = 0xf. */ + poly_uint64 mask = DR_TARGET_ALIGNMENT (dr_info) - 1; /* FORNOW: use the same mask to test all potentially unaligned references in the loop. */ - if (LOOP_VINFO_PTR_MASK (loop_vinfo) - && LOOP_VINFO_PTR_MASK (loop_vinfo) != mask) + if (maybe_ne (LOOP_VINFO_PTR_MASK (loop_vinfo), 0U) + && maybe_ne (LOOP_VINFO_PTR_MASK (loop_vinfo), mask)) { do_versioning = false; break; @@ -4423,8 +4430,9 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo) MASKED_P is true if the load or store is conditional. MEMORY_TYPE is the type of the memory elements being loaded or stored. OFFSET_TYPE is the type of the offset that is being applied to the invariant - base address. SCALE is the amount by which the offset should - be multiplied *after* it has been converted to address width. + base address. If OFFSET_TYPE is scalar the function chooses an + appropriate vector type for it. SCALE is the amount by which the + offset should be multiplied *after* it has been converted to address width. Return true if the function is supported, storing the function id in *IFN_OUT and the vector type for the offset in *OFFSET_VECTYPE_OUT. @@ -4467,9 +4475,15 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, for (;;) { - tree offset_vectype = get_vectype_for_scalar_type (vinfo, offset_type); - if (!offset_vectype) - return false; + tree offset_vectype; + if (VECTOR_TYPE_P (offset_type)) + offset_vectype = offset_type; + else + { + offset_vectype = get_vectype_for_scalar_type (vinfo, offset_type); + if (!offset_vectype) + return false; + } /* Test whether the target supports this combination. */ if (internal_gather_scatter_fn_supported_p (ifn, vectype, memory_type, @@ -4500,10 +4514,15 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, return true; } + /* For fixed offset vector type we're done. */ + if (VECTOR_TYPE_P (offset_type)) + return false; + if (TYPE_PRECISION (offset_type) >= POINTER_SIZE && TYPE_PRECISION (offset_type) >= element_bits) return false; + /* Try a larger offset vector type. */ offset_type = build_nonstandard_integer_type (TYPE_PRECISION (offset_type) * 2, TYPE_UNSIGNED (offset_type)); } @@ -4512,7 +4531,7 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, /* STMT_INFO is a call to an internal gather load or scatter store function. Describe the operation in INFO. */ -static void +void vect_describe_gather_scatter_call (stmt_vec_info stmt_info, gather_scatter_info *info) { @@ -6524,7 +6543,7 @@ vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info, tree vectype, int misalignment, gather_scatter_info *gs_info) { - data_reference *dr = dr_info ? dr_info->dr : nullptr; + data_reference *dr = dr_info->dr; stmt_vec_info stmt_info = dr_info->stmt; machine_mode mode = TYPE_MODE (vectype); loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo); @@ -6605,7 +6624,7 @@ vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info, } } */ - if (dr && DR_IS_READ (dr)) + if (DR_IS_READ (dr)) { if (can_implement_p (vec_realign_load_optab, mode) && (!targetm.vectorize.builtin_mask_for_load @@ -6635,38 +6654,7 @@ vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info, tree type = TREE_TYPE (DR_REF (dr)); bool is_gather_scatter = gs_info != nullptr; if (misalignment == DR_MISALIGNMENT_UNKNOWN) - { - if (!is_gather_scatter || dr != nullptr) - is_packed = not_size_aligned (DR_REF (dr)); - else - { - /* Gather-scatter accesses normally perform only component accesses - so alignment is irrelevant for them. Targets like riscv do care - about scalar alignment in vector accesses, though, so check scalar - alignment here. We determined the alias pointer as well as the - base alignment during pattern recognition and can re-use it here. - - As we do not have an analyzed dataref we only know the alignment - of the reference itself and nothing about init, steps, etc. - For now don't try harder to determine misalignment and - just assume it is unknown. We consider the type packed if its - scalar alignment is lower than the natural alignment of a vector - element's type. */ - - gcc_assert (!GATHER_SCATTER_LEGACY_P (*gs_info)); - gcc_assert (dr == nullptr); - - tree inner_vectype = TREE_TYPE (vectype); - - unsigned HOST_WIDE_INT scalar_align - = tree_to_uhwi (gs_info->alias_ptr); - unsigned HOST_WIDE_INT inner_vectype_sz - = tree_to_uhwi (TYPE_SIZE (inner_vectype)); - - bool is_misaligned = scalar_align < inner_vectype_sz; - is_packed = scalar_align > 1 && is_misaligned; - } - } + is_packed = not_size_aligned (DR_REF (dr)); if (targetm.vectorize.support_vector_misalignment (mode, type, misalignment, is_packed, is_gather_scatter)) diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc index 6c1b26a..566308f 100644 --- a/gcc/tree-vect-loop-manip.cc +++ b/gcc/tree-vect-loop-manip.cc @@ -2454,10 +2454,7 @@ get_misalign_in_elems (gimple **seq, loop_vec_info loop_vinfo) else { tree vla = build_int_cst (type, target_align); - tree vla_align = fold_build2 (BIT_AND_EXPR, type, vla, - fold_build2 (MINUS_EXPR, type, - build_int_cst (type, 0), vla)); - target_align_minus_1 = fold_build2 (MINUS_EXPR, type, vla_align, + target_align_minus_1 = fold_build2 (MINUS_EXPR, type, vla, build_int_cst (type, 1)); } @@ -3840,7 +3837,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo, const vec<stmt_vec_info> &may_misalign_stmts = LOOP_VINFO_MAY_MISALIGN_STMTS (loop_vinfo); stmt_vec_info stmt_info; - int mask = LOOP_VINFO_PTR_MASK (loop_vinfo); + poly_uint64 mask = LOOP_VINFO_PTR_MASK (loop_vinfo); tree mask_cst; unsigned int i; tree int_ptrsize_type; @@ -3852,9 +3849,7 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo, tree ptrsize_zero; tree part_cond_expr; - /* Check that mask is one less than a power of 2, i.e., mask is - all zeros followed by all ones. */ - gcc_assert ((mask != 0) && ((mask & (mask+1)) == 0)); + gcc_assert (known_ne (mask, 0U)); int_ptrsize_type = signed_type_for (ptr_type_node); @@ -3962,6 +3957,62 @@ vect_create_cond_for_align_checks (loop_vec_info loop_vinfo, chain_cond_expr (cond_expr, part_cond_expr); } +/* Function vect_create_cond_for_vla_spec_read. + + Create a conditional expression that represents the run-time checks with + max speculative read amount in VLA modes. We check two things: + 1) if the max speculative read amount exceeds the min page size + 2) if the VF is power-of-2 - done by checking the max read amount instead + + Input: + COND_EXPR - input conditional expression. New conditions will be chained + with logical AND operation. + LOOP_VINFO - field LOOP_VINFO_MAX_SPEC_READ_AMOUNT contains the max + possible speculative read amount in VLA modes. + + Output: + COND_EXPR - conditional expression. + + The returned COND_EXPR is the conditional expression to be used in the + if statement that controls which version of the loop gets executed at + runtime. */ + +static void +vect_create_cond_for_vla_spec_read (loop_vec_info loop_vinfo, tree *cond_expr) +{ + poly_uint64 read_amount_poly = LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo); + tree amount = build_int_cst (long_unsigned_type_node, read_amount_poly); + + /* Both the read amount and the VF must be variants, and the read amount must + be a constant power-of-2 multiple of the VF. */ + unsigned HOST_WIDE_INT multiple; + gcc_assert (!read_amount_poly.is_constant () + && !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant () + && constant_multiple_p (read_amount_poly, + LOOP_VINFO_VECT_FACTOR (loop_vinfo), + &multiple) + && pow2p_hwi (multiple)); + + tree cst_ul_zero = build_int_cstu (long_unsigned_type_node, 0U); + tree cst_ul_one = build_int_cstu (long_unsigned_type_node, 1U); + tree cst_ul_pagesize = build_int_cstu (long_unsigned_type_node, + (unsigned long) param_min_pagesize); + + /* Create an expression of "amount & (amount - 1) == 0". */ + tree amount_m1 = fold_build2 (MINUS_EXPR, long_unsigned_type_node, + amount, cst_ul_one); + tree amount_and_expr = fold_build2 (BIT_AND_EXPR, long_unsigned_type_node, + amount, amount_m1); + tree powof2_cond_expr = fold_build2 (EQ_EXPR, boolean_type_node, + amount_and_expr, cst_ul_zero); + chain_cond_expr (cond_expr, powof2_cond_expr); + + /* Create an expression of "amount <= cst_ul_pagesize". */ + tree pagesize_cond_expr = fold_build2 (LE_EXPR, boolean_type_node, + amount, cst_ul_pagesize); + chain_cond_expr (cond_expr, pagesize_cond_expr); +} + /* If LOOP_VINFO_CHECK_UNEQUAL_ADDRS contains <A1, B1>, ..., <An, Bn>, create a tree representation of: (&A1 != &B1) && ... && (&An != &Bn). Set *COND_EXPR to a tree that is true when both the original *COND_EXPR @@ -4087,6 +4138,7 @@ vect_loop_versioning (loop_vec_info loop_vinfo, gimple_seq gimplify_stmt_list = NULL; tree scalar_loop_iters = LOOP_VINFO_NITERSM1 (loop_vinfo); bool version_align = LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT (loop_vinfo); + bool version_spec_read = LOOP_REQUIRES_VERSIONING_FOR_SPEC_READ (loop_vinfo); bool version_alias = LOOP_REQUIRES_VERSIONING_FOR_ALIAS (loop_vinfo); bool version_niter = LOOP_REQUIRES_VERSIONING_FOR_NITERS (loop_vinfo); poly_uint64 versioning_threshold @@ -4145,6 +4197,9 @@ vect_loop_versioning (loop_vec_info loop_vinfo, vect_create_cond_for_align_checks (loop_vinfo, &cond_expr, &cond_expr_stmt_list); + if (version_spec_read) + vect_create_cond_for_vla_spec_read (loop_vinfo, &cond_expr); + if (version_alias) { vect_create_cond_for_unequal_addrs (loop_vinfo, &cond_expr); diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index 85f3e90..55a8495 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -1009,6 +1009,7 @@ _loop_vec_info::_loop_vec_info (class loop *loop_in, vec_info_shared *shared) unaligned_dr (NULL), peeling_for_alignment (0), ptr_mask (0), + max_spec_read_amount (0), nonlinear_iv (false), ivexpr_map (NULL), scan_map (NULL), @@ -10141,7 +10142,12 @@ vectorizable_induction (loop_vec_info loop_vinfo, if (peel_mul) { if (!step_mul) - step_mul = peel_mul; + { + gcc_assert (!nunits.is_constant ()); + step_mul = gimple_build (&init_stmts, + MINUS_EXPR, step_vectype, + build_zero_cst (step_vectype), peel_mul); + } else step_mul = gimple_build (&init_stmts, MINUS_EXPR, step_vectype, diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index 794a073..59acbc1 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -120,6 +120,8 @@ _slp_tree::_slp_tree () SLP_TREE_LANE_PERMUTATION (this) = vNULL; SLP_TREE_DEF_TYPE (this) = vect_uninitialized_def; SLP_TREE_CODE (this) = ERROR_MARK; + SLP_TREE_GS_SCALE (this) = 0; + SLP_TREE_GS_BASE (this) = NULL_TREE; this->ldst_lanes = false; this->avoid_stlf_fail = false; SLP_TREE_VECTYPE (this) = NULL_TREE; @@ -680,6 +682,15 @@ vect_get_and_check_slp_defs (vec_info *vinfo, unsigned char swap, { internal_fn ifn = gimple_call_internal_fn (stmt); commutative_op = first_commutative_argument (ifn); + if (internal_gather_scatter_fn_p (ifn)) + { + vect_describe_gather_scatter_call + (stmt_info, + first ? &(*oprnds_info)[0]->first_gs_info : &gs_info); + if (first) + (*oprnds_info)[0]->first_gs_p = true; + gs_op = 0; + } } } else if (gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt)) @@ -2720,6 +2731,9 @@ out: stmt_info = stmts[0]; + int gs_scale = 0; + tree gs_base = NULL_TREE; + /* Create SLP_TREE nodes for the definition node/s. */ FOR_EACH_VEC_ELT (oprnds_info, i, oprnd_info) { @@ -2742,6 +2756,12 @@ out: continue; } + if (oprnd_info->first_gs_p) + { + gs_scale = oprnd_info->first_gs_info.scale; + gs_base = oprnd_info->first_gs_info.base; + } + if (is_a <bb_vec_info> (vinfo) && oprnd_info->first_dt == vect_internal_def && !oprnd_info->any_pattern) @@ -3131,6 +3151,8 @@ fail: node = vect_create_new_slp_node (node, stmts, nops); SLP_TREE_VECTYPE (node) = vectype; SLP_TREE_CHILDREN (node).splice (children); + SLP_TREE_GS_SCALE (node) = gs_scale; + SLP_TREE_GS_BASE (node) = gs_base; return node; } diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index f7a052b..dbeb8bd 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -1497,7 +1497,8 @@ check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype, gs_info->memory_type, gs_info->offset_vectype, gs_info->scale, - elsvals)) + elsvals) + || gs_info->decl != NULL_TREE) vect_record_loop_mask (loop_vinfo, masks, nvectors, vectype, scalar_mask); else @@ -2018,31 +2019,40 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) { *memory_access_type = VMAT_GATHER_SCATTER; - if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info, - elsvals)) - gcc_unreachable (); slp_tree offset_node = SLP_TREE_CHILDREN (slp_node)[0]; tree offset_vectype = SLP_TREE_VECTYPE (offset_node); + memset (gs_info, 0, sizeof (gather_scatter_info)); gs_info->offset_vectype = offset_vectype; - /* When using internal functions, we rely on pattern recognition - to convert the type of the offset to the type that the target - requires, with the result being a call to an internal function. - If that failed for some reason (e.g. because another pattern - took priority), just handle cases in which the offset already - has the right type. */ - if (GATHER_SCATTER_IFN_P (*gs_info) - && !is_gimple_call (stmt_info->stmt) - && !tree_nop_conversion_p (TREE_TYPE (gs_info->offset), - TREE_TYPE (offset_vectype))) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "%s offset requires a conversion\n", - vls_type == VLS_LOAD ? "gather" : "scatter"); - return false; - } - else if (GATHER_SCATTER_EMULATED_P (*gs_info)) + gs_info->scale = SLP_TREE_GS_SCALE (slp_node); + gs_info->base = SLP_TREE_GS_BASE (slp_node); + gs_info->memory_type = TREE_TYPE (DR_REF (first_dr_info->dr)); + gs_info->decl = NULL_TREE; + gs_info->ifn = IFN_LAST; + tree tem; + if (vect_gather_scatter_fn_p (loop_vinfo, vls_type == VLS_LOAD, + masked_p, vectype, + gs_info->memory_type, + offset_vectype, gs_info->scale, + &gs_info->ifn, &tem, + elsvals)) + /* GATHER_SCATTER_IFN_P. */; + else if (vls_type == VLS_LOAD + ? (targetm.vectorize.builtin_gather + && (gs_info->decl + = targetm.vectorize.builtin_gather (vectype, + TREE_TYPE + (offset_vectype), + gs_info->scale))) + : (targetm.vectorize.builtin_scatter + && (gs_info->decl + = targetm.vectorize.builtin_scatter (vectype, + TREE_TYPE + (offset_vectype), + gs_info->scale)))) + /* GATHER_SCATTER_LEGACY_P. */; + else { + /* GATHER_SCATTER_EMULATED_P. */ if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant () || !TYPE_VECTOR_SUBPARTS (offset_vectype).is_constant () || VECTOR_BOOLEAN_TYPE_P (offset_vectype) @@ -2390,70 +2400,26 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, /* We can only peel for loops, of course. */ gcc_checking_assert (loop_vinfo); + poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); + poly_uint64 read_amount + = vf * TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))); + if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) + read_amount *= DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info)); + auto target_alignment = DR_TARGET_ALIGNMENT (STMT_VINFO_DR_INFO (stmt_info)); - unsigned HOST_WIDE_INT target_align; - - bool group_aligned = false; - if (target_alignment.is_constant (&target_align) - && nunits.is_constant ()) - { - poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); - auto vectype_size - = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (vectype))); - poly_uint64 required_alignment = vf * vectype_size; - /* If we have a grouped access we require that the alignment be N * elem. */ - if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) - required_alignment *= - DR_GROUP_SIZE (DR_GROUP_FIRST_ELEMENT (stmt_info)); - if (!multiple_p (target_alignment, required_alignment)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "desired alignment %wu not met. Instead got %wu " - "for DR alignment at %G", - required_alignment.to_constant (), - target_align, STMT_VINFO_STMT (stmt_info)); - return false; - } - - if (!pow2p_hwi (target_align)) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "non-power-of-two vector alignment %wd " - "for DR alignment at %G", - target_align, STMT_VINFO_STMT (stmt_info)); - return false; - } - - /* For VLA we have to insert a runtime check that the vector loads - per iterations don't exceed a page size. For now we can use - POLY_VALUE_MAX as a proxy as we can't peel for VLA. */ - if (known_gt (required_alignment, (unsigned)param_min_pagesize)) + if (!multiple_p (target_alignment, read_amount)) + { + if (dump_enabled_p ()) { - if (dump_enabled_p ()) - { - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "alignment required for correctness ("); - dump_dec (MSG_MISSED_OPTIMIZATION, required_alignment); - dump_printf (MSG_NOTE, ") may exceed page size\n"); - } - return false; + dump_printf_loc (MSG_NOTE, vect_location, + "desired alignment not met, target was "); + dump_dec (MSG_NOTE, target_alignment); + dump_printf (MSG_NOTE, " previously, but read amount is "); + dump_dec (MSG_NOTE, read_amount); + dump_printf (MSG_NOTE, " at %G.\n", STMT_VINFO_STMT (stmt_info)); } - - group_aligned = true; - } - - /* There are multiple loads that have a misalignment that we couldn't - align. We would need LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P to - vectorize. */ - if (!group_aligned) - { - if (inbounds) - LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true; - else - return false; + return false; } /* When using a group access the first element may be aligned but the @@ -2475,6 +2441,33 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, STMT_VINFO_STMT (stmt_info)); return false; } + + /* Reject vectorization if we know the read mount per vector iteration + exceeds the min page size. */ + if (known_gt (read_amount, (unsigned) param_min_pagesize)) + { + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "alignment required for correctness ("); + dump_dec (MSG_MISSED_OPTIMIZATION, read_amount); + dump_printf (MSG_NOTE, ") may exceed page size.\n"); + } + return false; + } + + if (!vf.is_constant ()) + { + /* For VLA modes, we need a runtime check to ensure any speculative + read amount does not exceed the page size. Here we record the max + possible read amount for the check. */ + if (maybe_gt (read_amount, + LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo))) + LOOP_VINFO_MAX_SPEC_READ_AMOUNT (loop_vinfo) = read_amount; + + /* For VLA modes, we must use partial vectors. */ + LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true; + } } if (*alignment_support_scheme == dr_unaligned_unsupported) @@ -8529,7 +8522,6 @@ vectorizable_store (vec_info *vinfo, gcc_assert (useless_type_conversion_p (vectype, TREE_TYPE (vec_oprnd))); } - unsigned HOST_WIDE_INT align; tree final_mask = NULL_TREE; tree final_len = NULL_TREE; tree bias = NULL_TREE; @@ -8544,6 +8536,8 @@ vectorizable_store (vec_info *vinfo, final_mask, vec_mask, gsi); } + unsigned align = get_object_alignment (DR_REF (first_dr_info->dr)); + tree alias_align_ptr = build_int_cst (ref_type, align); if (GATHER_SCATTER_IFN_P (gs_info)) { if (costing_p) @@ -8585,7 +8579,7 @@ vectorizable_store (vec_info *vinfo, if (VECTOR_TYPE_P (TREE_TYPE (vec_offset))) call = gimple_build_call_internal ( IFN_MASK_LEN_SCATTER_STORE, 8, dataref_ptr, - gs_info.alias_ptr, + alias_align_ptr, vec_offset, scale, vec_oprnd, final_mask, final_len, bias); else @@ -8602,12 +8596,12 @@ vectorizable_store (vec_info *vinfo, else if (final_mask) call = gimple_build_call_internal (IFN_MASK_SCATTER_STORE, 6, dataref_ptr, - gs_info.alias_ptr, + alias_align_ptr, vec_offset, scale, vec_oprnd, final_mask); else call = gimple_build_call_internal (IFN_SCATTER_STORE, 5, dataref_ptr, - gs_info.alias_ptr, + alias_align_ptr, vec_offset, scale, vec_oprnd); gimple_call_set_nothrow (call, true); @@ -8763,7 +8757,6 @@ vectorizable_store (vec_info *vinfo, = (j % factor) * const_nunits; tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); tree scale = size_int (gs_info.scale); - align = get_object_alignment (DR_REF (first_dr_info->dr)); tree ltype = build_aligned_type (TREE_TYPE (vectype), align); for (unsigned k = 0; k < const_nunits; ++k) { @@ -10392,7 +10385,8 @@ vectorizable_load (vec_info *vinfo, } /* 2. Create the vector-load in the loop. */ - unsigned HOST_WIDE_INT align; + unsigned align = get_object_alignment (DR_REF (first_dr_info->dr)); + tree alias_align_ptr = build_int_cst (ref_type, align); if (GATHER_SCATTER_IFN_P (gs_info)) { if (costing_p) @@ -10440,7 +10434,7 @@ vectorizable_load (vec_info *vinfo, if (VECTOR_TYPE_P (TREE_TYPE (vec_offset))) call = gimple_build_call_internal (IFN_MASK_LEN_GATHER_LOAD, 9, dataref_ptr, - gs_info.alias_ptr, + alias_align_ptr, vec_offset, scale, zero, final_mask, vec_els, final_len, bias); @@ -10456,13 +10450,13 @@ vectorizable_load (vec_info *vinfo, else if (final_mask) call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD, 7, dataref_ptr, - gs_info.alias_ptr, + alias_align_ptr, vec_offset, scale, zero, final_mask, vec_els); else call = gimple_build_call_internal (IFN_GATHER_LOAD, 5, dataref_ptr, - gs_info.alias_ptr, + alias_align_ptr, vec_offset, scale, zero); gimple_call_set_nothrow (call, true); new_stmt = call; @@ -10620,7 +10614,6 @@ vectorizable_load (vec_info *vinfo, unsigned elt_offset = (i % factor) * const_nunits; tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); tree scale = size_int (gs_info.scale); - align = get_object_alignment (DR_REF (first_dr_info->dr)); tree ltype = build_aligned_type (TREE_TYPE (vectype), align); for (unsigned k = 0; k < const_nunits; ++k) { diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 52e1075..041cff8 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -306,6 +306,11 @@ struct _slp_tree { unsigned int lanes; /* The operation of this node. */ enum tree_code code; + /* For gather/scatter memory operations the scale each offset element + should be multiplied by before being added to the base. */ + int gs_scale; + /* For gather/scatter memory operations the loop-invariant base value. */ + tree gs_base; /* Whether uses of this load or feeders of this store are suitable for load/store-lanes. */ bool ldst_lanes; @@ -412,6 +417,8 @@ public: #define SLP_TREE_CODE(S) (S)->code #define SLP_TREE_MEMORY_ACCESS_TYPE(S) (S)->memory_access_type #define SLP_TREE_TYPE(S) (S)->type +#define SLP_TREE_GS_SCALE(S) (S)->gs_scale +#define SLP_TREE_GS_BASE(S) (S)->gs_base enum vect_partial_vector_style { vect_partial_vectors_none, @@ -912,7 +919,10 @@ public: int peeling_for_alignment; /* The mask used to check the alignment of pointers or arrays. */ - int ptr_mask; + poly_uint64 ptr_mask; + + /* The maximum speculative read amount in VLA modes for runtime check. */ + poly_uint64 max_spec_read_amount; /* Indicates whether the loop has any non-linear IV. */ bool nonlinear_iv; @@ -1148,6 +1158,7 @@ public: #define LOOP_VINFO_RGROUP_IV_TYPE(L) (L)->rgroup_iv_type #define LOOP_VINFO_PARTIAL_VECTORS_STYLE(L) (L)->partial_vector_style #define LOOP_VINFO_PTR_MASK(L) (L)->ptr_mask +#define LOOP_VINFO_MAX_SPEC_READ_AMOUNT(L) (L)->max_spec_read_amount #define LOOP_VINFO_LOOP_NEST(L) (L)->shared->loop_nest #define LOOP_VINFO_DATAREFS(L) (L)->shared->datarefs #define LOOP_VINFO_DDRS(L) (L)->shared->ddrs @@ -1202,6 +1213,8 @@ public: #define LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT(L) \ ((L)->may_misalign_stmts.length () > 0) +#define LOOP_REQUIRES_VERSIONING_FOR_SPEC_READ(L) \ + (maybe_gt ((L)->max_spec_read_amount, 0U)) #define LOOP_REQUIRES_VERSIONING_FOR_ALIAS(L) \ ((L)->comp_alias_ddrs.length () > 0 \ || (L)->check_unequal_addrs.length () > 0 \ @@ -1212,6 +1225,7 @@ public: (LOOP_VINFO_SIMD_IF_COND (L)) #define LOOP_REQUIRES_VERSIONING(L) \ (LOOP_REQUIRES_VERSIONING_FOR_ALIGNMENT (L) \ + || LOOP_REQUIRES_VERSIONING_FOR_SPEC_READ (L) \ || LOOP_REQUIRES_VERSIONING_FOR_ALIAS (L) \ || LOOP_REQUIRES_VERSIONING_FOR_NITERS (L) \ || LOOP_REQUIRES_VERSIONING_FOR_SIMD_IF_COND (L)) @@ -2550,6 +2564,8 @@ extern bool vect_gather_scatter_fn_p (vec_info *, bool, bool, tree, tree, extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info, gather_scatter_info *, vec<int> * = nullptr); +extern void vect_describe_gather_scatter_call (stmt_vec_info, + gather_scatter_info *); extern opt_result vect_find_stmt_data_reference (loop_p, gimple *, vec<data_reference_p> *, vec<int> *, int); 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) \ |