diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc index c43919ba14e5f4..06aae26d498e82 100644 --- a/doc/syntax/pattern_matching.rdoc +++ b/doc/syntax/pattern_matching.rdoc @@ -253,11 +253,11 @@ The "rest" part of a pattern also can be bound to a variable: case {a: 1, b: 2} in {a: } | Array + # ^ SyntaxError (variable capture in alternative pattern) "matched: #{a}" else "not matched" end - # SyntaxError (illegal variable in alternative pattern (a)) Variables that start with _ are the only exclusions from this rule: diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb index cda385767c3cc7..079b37382d7bc3 100644 --- a/ext/json/parser/extconf.rb +++ b/ext/json/parser/extconf.rb @@ -6,7 +6,6 @@ have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0 have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2 have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby -have_func("strnlen", "string.h") # Missing on Solaris 10 append_cflags("-std=c99") diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index 9df04ce0079fad..2bf3ae0eb38dd6 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -296,15 +296,6 @@ static void rvalue_stack_eagerly_release(VALUE handle) } } - -#ifndef HAVE_STRNLEN -static size_t strnlen(const char *s, size_t maxlen) -{ - char *p; - return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen); -} -#endif - static int convert_UTF32_to_UTF8(char *buf, uint32_t ch) { int len = 1; diff --git a/gc.rb b/gc.rb index f5e62eed6058fa..f944c653b5b467 100644 --- a/gc.rb +++ b/gc.rb @@ -193,7 +193,10 @@ def self.count # - +:time+: # The total time spent in garbage collections (in milliseconds). # - +:heap_allocated_pages+: - # The total number of +:heap_eden_pages+ + +:heap_tomb_pages+. + # The total number of allocated pages. + # - +:heap_empty_pages+: + # - +:heap_allocated_pages+: + # The number of pages with no live objects, and that could be released to the system. # - +:heap_sorted_length+: # The number of pages that can fit into the buffer that holds references to all pages. # - +:heap_allocatable_pages+: @@ -210,8 +213,6 @@ def self.count # The total number of objects marked in the last \GC. # - +:heap_eden_pages+: # The total number of pages which contain at least one live slot. - # - +:heap_tomb_pages+: - # The total number of pages which do not contain any live slots. # - +:total_allocated_pages+: # The cumulative number of pages allocated since application start. # - +:total_freed_pages+: @@ -374,11 +375,6 @@ def self.stat hash_or_key = nil # The number of pages in the eden heap. # - +:heap_eden_slots+: # The total number of slots in all of the pages in the eden heap. - # - +:heap_tomb_pages+: - # The number of pages in the tomb heap. The tomb heap only contains pages - # that do not have any live objects. - # - +:heap_tomb_slots+: - # The total number of slots in all of the pages in the tomb heap. # - +:total_allocated_pages+: # The total number of pages that have been allocated in the heap. # - +:total_freed_pages+: diff --git a/lib/time.rb b/lib/time.rb index a0fc7dfbf5d300..14bfe4c8fbc43b 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -80,7 +80,7 @@ class << Time # # You must require 'time' to use this method. # - def zone_offset(zone, year=self.now.year) + def zone_offset(zone, year=nil) off = nil zone = zone.upcase if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone @@ -89,10 +89,13 @@ def zone_offset(zone, year=self.now.year) off = zone.to_i * 3600 elsif ZoneOffset.include?(zone) off = ZoneOffset[zone] * 3600 - elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false) - off = t.utc_offset - elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false) - off = t.utc_offset + else + year ||= self.now.year + if ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false) + off = t.utc_offset + elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false) + off = t.utc_offset + end end off end diff --git a/prism_compile.c b/prism_compile.c index 811ce4781696e7..d3c66691a8325b 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -2288,7 +2288,7 @@ pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node, // A forward declaration because this is the recursive function that handles // compiling a pattern. It can be reentered by nesting patterns, as in the case // of arrays or hashes. -static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index); +static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index); /** * This function generates the code to set up the error string and error_p @@ -2394,10 +2394,10 @@ pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const * label. */ static int -pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index) +pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index) { LABEL *matched_label = NEW_LABEL(pm_node_line_number(scope_node->parser, node)); - CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index)); + CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index)); PUSH_LABEL(ret, matched_label); return COMPILE_OK; } @@ -2544,7 +2544,7 @@ pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_n * Compile a pattern matching expression. */ static int -pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index) +pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index) { const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node); @@ -2604,7 +2604,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t PUSH_INSN(ret, location, dup); PUSH_INSN1(ret, location, putobject, INT2FIX(index)); PUSH_SEND(ret, location, idAREF, INT2FIX(1)); - CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1)); + CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, false, base_index + 1)); } if (cast->rest != NULL) { @@ -2617,7 +2617,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t PUSH_SEND(ret, location, idMINUS, INT2FIX(1)); PUSH_INSN1(ret, location, setn, INT2FIX(4)); PUSH_SEND(ret, location, idAREF, INT2FIX(2)); - CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1)); + CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, false, base_index + 1)); } else if (posts_size > 0) { PUSH_INSN(ret, location, dup); @@ -2637,7 +2637,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t PUSH_INSN1(ret, location, topn, INT2FIX(3)); PUSH_SEND(ret, location, idPLUS, INT2FIX(1)); PUSH_SEND(ret, location, idAREF, INT2FIX(1)); - CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1)); + CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, false, base_index + 1)); } PUSH_INSN(ret, location, pop); @@ -2734,7 +2734,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t } PUSH_SEND(ret, location, idAREF, INT2FIX(1)); - CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, in_alternation_pattern, false, base_index + 4)); + CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, false, base_index + 4)); } const pm_splat_node_t *left = cast->left; @@ -2744,7 +2744,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t PUSH_INSN1(ret, location, putobject, INT2FIX(0)); PUSH_INSN1(ret, location, topn, INT2FIX(2)); PUSH_SEND(ret, location, idAREF, INT2FIX(2)); - CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4)); + CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4)); } RUBY_ASSERT(PM_NODE_TYPE_P(cast->right, PM_SPLAT_NODE)); @@ -2757,7 +2757,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t PUSH_SEND(ret, location, idPLUS, INT2FIX(1)); PUSH_INSN1(ret, location, topn, INT2FIX(3)); PUSH_SEND(ret, location, idAREF, INT2FIX(2)); - pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4); + pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, false, base_index + 4); } PUSH_INSNL(ret, location, jump, find_succeeded_label); @@ -2936,7 +2936,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t value = ((const pm_implicit_node_t *) value)->value; } - CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1)); + CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, false, base_index + 1)); } PUSH_SEQ(ret, match_values); @@ -2964,7 +2964,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t case PM_ASSOC_SPLAT_NODE: { const pm_assoc_splat_node_t *splat = (const pm_assoc_splat_node_t *) cast->rest; PUSH_INSN(ret, location, dup); - pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1); + pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, false, base_index + 1); break; } default: @@ -3009,8 +3009,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t LABEL *match_failed_label = NEW_LABEL(location.line); PUSH_INSN(ret, location, dup); - CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index + 1)); - CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index)); + CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, use_deconstructed_cache, base_index + 1)); + CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, false, base_index)); PUSH_INSN(ret, location, putnil); PUSH_LABEL(ret, match_failed_label); @@ -3026,20 +3026,6 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node; pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth); - // If this local variable is being written from within an alternation - // pattern, then it cannot actually be added to the local table since - // it's ambiguous which value should be used. So instead we indicate - // this with a compile error. - if (in_alternation_pattern) { - ID id = pm_constant_id_lookup(scope_node, cast->name); - const char *name = rb_id2name(id); - - if (name && strlen(name) > 0 && name[0] != '_') { - COMPILE_ERROR(iseq, location.line, "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id)); - return COMPILE_NG; - } - } - PUSH_SETLOCAL(ret, location, index.index, index.level); PUSH_INSNL(ret, location, jump, matched_label); break; @@ -3055,7 +3041,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t // First, we're going to attempt to match against the left pattern. If // that pattern matches, then we'll skip matching the right pattern. PUSH_INSN(ret, location, dup); - CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, true, use_deconstructed_cache, base_index + 1)); + CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, use_deconstructed_cache, base_index + 1)); // If we get here, then we matched on the left pattern. In this case we // should pop out the duplicate value that we preemptively added to @@ -3068,7 +3054,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t // If we get here, then we didn't match on the left pattern. In this // case we attempt to match against the right pattern. PUSH_LABEL(ret, unmatched_left_label); - CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, true, use_deconstructed_cache, base_index)); + CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index)); break; } case PM_PARENTHESES_NODE: @@ -3076,7 +3062,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t // they do nothing since they can only wrap individual expressions and // not groups. In this case we'll recurse back into this same function // with the body of the parentheses. - return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index); + return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index); case PM_PINNED_EXPRESSION_NODE: // Pinned expressions are a way to match against the value of an // expression that should be evaluated at runtime. This looks like: @@ -3137,7 +3123,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t // looks like: foo in ^@bar. To compile these, we compile the variable // that they hold. const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node; - CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index)); + CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, true, base_index)); break; } case PM_IF_NODE: @@ -3171,7 +3157,7 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t statement = cast->statements->body.nodes[0]; } - CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index)); + CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, use_deconstructed_cache, base_index)); PM_COMPILE_NOT_POPPED(predicate); if (in_single_pattern) { @@ -7878,7 +7864,7 @@ pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, co LABEL *next_pattern_label = NEW_LABEL(pattern_location.line); PUSH_INSN(cond_seq, pattern_location, dup); - pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, false, true, 2); + pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, true, 2); PUSH_LABEL(cond_seq, next_pattern_label); LABEL_UNREMOVABLE(next_pattern_label); } @@ -8126,7 +8112,7 @@ pm_compile_match_required_node(rb_iseq_t *iseq, const pm_match_required_node_t * // through the in_single_pattern parameter. We also indicate that the // value to compare against is 2 slots from the top of the stack (the // base_index parameter). - pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, false, true, 2); + pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, true, 2); // If the pattern did not match the value, then we're going to compile // in our error handler code. This will determine which error to raise @@ -9815,7 +9801,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label = NEW_LABEL(location.line); LABEL *unmatched_label = NEW_LABEL(location.line); LABEL *done_label = NEW_LABEL(location.line); - pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, false, false, true, 2); + pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, false, true, 2); // If the pattern did not match, then compile the necessary instructions // to handle pushing false onto the stack, then jump to the end. diff --git a/string.c b/string.c index 5c4e15c4a10384..827555d9e0faab 100644 --- a/string.c +++ b/string.c @@ -1935,8 +1935,8 @@ str_duplicate_setup_embed(VALUE klass, VALUE str, VALUE dup) long len = RSTRING_LEN(str); RUBY_ASSERT(STR_EMBED_P(dup)); - RUBY_ASSERT(str_embed_capa(dup) >= len + 1); - MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + 1); + RUBY_ASSERT(str_embed_capa(dup) >= len + TERM_LEN(str)); + MEMCPY(RSTRING(dup)->as.embed.ary, RSTRING(str)->as.embed.ary, char, len + TERM_LEN(str)); STR_SET_LEN(dup, RSTRING_LEN(str)); return str_duplicate_setup_encoding(str, dup, flags); } diff --git a/test/prism/ruby/parser_test.rb b/test/prism/ruby/parser_test.rb index 1629c36b382b53..648c44e77a6573 100644 --- a/test/prism/ruby/parser_test.rb +++ b/test/prism/ruby/parser_test.rb @@ -172,7 +172,6 @@ def test_non_prism_builder_class_deprecated if RUBY_VERSION >= "3.3" def test_current_parser_for_current_ruby major, minor = current_major_minor.split(".") - return if major == "3" && minor == "5" # TODO: Remove once ruby-dev becomes 4.0 # Let's just hope there never is a Ruby 3.10 or similar expected = major.to_i * 10 + minor.to_i assert_equal(expected, Translation::ParserCurrent.new.version) diff --git a/test/prism/test_helper.rb b/test/prism/test_helper.rb index c03f70b2cdab18..42555738cf318f 100644 --- a/test/prism/test_helper.rb +++ b/test/prism/test_helper.rb @@ -256,7 +256,6 @@ def current_major_minor if RUBY_VERSION >= "3.3.0" def test_all_syntax_versions_present - return if RUBY_VERSION.start_with?("3.5") # TODO: Remove once ruby-dev becomes 4.0 assert_include(SYNTAX_VERSIONS, current_major_minor) end end diff --git a/tool/format-release b/tool/format-release index 927a35d58c23de..b7ad74a095c6fd 100755 --- a/tool/format-release +++ b/tool/format-release @@ -30,10 +30,9 @@ class Tarball def gz?; @url.end_with?('.gz'); end def zip?; @url.end_with?('.zip'); end - def bz2?; @url.end_with?('.bz2'); end def xz?; @url.end_with?('.xz'); end - def ext; @url[/(?:zip|tar\.(?:gz|bz2|xz))\z/]; end + def ext; @url[/(?:zip|tar\.(?:gz|xz))\z/]; end def to_md <