diff --git a/common.mk b/common.mk index df8bd7ee11..7d2edee208 100644 --- a/common.mk +++ b/common.mk @@ -17548,6 +17548,7 @@ variable.$(OBJEXT): {$(VPATH)}rubyparser.h variable.$(OBJEXT): {$(VPATH)}shape.h variable.$(OBJEXT): {$(VPATH)}st.h variable.$(OBJEXT): {$(VPATH)}subst.h +variable.$(OBJEXT): {$(VPATH)}symbol.h variable.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h variable.$(OBJEXT): {$(VPATH)}thread_native.h variable.$(OBJEXT): {$(VPATH)}transient_heap.h diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb index 891a363ea2..93a02a4143 100644 --- a/spec/ruby/core/module/set_temporary_name_spec.rb +++ b/spec/ruby/core/module/set_temporary_name_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require_relative 'fixtures/module' ruby_version_is "3.3" do describe "Module#set_temporary_name" do @@ -14,6 +13,15 @@ ruby_version_is "3.3" do m.name.should be_nil end + it "can assign a temporary name which is not a valid constant path" do + m = Module.new + m.set_temporary_name("a::B") + m.name.should == "a::B" + + m.set_temporary_name("Template['foo.rb']") + m.name.should == "Template['foo.rb']" + end + it "can't assign empty string as name" do m = Module.new -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name") @@ -21,7 +29,14 @@ ruby_version_is "3.3" do it "can't assign a constant name as a temporary name" do m = Module.new - -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "name must not be valid constant name") + -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "name must not be valid constant path") + end + + it "can't assign a constant path as a temporary name" do + m = Module.new + -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "name must not be valid constant path") + -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "name must not be valid constant path") + -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "name must not be valid constant path") end it "can't assign name to permanent module" do diff --git a/variable.c b/variable.c index c6c70e1391..79ff8c459c 100644 --- a/variable.c +++ b/variable.c @@ -35,6 +35,7 @@ #include "ruby/util.h" #include "transient_heap.h" #include "shape.h" +#include "symbol.h" #include "variable.h" #include "vm_core.h" #include "ractor_core.h" @@ -134,6 +135,38 @@ rb_mod_name(VALUE mod) return classname(mod, &permanent); } +// Similar to logic in rb_mod_const_get() +static bool +is_constant_path(VALUE name) +{ + const char *path = RSTRING_PTR(name); + const char *pend = RSTRING_END(name); + rb_encoding *enc = rb_enc_get(name); + + const char *p = path; + + if (p >= pend || !*p) { + return false; + } + + while (p < pend) { + if (p + 2 <= pend && p[0] == ':' && p[1] == ':') { + p += 2; + } + + const char *pbeg = p; + while (p < pend && *p != ':') p++; + + if (pbeg == p) return false; + + if (rb_enc_symname_type(pbeg, p - pbeg, enc, 0) != ID_CONST) { + return false; + } + } + + return true; +} + /* * call-seq: * mod.set_temporary_name(string) -> self @@ -196,8 +229,8 @@ rb_mod_set_temporary_name(VALUE mod, VALUE name) rb_raise(rb_eArgError, "empty class/module name"); } - if (rb_is_const_name(name)) { - rb_raise(rb_eArgError, "name must not be valid constant name"); + if (is_constant_path(name)) { + rb_raise(rb_eArgError, "name must not be valid constant path"); } // Set the temporary classpath to the given name: