ruby-changes:40240
From: nobu <ko1@a...>
Date: Wed, 28 Oct 2015 15:24:32 +0900 (JST)
Subject: [ruby-changes:40240] nobu:r52321 (trunk): NameError#receiver of uninitialized constant
nobu 2015-10-28 15:24:12 +0900 (Wed, 28 Oct 2015) New Revision: 52321 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52321 Log: NameError#receiver of uninitialized constant * error.c (name_err_mesg_to_str): quote the name if unprintable. * object.c (check_setter_id): use rb_check_id to convert names. * variable.c (uninitialized_constant): use NameError::message to keep the receiver of uninitialized constant. [Feature #10881] Modified files: trunk/ChangeLog trunk/error.c trunk/eval_error.c trunk/method.h trunk/object.c trunk/proc.c trunk/range.c trunk/struct.c trunk/test/ruby/test_exception.rb trunk/variable.c trunk/vm_method.c Index: method.h =================================================================== --- method.h (revision 52320) +++ method.h (revision 52321) @@ -27,7 +27,9 @@ typedef enum { https://github.com/ruby/ruby/blob/trunk/method.h#L27 METHOD_VISI_UNDEF = 0x00, METHOD_VISI_PUBLIC = 0x01, METHOD_VISI_PRIVATE = 0x02, - METHOD_VISI_PROTECTED = 0x03 + METHOD_VISI_PROTECTED = 0x03, + + METHOD_VISI_MASK = 0x03 } rb_method_visibility_t; typedef struct rb_scope_visi_struct { Index: ChangeLog =================================================================== --- ChangeLog (revision 52320) +++ ChangeLog (revision 52321) @@ -1,4 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 -Wed Oct 28 15:23:14 2015 Nobuyoshi Nakada <nobu@r...> +Wed Oct 28 15:24:09 2015 Nobuyoshi Nakada <nobu@r...> + + * error.c (name_err_mesg_to_str): quote the name if unprintable. + + * object.c (check_setter_id): use rb_check_id to convert names. + + * variable.c (uninitialized_constant): use NameError::message to + keep the receiver of uninitialized constant. [Feature #10881] * error.c (rb_name_err_new): new function to create NameError exception instance. [Feature #10881] Index: variable.c =================================================================== --- variable.c (revision 52320) +++ variable.c (revision 52321) @@ -1691,6 +1691,27 @@ rb_obj_instance_variables(VALUE obj) https://github.com/ruby/ruby/blob/trunk/variable.c#L1691 return ary; } +#define rb_is_constant_id rb_is_const_id +#define rb_is_constant_name rb_is_const_name +#define id_for_var(obj, name, part, type) \ + id_for_var_message(obj, name, type, "`%1$s' is not allowed as "#part" "#type" variable name") +#define id_for_var_message(obj, name, type, message) \ + check_id_type(obj, &(name), rb_is_##type##_id, rb_is_##type##_name, message, strlen(message)) +static ID +check_id_type(VALUE obj, VALUE *pname, + int (*valid_id_p)(ID), int (*valid_name_p)(VALUE), + const char *message, size_t message_len) +{ + ID id = rb_check_id(pname); + VALUE name = *pname; + + if (id ? !valid_id_p(id) : !valid_name_p(name)) { + rb_name_err_raise_str(rb_fstring_new(message, message_len), + obj, name); + } + return id; +} + /* * call-seq: * obj.remove_instance_variable(symbol) -> obj @@ -1717,25 +1738,14 @@ VALUE https://github.com/ruby/ruby/blob/trunk/variable.c#L1738 rb_obj_remove_instance_variable(VALUE obj, VALUE name) { VALUE val = Qnil; - const ID id = rb_check_id(&name); + const ID id = id_for_var(obj, name, an, instance); st_data_t n, v; struct st_table *iv_index_tbl; st_data_t index; rb_check_frozen(obj); if (!id) { - if (rb_is_instance_name(name)) { - rb_name_error_str(name, "instance variable %"PRIsVALUE" not defined", - name); - } - else { - rb_name_error_str(name, "`%"PRIsVALUE"' is not allowed as an instance variable name", - QUOTE(name)); - } - } - if (!rb_is_instance_id(id)) { - rb_name_error(id, "`%"PRIsVALUE"' is not allowed as an instance variable name", - QUOTE_ID(id)); + goto not_defined; } switch (BUILTIN_TYPE(obj)) { @@ -1766,8 +1776,10 @@ rb_obj_remove_instance_variable(VALUE ob https://github.com/ruby/ruby/blob/trunk/variable.c#L1776 } break; } - rb_name_error(id, "instance variable %"PRIsVALUE" not defined", QUOTE_ID(id)); + not_defined: + rb_name_err_raise("instance variable %1$s not defined", + obj, name); UNREACHABLE; } @@ -1776,11 +1788,11 @@ static void https://github.com/ruby/ruby/blob/trunk/variable.c#L1788 uninitialized_constant(VALUE klass, VALUE name) { if (klass && rb_class_real(klass) != rb_cObject) - rb_name_error_str(name, "uninitialized constant %"PRIsVALUE"::% "PRIsVALUE"", - rb_class_name(klass), name); - else { - rb_name_error_str(name, "uninitialized constant % "PRIsVALUE"", name); - } + rb_name_err_raise("uninitialized constant %2$s::%1$s", + klass, name); + else + rb_name_err_raise("uninitialized constant %1$s", + klass, name); } VALUE @@ -2152,8 +2164,8 @@ rb_const_get_0(VALUE klass, ID id, int e https://github.com/ruby/ruby/blob/trunk/variable.c#L2164 while ((ce = rb_const_lookup(tmp, id))) { if (visibility && RB_CONST_PRIVATE_P(ce)) { - rb_name_error(id, "private constant %"PRIsVALUE"::%"PRIsVALUE" referenced", - rb_class_name(klass), QUOTE_ID(id)); + rb_name_err_raise("private constant %2$s::%1$s referenced", + klass, ID2SYM(id)); } if (RB_CONST_DEPRECATED_P(ce)) { if (klass == rb_cObject) { @@ -2239,21 +2251,11 @@ rb_public_const_get_at(VALUE klass, ID i https://github.com/ruby/ruby/blob/trunk/variable.c#L2251 VALUE rb_mod_remove_const(VALUE mod, VALUE name) { - const ID id = rb_check_id(&name); + const ID id = id_for_var(mod, name, a, constant); if (!id) { - if (rb_is_const_name(name)) { - rb_name_error_str(name, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined", - rb_class_name(mod), name); - } - else { - rb_name_error_str(name, "`%"PRIsVALUE"' is not allowed as a constant name", - QUOTE(name)); - } - } - if (!rb_is_const_id(id)) { - rb_name_error(id, "`%"PRIsVALUE"' is not allowed as a constant name", - QUOTE_ID(id)); + rb_name_err_raise("constant %2$s::%1$s not defined", + mod, name); } return rb_const_remove(mod, id); } @@ -2267,11 +2269,11 @@ rb_const_remove(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2269 rb_check_frozen(mod); if (!RCLASS_CONST_TBL(mod) || !st_delete(RCLASS_CONST_TBL(mod), &n, &v)) { if (rb_const_defined_at(mod, id)) { - rb_name_error(id, "cannot remove %"PRIsVALUE"::%"PRIsVALUE"", - rb_class_name(mod), QUOTE_ID(id)); + rb_name_err_raise("cannot remove %2$s::%1$s", + mod, ID2SYM(id)); } - rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined", - rb_class_name(mod), QUOTE_ID(id)); + rb_name_err_raise("constant %2$s::%1$s not defined", + mod, ID2SYM(id)); } rb_clear_constant_cache(); @@ -2616,8 +2618,8 @@ set_const_visibility(VALUE mod, int argc https://github.com/ruby/ruby/blob/trunk/variable.c#L2618 rb_clear_constant_cache(); } - rb_name_error_str(val, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined", - rb_class_name(mod), QUOTE(val)); + rb_name_err_raise("constant %2$s::%1$s not defined", + mod, val); } if ((ce = rb_const_lookup(mod, id))) { ce->flag &= ~mask; @@ -2627,8 +2629,8 @@ set_const_visibility(VALUE mod, int argc https://github.com/ruby/ruby/blob/trunk/variable.c#L2629 if (i > 0) { rb_clear_constant_cache(); } - rb_name_error(id, "constant %"PRIsVALUE"::%"PRIsVALUE" not defined", - rb_class_name(mod), QUOTE_ID(id)); + rb_name_err_raise("constant %2$s::%1$s not defined", + mod, ID2SYM(id)); } } rb_clear_constant_cache(); @@ -2751,8 +2753,8 @@ rb_cvar_get(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2753 tmp = klass; CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;}); if (!target) { - rb_name_error(id, "uninitialized class variable %"PRIsVALUE" in %"PRIsVALUE"", - QUOTE_ID(id), rb_class_name(tmp)); + rb_name_err_raise("uninitialized class variable %1$s in %2$s", + tmp, ID2SYM(id)); } if (front && target != front) { st_data_t did = id; @@ -2777,34 +2779,35 @@ rb_cvar_defined(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2779 return Qfalse; } -void -rb_cv_set(VALUE klass, const char *name, VALUE val) +static ID +cv_intern(VALUE klass, const char *name) { ID id = rb_intern(name); if (!rb_is_class_id(id)) { - rb_name_error(id, "wrong class variable name %s", name); + rb_name_err_raise("wrong class variable name %1$s", + klass, rb_str_new_cstr(name)); } + return id; +} + +void +rb_cv_set(VALUE klass, const char *name, VALUE val) +{ + ID id = cv_intern(klass, name); rb_cvar_set(klass, id, val); } VALUE rb_cv_get(VALUE klass, const char *name) { - ID id = rb_intern(name); - if (!rb_is_class_id(id)) { - rb_name_error(id, "wrong class variable name %s", name); - } + ID id = cv_intern(klass, name); return rb_cvar_get(klass, id); } void rb_define_class_variable(VALUE klass, const char *name, VALUE val) { - ID id = rb_intern(name); - - if (!rb_is_class_id(id)) { - rb_name_error(id, "wrong class variable name %s", name); - } + ID id = cv_intern(klass, name); rb_cvar_set(klass, id, val); } @@ -2931,33 +2934,22 @@ rb_mod_class_variables(int argc, const V https://github.com/ruby/ruby/blob/trunk/variable.c#L2934 VALUE rb_mod_remove_cvar(VALUE mod, VALUE name) { - const ID id = rb_check_id(&name); + const ID id = id_for_var_message(mod, name, class, "wrong class variable name %1$s"); st_data_t val, n = id; if (!id) { - if (rb_is_class_name(name)) { - rb_name_error_str(name, "class variable %"PRIsVALUE" not defined for %"PRIsVALUE"", - name, rb_class_name(mod)); - } - else { - rb_name_error_str(name, "wrong class variable name %"PRIsVALUE"", QUOTE(name)); - } - } - if (!rb_is_class_id(id)) { - rb_name_error(id, "wrong class variable name %"PRIsVALUE"", QUOTE_ID(id)); + not_defined: + rb_name_err_raise("class variable %1$s not defined for %2$s", + mod, name); } rb_check_frozen(mod); if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) { return (VALUE)val; } if (rb_cvar_defined(mod, id)) { - rb_name_error(id, "cannot remove %"PRIsVALUE" for %"PRIsVALUE"", - QUOTE_ID(id), rb_class_name(mod)); + rb_name_err_raise("cannot remove %1$s for %2$s", mod, ID2SYM(id)); } - rb_name_error(id, "class variable %"PRIsVALUE" not defined for %"PRIsVALUE"", - QUOTE_ID(id), rb_class_name(mod)); - - UNREACHABLE; + goto not_defined; } VALUE Index: eval_error.c =================================================================== --- eval_error.c (revision 52320) +++ eval_error.c (revision 52321) @@ -208,47 +208,53 @@ ruby_error_print(void) https://github.com/ruby/ruby/blob/trunk/eval_error.c#L208 error_print(); } -static const char * -method_visibility_name(rb_method_visibility_t visi) -{ - switch (visi) { - case METHOD_VISI_UNDEF: - case METHOD_VISI_PUBLIC: return ""; - case METHOD_VISI_PRIVATE: return " private"; - case METHOD_VISI_PROTECTED: return " protected"; - } - rb_bug("method_visibility_name: unreachable (%d)", (int)visi); -} +#define undef_mesg_for(v, k) rb_fstring_cstr("undefined"v" method `%1$s' for "k" `%$s'") +#define undef_mesg(v) ( \ + is_mod ? \ + undef_mesg_for(v, "module") : \ + undef_mesg_for(v, "class")) void rb_print_undef(VALUE klass, ID id, int visi) { - const char *v = method_visibility_name(visi); - - rb_name_error(id, "undefined%s method `%"PRIsVALUE"' for %s `% "PRIsVALUE"'", v, - QUOTE_ID(id), - (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class", - rb_class_name(klass)); + const int is_mod = RB_TYPE_P(klass, T_MODULE); + VALUE mesg; + switch (visi & METHOD_VISI_MASK) { + case METHOD_VISI_UNDEF: + case METHOD_VISI_PUBLIC: mesg = undef_mesg(""); break; + case METHOD_VISI_PRIVATE: mesg = undef_mesg(" private"); break; + case METHOD_VISI_PROTECTED: mesg = undef_mesg(" protected"); break; + default: UNREACHABLE; + } + rb_name_err_raise_str(mesg, klass, ID2SYM(id)); } void rb_print_undef_str(VALUE klass, VALUE name) { - rb_name_error_str(name, "undefined method `%"PRIsVALUE"' for %s `% "PRIsVALUE"'", - QUOTE(name), - (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class", - rb_class_name(klass)); + const int is_mod = RB_TYPE_P(klass, T_MODULE); + rb_name_err_raise_str(undef_mesg(""), klass, name); } +#define inaccessible_mesg_for(v, k) rb_fstring_cstr("method `%1$s' for "k" `%2$s' is "v) +#define inaccessible_mesg(v) ( \ + is_mod ? \ + inaccessible_mesg_for(v, "module") : \ + inaccessible_mesg_for(v, "class")) + void rb_print_inaccessible(VALUE klass, ID id, rb_method_visibility_t visi) { - const char *v = method_visibility_name(visi); - rb_name_error(id, "method `%"PRIsVALUE"' for %s `% "PRIsVALUE"' is %s", - QUOTE_ID(id), - (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class", - rb_class_name(klass), - v); + const int is_mod = RB_TYPE_P(klass, T_MODULE); + VALUE mesg; + switch (visi & METHOD_VISI_MASK) { + case METHOD_VISI_UNDEF: + case METHOD_VISI_PUBLIC: mesg = inaccessible_mesg(""); break; + case METHOD_VISI_PRIVATE: mesg = inaccessible_mesg(" private"); break; + case METHOD_VISI_PROTECTED: mesg = inaccessible_mesg(" protected"); break; + default: UNREACHABLE; + } + rb_name_err_raise_str(mesg, klass, ID2SYM(id)); } static int Index: object.c =================================================================== --- object.c (revision 52320) +++ object.c (revision 52321) @@ -1900,29 +1900,21 @@ rb_class_get_superclass(VALUE klass) https://github.com/ruby/ruby/blob/trunk/object.c#L1900 return RCLASS(klass)->super; } -#define id_for_setter(name, type, message) \ - check_setter_id(name, rb_is_##type##_sym, rb_is_##type##_name, message) +#define id_for_var(obj, name, part, type) \ + id_for_setter(obj, name, type, "`%1$s' is not allowed as "#part" "#type" variable name") +#define id_for_setter(obj, name, type, message) \ + check_setter_id(obj, &(name), rb_is_##type##_id, rb_is_##type##_name, message, strlen(message)) static ID -check_setter_id(VALUE name, int (*valid_sym_p)(VALUE), int (*valid_name_p)(VALUE), - const char *message) -{ - ID id; - if (SYMBOL_P(name)) { - if (!valid_sym_p(name)) { - rb_name_error_str(name, message, QUOTE(rb_sym2str(name))); - } - id = SYM2ID(name); - } - else { - VALUE str = rb_check_string_type(name); - if (NIL_P(str)) { - rb_raise(rb_eTypeError, "% "PRIsVALUE" is not a symbol or string", - name); - } - if (!valid_name_p(str)) { - rb_name_error_str(str, message, QUOTE(str)); - } - id = rb_intern_str(str); +check_setter_id(VALUE obj, VALUE *pname, + int (*valid_id_p)(ID), int (*valid_name_p)(VALUE), + const char *message, size_t message_len) +{ + ID id = rb_check_id(pname); + VALUE name = *pname; + + if (id ? !valid_id_p(id) : !valid_name_p(name)) { + rb_name_err_raise_str(rb_fstring_new(message, message_len), + obj, name); } return id; } @@ -1934,17 +1926,20 @@ rb_is_attr_name(VALUE name) https://github.com/ruby/ruby/blob/trunk/object.c#L1926 } static int -rb_is_attr_sym(VALUE sym) +rb_is_attr_id(ID id) { - return rb_is_local_sym(sym) || rb_is_const_sym(sym); + return rb_is_local_id(id) || rb_is_const_id(id); } -static const char invalid_attribute_name[] = "invalid attribute name `%"PRIsVALUE"'"; +static const char wrong_constant_name[] = "wrong constant name %1$s"; +static const char invalid_attribute_name[] = "invalid attribute name `%1$s'"; static ID -id_for_attr(VALUE name) +id_for_attr(VALUE obj, VALUE name) { - return id_for_setter(name, attr, invalid_attribute_name); + ID id = id_for_setter(obj, name, attr, invalid_attribute_name); + if (!id) id = rb_intern_str(name); + return id; } /* @@ -1966,7 +1961,7 @@ rb_mod_attr_reader(int argc, VALUE *argv https://github.com/ruby/ruby/blob/trunk/object.c#L1961 int i; for (i=0; i<argc; i++) { - rb_attr(klass, id_for_attr(argv[i]), TRUE, FALSE, TRUE); + rb_attr(klass, id_for_attr(klass, argv[i]), TRUE, FALSE, TRUE); } return Qnil; } @@ -1976,7 +1971,7 @@ rb_mod_attr(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/object.c#L1971 { if (argc == 2 && (argv[1] == Qtrue || argv[1] == Qfalse)) { rb_warning("optional boolean argument is obsoleted"); - rb_attr(klass, id_for_attr(argv[0]), 1, RTEST(argv[1]), TRUE); + rb_attr(klass, id_for_attr(klass, argv[0]), 1, RTEST(argv[1]), TRUE); return Qnil; } return rb_mod_attr_reader(argc, argv, klass); @@ -1998,7 +1993,7 @@ rb_mod_attr_writer(int argc, VALUE *argv https://github.com/ruby/ruby/blob/trunk/object.c#L1993 int i; for (i=0; i<argc; i++) { - rb_attr(klass, id_for_attr(argv[i]), FALSE, TRUE, TRUE); + rb_attr(klass, id_for_attr(klass, argv[i]), FALSE, TRUE, TRUE); } return Qnil; } @@ -2026,7 +2021,7 @@ rb_mod_attr_accessor(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/object.c#L2021 int i; for (i=0; i<argc; i++) { - rb_attr(klass, id_for_attr(argv[i]), TRUE, TRUE, TRUE); + rb_attr(klass, id_for_attr(klass, argv[i]), TRUE, TRUE, TRUE); } return Qnil; } @@ -2102,7 +2097,7 @@ rb_mod_const_get(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/object.c#L2097 if (p >= pend || !*p) { wrong_name: - rb_name_error_str(name, "wrong constant name % "PRIsVALUE, name); + rb_name_err_raise(wrong_constant_name, mod, name); } if (p + 2 < pend && p[0] == ':' && p[1] == ':') { @@ -2137,8 +2132,8 @@ rb_mod_const_get(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/object.c#L2132 part = rb_str_subseq(name, beglen, len); OBJ_FREEZE(part); if (!ISUPPER(*pbeg) || !rb_is_const_name(part)) { - rb_name_error_str(part, "wrong constant name %"PRIsVALUE, - QUOTE(part)); + name = part; + goto wrong_name; } else if (!rb_method_basic_definition_p(CLASS_OF(mod), id_const_missing)) { part = rb_str_intern(part); @@ -2146,14 +2141,12 @@ rb_mod_const_get(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/object.c#L2141 continue; } else { - rb_name_error_str(part, "uninitialized constant %"PRIsVALUE"% "PRIsVALUE, - rb_str_subseq(name, 0, beglen), - part); + rb_name_err_raise("uninitialized constant %2$s::%1$s", mod, part); } } if (!rb_is_const_id(id)) { - rb_name_error(id, "wrong constant name %"PRIsVALUE, - QUOTE_ID(id)); + name = ID2SYM(id); + goto wrong_name; } mod = RTEST(recur) ? rb_const_get(mod, id) : rb_const_get_at(mod, id); } @@ -2183,7 +2176,8 @@ rb_mod_const_get(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/object.c#L2176 static VALUE rb_mod_const_set(VALUE mod, VALUE name, VALUE value) { - ID id = id_for_setter(name, const, "wrong constant name %"PRIsVALUE); + ID id = id_for_setter(mod, name, const, wrong_constant_name); + if (!id) id = rb_intern_str(name); rb_const_set(mod, id, value); return value; } @@ -2260,7 +2254,7 @@ rb_mod_const_defined(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/object.c#L2254 if (p >= pend || !*p) { wrong_name: - rb_name_error_str(name, "wrong constant name % "PRIsVALUE, name); + rb_name_err_raise(wrong_constant_name, mod, name); } if (p + 2 < pend && p[0] == ':' && p[1] == ':') { @@ -2290,16 +2284,16 @@ rb_mod_const_defined(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/object.c#L2284 part = rb_str_subseq(name, beglen, len); OBJ_FREEZE(part); if (!ISUPPER(*pbeg) || !rb_is_const_name(part)) { - rb_name_error_str(part, "wrong constant name %"PRIsVALUE, - QUOTE(part)); + name = part; + goto wrong_name; } else { return Qfalse; } } if (!rb_is_const_id(id)) { - rb_name_error(id, "wrong constant name %"PRIsVALUE, - QUOTE_ID(id)); + name = ID2SYM(id); + goto wrong_name; } if (RTEST(recur)) { if (!rb_const_defined(mod, id)) @@ -2347,20 +2341,10 @@ rb_mod_const_defined(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/object.c#L2341 static VALUE rb_obj_ivar_get(VALUE obj, VALUE iv) { - ID id = rb_check_id(&iv); + ID id = id_for_var(obj, iv, an, instance); (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/