diff options
author | Jeremy Evans <code@jeremyevans.net> | 2021-10-18 07:09:07 -0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-18 09:09:07 -0700 |
commit | fac2c0f73cafb5d65bfbba7aa8018fa427972d71 (patch) | |
tree | aacc9415ba64e1b2af30bc76c3ed92c620b1e940 /parse.y | |
parent | 59bec48e48f7fc68a5bcff66642cceec0076e509 (diff) |
Fix evaluation order of hash values for duplicate keys
Fixes [Bug #17719]
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: Ivo Anjo <ivo@ivoanjo.me>
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4969
Merged-By: jeremyevans <code@jeremyevans.net>
Diffstat (limited to 'parse.y')
-rw-r--r-- | parse.y | 20 |
1 files changed, 13 insertions, 7 deletions
@@ -12246,24 +12246,30 @@ remove_duplicate_keys(struct parser_params *p, NODE *hash) { st_table *literal_keys = st_init_table_with_size(&literal_type, hash->nd_alen / 2); NODE *result = 0; + NODE *last_expr = 0; rb_code_location_t loc = hash->nd_loc; while (hash && hash->nd_head && hash->nd_next) { NODE *head = hash->nd_head; NODE *value = hash->nd_next; NODE *next = value->nd_next; - VALUE key = (VALUE)head; + st_data_t key = (st_data_t)head; st_data_t data; + value->nd_next = 0; if (nd_type(head) == NODE_LIT && - st_lookup(literal_keys, (key = head->nd_lit), &data)) { + st_delete(literal_keys, (key = (st_data_t)head->nd_lit, &key), &data)) { + NODE *dup_value = ((NODE *)data)->nd_next; rb_compile_warn(p->ruby_sourcefile, nd_line((NODE *)data), "key %+"PRIsVALUE" is duplicated and overwritten on line %d", head->nd_lit, nd_line(head)); - head = ((NODE *)data)->nd_next; - head->nd_head = block_append(p, head->nd_head, value->nd_head); - } - else { - st_insert(literal_keys, (st_data_t)key, (st_data_t)hash); + if (dup_value == last_expr) { + value->nd_head = block_append(p, dup_value->nd_head, value->nd_head); + } + else { + last_expr->nd_head = block_append(p, dup_value->nd_head, last_expr->nd_head); + } } + st_insert(literal_keys, (st_data_t)key, (st_data_t)hash); + last_expr = nd_type(head) == NODE_LIT ? value : head; hash = next; } st_foreach(literal_keys, append_literal_keys, (st_data_t)&result); |