Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions include/ruby/internal/encoding/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@ VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to);
*/
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts);

/**
* @private
*
* This is an implementation detail of rb_enc_str_coderange(). Don't use this
* directly.
**/
int rbimpl_enc_str_coderange_scan(VALUE str);

/**
* Scans the passed string to collect its code range. Because a Ruby's string
* is mutable, its contents change from time to time; so does its code range.
Expand All @@ -274,6 +282,27 @@ VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ec
*/
int rb_enc_str_coderange(VALUE str);

/**
* Scans the passed string to collect its code range. Because a Ruby's string
* is mutable, its contents change from time to time; so does its code range.
* A long-lived string tends to fall back to ::RUBY_ENC_CODERANGE_UNKNOWN.
* This API scans it and re-assigns a fine-grained code range constant.
*
* @param[out] str A string.
* @return An enum ::ruby_coderange_type.
*/
static inline int
rb_enc_str_coderange_inline(VALUE str)
{
int cr = ENC_CODERANGE(str);
if (cr == ENC_CODERANGE_UNKNOWN) {
cr = rbimpl_enc_str_coderange_scan(str);
}
return cr;
}

#define rb_enc_str_coderange rb_enc_str_coderange_inline

/**
* Scans the passed string until it finds something odd. Returns the number of
* bytes scanned. As the name implies this is suitable for repeated call. One
Expand Down
18 changes: 16 additions & 2 deletions iseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1916,16 +1916,30 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, file);

make_compile_option(&option, opt);

pm_parse_result_t result;
pm_parse_result_init(&result);
result.node.coverage_enabled = 1;

switch (option.frozen_string_literal) {
case ISEQ_FROZEN_STRING_LITERAL_UNSET:
break;
case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
pm_options_frozen_string_literal_set(result.options, false);
break;
case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
pm_options_frozen_string_literal_set(result.options, true);
break;
default:
rb_bug("iseqw_s_compile_file_prism: invalid frozen_string_literal=%d", option.frozen_string_literal);
break;
}

VALUE script_lines;
VALUE error = pm_load_parse_file(&result, file, ruby_vm_keep_script_lines ? &script_lines : NULL);

if (error == Qnil) {
make_compile_option(&option, opt);

int error_state;
rb_iseq_t *iseq = pm_iseq_new_with_opt(&result.node, rb_fstring_lit("<main>"),
file,
Expand Down
16 changes: 3 additions & 13 deletions re.c
Original file line number Diff line number Diff line change
Expand Up @@ -1584,21 +1584,11 @@ reg_enc_error(VALUE re, VALUE str)
rb_enc_inspect_name(rb_enc_get(str)));
}

static inline int
str_coderange(VALUE str)
{
int cr = ENC_CODERANGE(str);
if (cr == ENC_CODERANGE_UNKNOWN) {
cr = rb_enc_str_coderange(str);
}
return cr;
}

static rb_encoding*
rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
{
rb_encoding *enc = 0;
int cr = str_coderange(str);
int cr = rb_enc_str_coderange(str);

if (cr == ENC_CODERANGE_BROKEN) {
rb_raise(rb_eArgError,
Expand Down Expand Up @@ -3276,7 +3266,7 @@ rb_reg_preprocess_dregexp(VALUE ary, int options)
src_enc = rb_enc_get(str);
if (options & ARG_ENCODING_NONE &&
src_enc != ascii8bit) {
if (str_coderange(str) != ENC_CODERANGE_7BIT)
if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT)
rb_raise(rb_eRegexpError, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
else
src_enc = ascii8bit;
Expand Down Expand Up @@ -3397,7 +3387,7 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
if (options & ARG_ENCODING_NONE) {
rb_encoding *ascii8bit = rb_ascii8bit_encoding();
if (enc != ascii8bit) {
if (str_coderange(str) != ENC_CODERANGE_7BIT) {
if (rb_enc_str_coderange(str) != ENC_CODERANGE_7BIT) {
errcpy(err, "/.../n has a non escaped non ASCII character in non ASCII-8BIT script");
return -1;
}
Expand Down
13 changes: 11 additions & 2 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -941,17 +941,26 @@ rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc)
return enc_coderange_scan(str, enc);
}

int
rbimpl_enc_str_coderange_scan(VALUE str)
{
int cr = enc_coderange_scan(str, get_encoding(str));
ENC_CODERANGE_SET(str, cr);
return cr;
}

#undef rb_enc_str_coderange
int
rb_enc_str_coderange(VALUE str)
{
int cr = ENC_CODERANGE(str);

if (cr == ENC_CODERANGE_UNKNOWN) {
cr = enc_coderange_scan(str, get_encoding(str));
ENC_CODERANGE_SET(str, cr);
cr = rbimpl_enc_str_coderange_scan(str);
}
return cr;
}
#define rb_enc_str_coderange rb_enc_str_coderange_inline

static inline bool
rb_enc_str_asciicompat(VALUE str)
Expand Down
14 changes: 14 additions & 0 deletions test/ruby/test_iseq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,20 @@ def test_frozen_string_literal_compile_option
assert_not_predicate(s4, :frozen?)
end

def test_frozen_string_literal_compile_option_file
Tempfile.create(%w[fsl .rb]) do |f|
f.write("['foo', 'foo', \"\#{$f}foo\", \"\#{'foo'}\"]\n")
f.flush
$f = 'f'
s1, s2, s3, s4 = RubyVM::InstructionSequence
.compile_file(f.path, frozen_string_literal: true).eval
assert_predicate(s1, :frozen?)
assert_predicate(s2, :frozen?)
assert_not_predicate(s3, :frozen?)
assert_not_predicate(s4, :frozen?)
end
end

# Safe call chain is not optimized when Coverage is running.
# So we can test it only when Coverage is not running.
def test_safe_call_chain
Expand Down
2 changes: 1 addition & 1 deletion tool/leaked-globals
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Pipe.new(NM + ARGV).each do |line|
next
when /\Aruby_static_id_/
next unless so
when /\A(?:RUBY_|ruby_|rb_)/
when /\A(?:RUBY_|ruby_|rb_|rbimpl_)/
next unless so and /_(threadptr|ec)_/ =~ n
when *SYMBOLS_IN_EMPTYLIB
next
Expand Down