From 1f299dd309a963f533f107c576966a723568820f Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Tue, 18 Nov 2025 15:42:53 -0800 Subject: [PATCH 01/16] Fix crash in optimal size for large T_OBJECT Previously any T_OBJECT with >= 94 IVARs would crash during compaction attempting to make an object too large to embed. --- gc.c | 8 +++++++- test/ruby/test_gc_compact.rb | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 74502dc21b74a5..c9fa18f42b8e8e 100644 --- a/gc.c +++ b/gc.c @@ -3332,7 +3332,13 @@ rb_gc_obj_optimal_size(VALUE obj) return sizeof(struct RObject); } else { - return rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(obj)); + size_t size = rb_obj_embedded_size(ROBJECT_FIELDS_CAPACITY(obj)); + if (rb_gc_size_allocatable_p(size)) { + return size; + } + else { + return sizeof(struct RObject); + } } case T_STRING: diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb index 32b0a5def0b8f5..a03535171c42e8 100644 --- a/test/ruby/test_gc_compact.rb +++ b/test/ruby/test_gc_compact.rb @@ -361,6 +361,22 @@ def add_ivars end; end + def test_compact_objects_of_varying_sizes + omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 + + assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}", timeout: 10) + begin; + $objects = [] + 160.times do |n| + obj = Class.new.new + n.times { |i| obj.instance_variable_set("@foo" + i.to_s, 0) } + $objects << obj + end + + GC.verify_compaction_references(expand_heap: true, toward: :empty) + end; + end + def test_moving_strings_up_heaps omit if GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT] == 1 From 83b0cfe1b5d5cab1328aeeac0c1c6eb2484b66de Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Wed, 30 Aug 2023 16:52:45 -0600 Subject: [PATCH 02/16] [ruby/rubygems] Handle BUNDLER_VERSION being set to an empty string This is useful, in case you're using Docker, and an upstream Dockerfile sets BUNDLER_VERSION to something you don't want. It's impossible to unset it... only override to be the empty string. https://github.com/ruby/rubygems/commit/ffa3eb9ac6 --- lib/bundler/self_manager.rb | 2 +- lib/rubygems/bundler_version_finder.rb | 1 + test/rubygems/test_gem_bundler_version_finder.rb | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb index 7db6c9f6f1cd9e..1db77fd46b3fef 100644 --- a/lib/bundler/self_manager.rb +++ b/lib/bundler/self_manager.rb @@ -97,7 +97,7 @@ def needs_switching?(restart_version) end def autoswitching_applies? - ENV["BUNDLER_VERSION"].nil? && + (ENV["BUNDLER_VERSION"].nil? || ENV["BUNDLER_VERSION"].empty?) && ruby_can_restart_with_same_arguments? && lockfile_version end diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb index 4ebbad1c0cfa33..ac8988dea577bb 100644 --- a/lib/rubygems/bundler_version_finder.rb +++ b/lib/rubygems/bundler_version_finder.rb @@ -3,6 +3,7 @@ module Gem::BundlerVersionFinder def self.bundler_version v = ENV["BUNDLER_VERSION"] + v = nil if v&.empty? v ||= bundle_update_bundler_version return if v == true diff --git a/test/rubygems/test_gem_bundler_version_finder.rb b/test/rubygems/test_gem_bundler_version_finder.rb index 39255bc4e1d7cb..908f9278323c09 100644 --- a/test/rubygems/test_gem_bundler_version_finder.rb +++ b/test/rubygems/test_gem_bundler_version_finder.rb @@ -32,6 +32,11 @@ def test_bundler_version_with_env_var assert_equal v("1.1.1.1"), bvf.bundler_version end + def test_bundler_version_with_empty_env_var + ENV["BUNDLER_VERSION"] = "" + assert_nil bvf.bundler_version + end + def test_bundler_version_with_bundle_update_bundler ARGV.replace %w[update --bundler] assert_nil bvf.bundler_version From 3b9539176bc37b3e95864b04b0eef1263f434eef Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Mon, 17 Nov 2025 21:33:58 +0100 Subject: [PATCH 03/16] [ruby/rubygems] Warn users that `bundle` now display the help: - In https://github.com/ruby/rubygems/commit/31d67ecc056fb5a9193bc66a6e69e21576a87702 we enforced the new behaviour where running `bundle` no longer installs gems but displays the help. Users now have a way to configure their preferred default command using the `BUNDLE_DEFAULT_CLI_COMMAND` flag. With the preview of Ruby 4.0 now being released, some people will start to see this new change. The problem is that the previous behaviour had existed for like an eternity and we didn't warn users about this change in advance. I'd like to provide a deprecation/warning cycle because this is confusing users already and this breaks various CI setup that now needs to be changed immediately. https://github.com/ruby/rubygems/commit/e415480ac5 --- lib/bundler/cli.rb | 17 ++++++++++++++++- lib/bundler/settings.rb | 1 - spec/bundler/bundler/cli_spec.rb | 12 ++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index 86b86b359fcf82..79f93a7784734c 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -107,7 +107,22 @@ def cli_help shell.say self.class.send(:class_options_help, shell) end - default_task(Bundler.settings[:default_cli_command]) + + def self.default_command(meth = nil) + return super if meth + + default_cli_command = Bundler.settings[:default_cli_command] + return default_cli_command if default_cli_command + + Bundler.ui.warn(<<~MSG) + In the next version of Bundler, running `bundle` without argument will no longer run `bundle install`. + Instead, the `help` command will be displayed. + + If you'd like to keep the previous behaviour please run `bundle config set default_cli_command install --global`. + MSG + + "install" + end class_option "no-color", type: :boolean, desc: "Disable colorization in output" class_option "retry", type: :numeric, aliases: "-r", banner: "NUM", diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 81f1857eec7648..fb1b875b264500 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -83,7 +83,6 @@ class Settings "BUNDLE_VERSION" => "lockfile", "BUNDLE_LOCKFILE_CHECKSUMS" => true, "BUNDLE_CACHE_ALL" => true, - "BUNDLE_DEFAULT_CLI_COMMAND" => "cli_help", "BUNDLE_PLUGINS" => true, "BUNDLE_GLOBAL_GEM_CACHE" => false, "BUNDLE_UPDATE_REQUIRES_ALL_FLAG" => false, diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb index b3a97e72ceb2d8..ee3c0d0fd50ff5 100644 --- a/spec/bundler/bundler/cli_spec.rb +++ b/spec/bundler/bundler/cli_spec.rb @@ -87,14 +87,10 @@ def out_with_macos_man_workaround end context "with no arguments" do - it "prints a concise help message by default" do - bundle "" - expect(err).to be_empty - expect(out).to include("Bundler version #{Bundler::VERSION}"). - and include("\n\nBundler commands:\n\n"). - and include("\n\n Primary commands:\n"). - and include("\n\n Utilities:\n"). - and include("\n\nOptions:\n") + it "installs and log a warning by default" do + bundle "", raise_on_error: false + expect(err).to include("running `bundle` without argument will no longer run `bundle install`.") + expect(err).to include("Could not locate Gemfile") end it "prints a concise help message when default_cli_command set to cli_help" do From 1979f8c07d6c2794dda7b482372c9dc0e9f305b0 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Fri, 14 Nov 2025 10:14:44 -0500 Subject: [PATCH 04/16] [ruby/prism] Add docs for super nodes https://github.com/ruby/prism/commit/69abcdbb18 --- prism/config.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/prism/config.yml b/prism/config.yml index e57aa850445c5d..69a46de628e63c 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -2628,11 +2628,18 @@ nodes: - name: block type: node? kind: BlockNode + comment: | + All other arguments are forwarded as normal, except the original block is replaced with the new block. comment: | - Represents the use of the `super` keyword without parentheses or arguments. + Represents the use of the `super` keyword without parentheses or arguments, but which might have a block. super ^^^^^ + + super { 123 } + ^^^^^^^^^^^^^ + + If it has any other arguments, it would be a `SuperNode` instead. - name: GlobalVariableAndWriteNode fields: - name: name @@ -4508,6 +4515,7 @@ nodes: - name: arguments type: node? kind: ArgumentsNode + comment: "Can be only `nil` when there are empty parentheses, like `super()`." - name: rparen_loc type: location? - name: block @@ -4523,6 +4531,8 @@ nodes: super foo, bar ^^^^^^^^^^^^^^ + + If no arguments are provided (except for a block), it would be a `ForwardingSuperNode` instead. - name: SymbolNode flags: SymbolFlags fields: From cdb9893c552f67a6065dcb165b2040d35c57aee3 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 9 Dec 2024 14:56:58 +0900 Subject: [PATCH 05/16] Win32: Drop support for older than MSVC 8.0/_MSC_VER 1400 Visual C++ 2005 (8.0): - _MSC_VER: 1400 - MSVCRT_VERSION: 80 --- configure.ac | 1 + debug.c | 4 - error.c | 2 +- ext/socket/getaddrinfo.c | 3 - ext/socket/getnameinfo.c | 3 - include/ruby/internal/compiler_is/msvc.h | 13 +-- include/ruby/win32.h | 13 +-- internal/bits.h | 33 +++--- numeric.c | 35 +----- parser_bits.h | 30 ++--- random.c | 2 +- regint.h | 13 --- vm_insnhelper.c | 23 ---- win32/Makefile.sub | 43 ++----- win32/file.c | 4 - win32/win32.c | 143 +---------------------- 16 files changed, 50 insertions(+), 315 deletions(-) diff --git a/configure.ac b/configure.ac index 339ee3b2f2e66e..43e517f370982d 100644 --- a/configure.ac +++ b/configure.ac @@ -526,6 +526,7 @@ AS_CASE(["$target_os"], RT_VER=`echo "$rb_cv_msvcrt" | tr -cd [0-9]` test "$RT_VER" = "" && RT_VER=60 test "$rb_cv_msvcrt" = "ucrt" && RT_VER=140 + AS_IF([test $RT_VER -lt 80], AC_MSG_ERROR(Runtime library $RT_VER is not supported)) AC_DEFINE_UNQUOTED(RUBY_MSVCRT_VERSION, $RT_VER) sysconfdir= ]) diff --git a/debug.c b/debug.c index 4717a0bc9c5e90..b92faa8f369398 100644 --- a/debug.c +++ b/debug.c @@ -168,9 +168,7 @@ ruby_debug_breakpoint(void) } #if defined _WIN32 -# if RUBY_MSVCRT_VERSION >= 80 extern int ruby_w32_rtc_error; -# endif #endif #if defined _WIN32 || defined __CYGWIN__ #include @@ -233,9 +231,7 @@ ruby_env_debug_option(const char *str, int len, void *arg) SET_WHEN("ci", ruby_on_ci, 1); SET_WHEN_UINT("rgengc", &ruby_rgengc_debug, 1, ruby_rgengc_debug = 1); #if defined _WIN32 -# if RUBY_MSVCRT_VERSION >= 80 SET_WHEN("rtc_error", ruby_w32_rtc_error, 1); -# endif #endif #if defined _WIN32 || defined __CYGWIN__ SET_WHEN_UINT("codepage", ruby_w32_codepage, numberof(ruby_w32_codepage), diff --git a/error.c b/error.c index abf50b696aefa6..f452f7b01cf23b 100644 --- a/error.c +++ b/error.c @@ -1076,7 +1076,7 @@ NORETURN(static void die(void)); static void die(void) { -#if defined(_WIN32) && defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 80 +#if defined(_WIN32) _set_abort_behavior( 0, _CALL_REPORTFAULT); #endif diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c index 5b824996552e5f..9a65490b1d662d 100644 --- a/ext/socket/getaddrinfo.c +++ b/ext/socket/getaddrinfo.c @@ -62,9 +62,6 @@ #endif #include #else -#if defined(_MSC_VER) && _MSC_VER <= 1200 -#include -#endif #include #include #include diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c index ffda7f98c73f6d..98da8c1647afb9 100644 --- a/ext/socket/getnameinfo.c +++ b/ext/socket/getnameinfo.c @@ -55,9 +55,6 @@ #endif #endif #ifdef _WIN32 -#if defined(_MSC_VER) && _MSC_VER <= 1200 -#include -#endif #include #include #define snprintf _snprintf diff --git a/include/ruby/internal/compiler_is/msvc.h b/include/ruby/internal/compiler_is/msvc.h index 8a864ea558a53f..824f0ecc21e83a 100644 --- a/include/ruby/internal/compiler_is/msvc.h +++ b/include/ruby/internal/compiler_is/msvc.h @@ -38,19 +38,8 @@ # define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 10000000 / 100000) # define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 100000) -#elif defined(_MSC_FULL_VER) -# define RBIMPL_COMPILER_IS_MSVC 1 -# /* _MSC_FULL_VER = XXYYZZZZ */ -# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_FULL_VER / 1000000) -# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 1000000 / 10000) -# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 10000) - #else -# define RBIMPL_COMPILER_IS_MSVC 1 -# /* _MSC_VER = XXYY */ -# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_VER / 100) -# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_VER % 100) -# define RBIMPL_COMPILER_VERSION_PATCH 0 +# error Unsupported MSVC version #endif #endif /* RBIMPL_COMPILER_IS_MSVC_H */ diff --git a/include/ruby/win32.h b/include/ruby/win32.h index 69e92ed9ffa1ba..57e8ab471b8fc4 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -30,15 +30,10 @@ extern "C++" { /* template without extern "C++" */ #if !defined(_WIN64) && !defined(WIN32) #define WIN32 #endif -#if defined(_MSC_VER) && _MSC_VER <= 1200 -#include -#endif #include #include #include -#if !defined(_MSC_VER) || _MSC_VER >= 1400 #include -#endif #if defined(__cplusplus) && defined(_MSC_VER) } #endif @@ -59,13 +54,7 @@ extern "C++" { /* template without extern "C++" */ #include #include #include -#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200 -extern "C++" { /* template without extern "C++" */ -#endif #include -#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200 -} -#endif #include #include #include @@ -436,7 +425,7 @@ extern int rb_w32_utruncate(const char *path, rb_off_t length); #define HAVE_TRUNCATE 1 #define truncate rb_w32_utruncate -#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1800 +#if defined(_MSC_VER) && _MSC_VER < 1800 #define strtoll _strtoi64 #define strtoull _strtoui64 #endif diff --git a/internal/bits.h b/internal/bits.h index 2b5aecf1128a72..bbd59ffaca5cbc 100644 --- a/internal/bits.h +++ b/internal/bits.h @@ -30,13 +30,13 @@ #include /* for uintptr_t */ #include "internal/compilers.h" /* for MSC_VERSION_SINCE */ -#if MSC_VERSION_SINCE(1310) +#ifdef _MSC_VER # include /* for _byteswap_uint64 */ #endif #if defined(HAVE_X86INTRIN_H) # include /* for _lzcnt_u64 */ -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) # include /* for the following intrinsics */ #endif @@ -50,16 +50,13 @@ # pragma intrinsic(__lzcnt64) #endif -#if MSC_VERSION_SINCE(1310) +#if defined(_MSC_VER) # pragma intrinsic(_rotl) # pragma intrinsic(_rotr) # ifdef _WIN64 # pragma intrinsic(_rotl64) # pragma intrinsic(_rotr64) # endif -#endif - -#if MSC_VERSION_SINCE(1400) # pragma intrinsic(_BitScanForward) # pragma intrinsic(_BitScanReverse) # ifdef _WIN64 @@ -266,7 +263,7 @@ ruby_swap16(uint16_t x) #if __has_builtin(__builtin_bswap16) return __builtin_bswap16(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_ushort(x); #else @@ -281,7 +278,7 @@ ruby_swap32(uint32_t x) #if __has_builtin(__builtin_bswap32) return __builtin_bswap32(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_ulong(x); #else @@ -298,7 +295,7 @@ ruby_swap64(uint64_t x) #if __has_builtin(__builtin_bswap64) return __builtin_bswap64(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_uint64(x); #else @@ -323,7 +320,7 @@ nlz_int32(uint32_t x) #elif defined(__x86_64__) && defined(__LZCNT__) return (unsigned int)_lzcnt_u32(x); -#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ +#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */ unsigned long r; return _BitScanReverse(&r, x) ? (31 - (int)r) : 32; @@ -352,7 +349,7 @@ nlz_int64(uint64_t x) #elif defined(__x86_64__) && defined(__LZCNT__) return (unsigned int)_lzcnt_u64(x); -#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ +#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */ unsigned long r; return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64; @@ -538,7 +535,7 @@ ntz_int32(uint32_t x) #if defined(__x86_64__) && defined(__BMI__) return (unsigned)_tzcnt_u32(x); -#elif MSC_VERSION_SINCE(1400) +#elif defined(_MSC_VER) /* :FIXME: Is there any way to issue TZCNT instead of BSF, apart from using * assembly? Because issuing LZCNT seems possible (see nlz.h). */ unsigned long r; @@ -559,8 +556,8 @@ ntz_int64(uint64_t x) { #if defined(__x86_64__) && defined(__BMI__) return (unsigned)_tzcnt_u64(x); - -#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) +` +#elif defined(_WIN64) && defined(_MSC_VER) unsigned long r; return _BitScanForward64(&r, x) ? (int)r : 64; @@ -608,10 +605,10 @@ RUBY_BIT_ROTL(VALUE v, int n) #elif __has_builtin(__builtin_rotateleft64) && (SIZEOF_VALUE * CHAR_BIT == 64) return __builtin_rotateleft64(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32) return _rotl(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64) return _rotl64(v, n); #elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG) @@ -632,10 +629,10 @@ RUBY_BIT_ROTR(VALUE v, int n) #elif __has_builtin(__builtin_rotateright64) && (SIZEOF_VALUE * CHAR_BIT == 64) return __builtin_rotateright64(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32) return _rotr(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64) return _rotr64(v, n); #elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG) diff --git a/numeric.c b/numeric.c index 731a8095239107..3d6648f7d6fbd7 100644 --- a/numeric.c +++ b/numeric.c @@ -1591,17 +1591,11 @@ rb_float_equal(VALUE x, VALUE y) } else if (RB_FLOAT_TYPE_P(y)) { b = RFLOAT_VALUE(y); -#if MSC_VERSION_BEFORE(1300) - if (isnan(b)) return Qfalse; -#endif } else { return num_equal(x, y); } a = RFLOAT_VALUE(x); -#if MSC_VERSION_BEFORE(1300) - if (isnan(a)) return Qfalse; -#endif return RBOOL(a == b); } @@ -1734,16 +1728,10 @@ rb_float_gt(VALUE x, VALUE y) } else if (RB_FLOAT_TYPE_P(y)) { b = RFLOAT_VALUE(y); -#if MSC_VERSION_BEFORE(1300) - if (isnan(b)) return Qfalse; -#endif } else { return rb_num_coerce_relop(x, y, '>'); } -#if MSC_VERSION_BEFORE(1300) - if (isnan(a)) return Qfalse; -#endif return RBOOL(a > b); } @@ -1777,16 +1765,10 @@ flo_ge(VALUE x, VALUE y) } else if (RB_FLOAT_TYPE_P(y)) { b = RFLOAT_VALUE(y); -#if MSC_VERSION_BEFORE(1300) - if (isnan(b)) return Qfalse; -#endif } else { return rb_num_coerce_relop(x, y, idGE); } -#if MSC_VERSION_BEFORE(1300) - if (isnan(a)) return Qfalse; -#endif return RBOOL(a >= b); } @@ -1819,16 +1801,10 @@ flo_lt(VALUE x, VALUE y) } else if (RB_FLOAT_TYPE_P(y)) { b = RFLOAT_VALUE(y); -#if MSC_VERSION_BEFORE(1300) - if (isnan(b)) return Qfalse; -#endif } else { return rb_num_coerce_relop(x, y, '<'); } -#if MSC_VERSION_BEFORE(1300) - if (isnan(a)) return Qfalse; -#endif return RBOOL(a < b); } @@ -1862,16 +1838,10 @@ flo_le(VALUE x, VALUE y) } else if (RB_FLOAT_TYPE_P(y)) { b = RFLOAT_VALUE(y); -#if MSC_VERSION_BEFORE(1300) - if (isnan(b)) return Qfalse; -#endif } else { return rb_num_coerce_relop(x, y, idLE); } -#if MSC_VERSION_BEFORE(1300) - if (isnan(a)) return Qfalse; -#endif return RBOOL(a <= b); } @@ -1899,10 +1869,7 @@ rb_float_eql(VALUE x, VALUE y) if (RB_FLOAT_TYPE_P(y)) { double a = RFLOAT_VALUE(x); double b = RFLOAT_VALUE(y); -#if MSC_VERSION_BEFORE(1300) - if (isnan(a) || isnan(b)) return Qfalse; -#endif - return RBOOL(a == b); + return RBOOL(a == b); } return Qfalse; } diff --git a/parser_bits.h b/parser_bits.h index ca7535280efb61..cbe42db39631be 100644 --- a/parser_bits.h +++ b/parser_bits.h @@ -30,13 +30,13 @@ #include /* for uintptr_t */ #include "internal/compilers.h" /* for MSC_VERSION_SINCE */ -#if MSC_VERSION_SINCE(1310) +#if defined(_MSC_VER) # include /* for _byteswap_uint64 */ #endif #if defined(HAVE_X86INTRIN_H) # include /* for _lzcnt_u64 */ -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) # include /* for the following intrinsics */ #endif @@ -50,7 +50,7 @@ # pragma intrinsic(__lzcnt64) #endif -#if MSC_VERSION_SINCE(1310) +#if defined(_MSC_VER) # pragma intrinsic(_rotl) # pragma intrinsic(_rotr) # ifdef _WIN64 @@ -59,7 +59,7 @@ # endif #endif -#if MSC_VERSION_SINCE(1400) +#if defined(_MSC_VER) # pragma intrinsic(_BitScanForward) # pragma intrinsic(_BitScanReverse) # ifdef _WIN64 @@ -180,7 +180,7 @@ ruby_swap16(uint16_t x) #if __has_builtin(__builtin_bswap16) return __builtin_bswap16(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_ushort(x); #else @@ -195,7 +195,7 @@ ruby_swap32(uint32_t x) #if __has_builtin(__builtin_bswap32) return __builtin_bswap32(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_ulong(x); #else @@ -212,7 +212,7 @@ ruby_swap64(uint64_t x) #if __has_builtin(__builtin_bswap64) return __builtin_bswap64(x); -#elif MSC_VERSION_SINCE(1310) +#elif defined(_MSC_VER) return _byteswap_uint64(x); #else @@ -237,7 +237,7 @@ nlz_int32(uint32_t x) #elif defined(__x86_64__) && defined(__LZCNT__) return (unsigned int)_lzcnt_u32(x); -#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ +#elif defined(_MSC_VER) /* &&! defined(__AVX2__) */ unsigned long r; return _BitScanReverse(&r, x) ? (31 - (int)r) : 32; @@ -266,7 +266,7 @@ nlz_int64(uint64_t x) #elif defined(__x86_64__) && defined(__LZCNT__) return (unsigned int)_lzcnt_u64(x); -#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */ +#elif defined(_WIN64) && defined(_MSC_VER) /* &&! defined(__AVX2__) */ unsigned long r; return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64; @@ -452,7 +452,7 @@ ntz_int32(uint32_t x) #if defined(__x86_64__) && defined(__BMI__) return (unsigned)_tzcnt_u32(x); -#elif MSC_VERSION_SINCE(1400) +#elif defined(_MSC_VER) /* :FIXME: Is there any way to issue TZCNT instead of BSF, apart from using * assembly? Because issuing LZCNT seems possible (see nlz.h). */ unsigned long r; @@ -474,7 +474,7 @@ ntz_int64(uint64_t x) #if defined(__x86_64__) && defined(__BMI__) return (unsigned)_tzcnt_u64(x); -#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) +#elif defined(_WIN64) && defined(_MSC_VER) unsigned long r; return _BitScanForward64(&r, x) ? (int)r : 64; @@ -522,10 +522,10 @@ RUBY_BIT_ROTL(VALUE v, int n) #elif __has_builtin(__builtin_rotateleft64) && (SIZEOF_VALUE * CHAR_BIT == 64) return __builtin_rotateleft64(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32) return _rotl(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64) return _rotl64(v, n); #elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG) @@ -546,10 +546,10 @@ RUBY_BIT_ROTR(VALUE v, int n) #elif __has_builtin(__builtin_rotateright64) && (SIZEOF_VALUE * CHAR_BIT == 64) return __builtin_rotateright64(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 32) return _rotr(v, n); -#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64) +#elif defined(_MSC_VER) && (SIZEOF_VALUE * CHAR_BIT == 64) return _rotr64(v, n); #elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG) diff --git a/random.c b/random.c index bf5588186c2771..0fd953b81e9eed 100644 --- a/random.c +++ b/random.c @@ -230,7 +230,7 @@ int_pair_to_real_inclusive(uint32_t a, uint32_t b) const uint128_t m = ((uint128_t)1 << dig) | 1; uint128_t x = ((uint128_t)a << 32) | b; r = (double)(uint64_t)((x * m) >> 64); -#elif defined HAVE_UINT64_T && !MSC_VERSION_BEFORE(1300) +#elif defined HAVE_UINT64_T uint64_t x = ((uint64_t)a << dig_u) + (((uint64_t)b + (a >> dig_u)) >> dig_r64); r = (double)x; diff --git a/regint.h b/regint.h index 9924e5f62ab5f3..9f59ca6006deb7 100644 --- a/regint.h +++ b/regint.h @@ -266,19 +266,6 @@ # include #endif -#ifdef _WIN32 -# if defined(_MSC_VER) && (_MSC_VER < 1300) -# ifndef _INTPTR_T_DEFINED -# define _INTPTR_T_DEFINED -typedef int intptr_t; -# endif -# ifndef _UINTPTR_T_DEFINED -# define _UINTPTR_T_DEFINED -typedef unsigned int uintptr_t; -# endif -# endif -#endif /* _WIN32 */ - #ifndef PRIdPTR # ifdef _WIN64 # define PRIdPTR "I64d" diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 1b1eeb69d9ffb4..8495ee59ef438e 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -2518,15 +2518,6 @@ opt_equality_specialized(VALUE recv, VALUE obj) double a = RFLOAT_VALUE(recv); double b = RFLOAT_VALUE(obj); -#if MSC_VERSION_BEFORE(1300) - if (isnan(a)) { - return Qfalse; - } - else if (isnan(b)) { - return Qfalse; - } - else -#endif return RBOOL(a == b); } else if (RBASIC_CLASS(recv) == rb_cString && EQ_UNREDEFINED_P(STRING)) { @@ -2624,37 +2615,27 @@ check_match(rb_execution_context_t *ec, VALUE pattern, VALUE target, enum vm_che } -#if MSC_VERSION_BEFORE(1300) -#define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse; -#else -#define CHECK_CMP_NAN(a, b) /* do nothing */ -#endif - static inline VALUE double_cmp_lt(double a, double b) { - CHECK_CMP_NAN(a, b); return RBOOL(a < b); } static inline VALUE double_cmp_le(double a, double b) { - CHECK_CMP_NAN(a, b); return RBOOL(a <= b); } static inline VALUE double_cmp_gt(double a, double b) { - CHECK_CMP_NAN(a, b); return RBOOL(a > b); } static inline VALUE double_cmp_ge(double a, double b) { - CHECK_CMP_NAN(a, b); return RBOOL(a >= b); } @@ -6878,7 +6859,6 @@ vm_opt_lt(VALUE recv, VALUE obj) else if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); return RBOOL(RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj)); } else { @@ -6903,7 +6883,6 @@ vm_opt_le(VALUE recv, VALUE obj) else if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) { - CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); return RBOOL(RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj)); } else { @@ -6928,7 +6907,6 @@ vm_opt_gt(VALUE recv, VALUE obj) else if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { - CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); return RBOOL(RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj)); } else { @@ -6953,7 +6931,6 @@ vm_opt_ge(VALUE recv, VALUE obj) else if (RBASIC_CLASS(recv) == rb_cFloat && RBASIC_CLASS(obj) == rb_cFloat && BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) { - CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); return RBOOL(RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj)); } else { diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 81a33277afb161..5bad1d3d752861 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -130,6 +130,11 @@ TEST_RUNNABLE = yes CAT_DEPEND = type +!if !defined(MSC_VER) +! error MSC_VER not defined. Retry from configure pass. +!else if $(MSC_VER) < 1400 +! error MSVC $(MSC_VER) is not supported +!endif !if !defined(MACHINE) MACHINE = x86 !endif @@ -140,9 +145,6 @@ PROCESSOR_LEVEL = 5 !if 6 < $(PROCESSOR_LEVEL) PROCESSOR_LEVEL = 6 !endif -!if $(MSC_VER) < 1400 -PROCESSOR_FLAG = -G$(PROCESSOR_LEVEL) -!endif CPU = i$(PROCESSOR_LEVEL)86 ARCH = i386 !else @@ -159,12 +161,8 @@ XCFLAGS = $(XCFLAGS) -DRUBY_DEVEL=1 XCFLAGS = $(XCFLAGS) -Dmodular_gc_dir="$(modular_gc_dir)" !endif !if !defined(OPTFLAGS) -!if $(MSC_VER) < 1400 -OPTFLAGS = -O2b2xg- -!else OPTFLAGS = -O2sy- !endif -!endif !if $(MSC_VER) >= 1900 OPTFLAGS = $(OPTFLAGS) -Zc:inline !endif @@ -176,6 +174,8 @@ PLATFORM = mswin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. +!else if $(RT_VER) < 80 +! error Runtime library $(RT_VER) is not supported !endif !ifndef NTVER NTVER = _WIN32_WINNT_WIN8 @@ -278,13 +278,9 @@ RUNTIMEFLAG = -MD COMPILERFLAG = -Zm600 !endif !if !defined(WARNFLAGS) -!if $(MSC_VER) >= 1400 WARNFLAGS = -W2 -wd4100 -wd4127 -wd4210 -wd4214 -wd4255 -wd4574 \ -wd4668 -wd4710 -wd4711 -wd4820 -wd4996 \ -we4028 -we4142 -we4047 -we4013 -!else -WARNFLAGS = -W2 -!endif !if $(MSC_VER) >= 1944 # https://developercommunity.visualstudio.com/t/warning-C5287:-operands-are-different-e/10877942 WARNFLAGS = $(WARNFLAGS) -wd5287 @@ -318,9 +314,7 @@ EXTSOLIBS = !endif !if !defined(LIBS) LIBS = user32.lib advapi32.lib shell32.lib ws2_32.lib -!if $(MSC_VER) >= 1400 LIBS = $(LIBS) iphlpapi.lib -!endif !if defined(USE_GMP) LIBS = $(LIBS) gmp.lib !endif @@ -697,11 +691,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub !if $(MSC_VER) >= 1920 #define HAVE_AFUNIX_H 1 !endif -!if $(MSC_VER) >= 1400 #define HAVE_LONG_LONG 1 -!else -#define ULL_TO_DOUBLE(n) ((double)(unsigned long)((n)>>32) * (1I64 << 32) + (unsigned long)(n)) -!endif #define HAVE_OFF_T 1 #define rb_off_t __int64 #define SIGNEDNESS_OF_OFF_T -1 @@ -710,11 +700,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define SIZEOF_INT 4 #define SIZEOF_SHORT 2 #define SIZEOF_LONG 4 -!if $(MSC_VER) >= 1400 #define SIZEOF_LONG_LONG 8 -!else -#define SIZEOF_LONG_LONG 0 -!endif #define SIZEOF___INT64 8 #ifndef _INTEGRAL_MAX_BITS #define _INTEGRAL_MAX_BITS 64 @@ -729,15 +715,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define SIZEOF_DOUBLE 8 #define SIGNEDNESS_OF_TIME_T -1 #define NEGATIVE_TIME_T 1 -!if $(RT_VER) >= 80 #define SIZEOF_TIME_T 8 #define TIMET2NUM(v) LL2NUM(v) #define NUM2TIMET(v) NUM2LL(v) -!else -#define SIZEOF_TIME_T 4 -#define TIMET2NUM(v) LONG2NUM(v) -#define NUM2TIMET(v) NUM2LONG(v) -!endif #define CLOCKID2NUM(v) INT2NUM(v) #define NUM2CLOCKID(v) NUM2INT(v) #define SIZEOF_CLOCK_T 4 @@ -753,22 +733,15 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define SIZEOF_INTPTR_T 4 #define SIZEOF_UINTPTR_T 4 !endif -!if $(MSC_VER) < 1400 -#define SIZE_MAX UINT_MAX -!endif !if $(MSC_VER) >= 1800 #define HAVE_VA_COPY 1 !else #define HAVE_VA_COPY_VIA_STRUCT_ASSIGNMENT 1 !endif -!if $(MSC_VER) > 1100 #define NORETURN(x) __declspec(noreturn) x -!endif -!if $(MSC_VER) >= 1300 #define DEPRECATED(x) __declspec(deprecated) x #define RUBY_CXX_DEPRECATED(mesg) __declspec(deprecated(mesg)) #define NOINLINE(x) __declspec(noinline) x -!endif #define ALWAYS_INLINE(x) __forceinline x #define WARN_UNUSED_RESULT(x) x #define MAYBE_UNUSED(x) x @@ -1119,7 +1092,7 @@ s,@LIBPATHFLAG@,-libpath:%s,;t t s,@RPATHFLAG@,,;t t s,@LIBARG@,%s.lib,;t t s,@LINK_SO@,$$(LDSHARED) -Fe$$(@) $$(OBJS) $$(LIBS) $$(LOCAL_LIBS) -link $$(DLDFLAGS) -implib:$$(*F:.so=)-$$(arch).lib -pdb:$$(*F:.so=)-$$(arch).pdb -def:$$(DEFFILE),;t t -!if $(MSC_VER) >= 1400 && $(MSC_VER) < 1800 +!if $(MSC_VER) < 1800 s,@LINK_SO@,@if exist $$(@).manifest $$(RUBY) -run -e wait_writable -- -n 10 $$(@),;t t s,@LINK_SO@,@if exist $$(@).manifest $(MANIFESTTOOL) -manifest $$(@).manifest -outputresource:$$(@);2,;t t s,@LINK_SO@,@if exist $$(@).manifest $$(RM) $$(@:/=\).manifest,;t t diff --git a/win32/file.c b/win32/file.c index f137f04c43db94..26b99715cd6ca8 100644 --- a/win32/file.c +++ b/win32/file.c @@ -629,14 +629,10 @@ rb_freopen(VALUE fname, const char *mode, FILE *file) len = MultiByteToWideChar(CP_UTF8, 0, name, n, wname, len); wname[len] = L'\0'; RB_GC_GUARD(fname); -#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__WFREOPEN_S) - e = _wfreopen(wname, wmode, file) ? 0 : errno; -#else { FILE *newfp = 0; e = _wfreopen_s(&newfp, wname, wmode, file); } -#endif ALLOCV_END(wtmp); return e; } diff --git a/win32/win32.c b/win32/win32.c index e7dfe2b065975a..9cffd67597aae0 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -21,6 +21,10 @@ #undef __STRICT_ANSI__ +/* Visual C++ 2005 (8.0): + * - _MSC_VER: 1400 + * - MSVCRT_VERSION: 80 + */ #include "ruby/ruby.h" #include "ruby/encoding.h" #include "ruby/io.h" @@ -42,7 +46,7 @@ #include #include #include -#if defined _MSC_VER && _MSC_VER >= 1400 +#if defined _MSC_VER #include #include #endif @@ -65,10 +69,6 @@ #include "encindex.h" #define isdirsep(x) ((x) == '/' || (x) == '\\') -#if defined _MSC_VER && _MSC_VER <= 1200 -# define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags)) -#endif - static int w32_wopen(const WCHAR *file, int oflag, int perm); static int w32_stati128(const char *path, struct stati128 *st, UINT cp, BOOL lstat); static char *w32_getenv(const char *name, UINT cp); @@ -503,11 +503,6 @@ rb_w32_special_folder(int type) return rb_w32_conv_from_wchar(path, rb_filesystem_encoding()); } -#if defined _MSC_VER && _MSC_VER <= 1200 -/* License: Ruby's */ -#define GetSystemWindowsDirectoryW GetWindowsDirectoryW -#endif - /* License: Ruby's */ UINT rb_w32_system_tmpdir(WCHAR *path, UINT len) @@ -629,7 +624,6 @@ init_env(void) static void init_stdhandle(void); -#if RUBY_MSVCRT_VERSION >= 80 /* License: Ruby's */ static void invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy) @@ -639,7 +633,7 @@ invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, int ruby_w32_rtc_error; -# ifndef __MINGW32__ +#ifndef __MINGW32__ /* License: Ruby's */ RBIMPL_ATTR_NONNULL((5)) RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 5, 6) @@ -658,7 +652,6 @@ rtc_error_handler(int e, const char *src, int line, const char *exe, const char rb_write_error2(RSTRING_PTR(str), RSTRING_LEN(str)); return 0; } -# endif #endif static CRITICAL_SECTION select_mutex; @@ -852,13 +845,11 @@ socklist_delete(SOCKET *sockp, int *flagp) return ret; } -#if RUBY_MSVCRT_VERSION >= 80 # ifdef __MINGW32__ # define _CrtSetReportMode(type,mode) ((void)0) # define _RTC_SetErrorFunc(func) ((void)0) # endif static void set_pioinfo_extra(void); -#endif static int w32_cmdvector(const WCHAR *, char ***, UINT, rb_encoding *); // // Initialization stuff @@ -867,13 +858,10 @@ static int w32_cmdvector(const WCHAR *, char ***, UINT, rb_encoding *); void rb_w32_sysinit(int *argc, char ***argv) { -#if RUBY_MSVCRT_VERSION >= 80 - _CrtSetReportMode(_CRT_ASSERT, 0); _set_invalid_parameter_handler(invalid_parameter); _RTC_SetErrorFunc(rtc_error_handler); set_pioinfo_extra(); -#endif SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX); get_version(); @@ -2464,10 +2452,8 @@ typedef struct { char pipech; /* one char buffer for handles opened on pipes */ int lockinitflag; CRITICAL_SECTION lock; -#if RUBY_MSVCRT_VERSION >= 80 char textmode; char pipech2[2]; -#endif } ioinfo; #endif @@ -2492,7 +2478,6 @@ static inline ioinfo* _pioinfo(int); #define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock) #define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock) -#if RUBY_MSVCRT_VERSION >= 80 static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */ /* License: Ruby's */ @@ -2656,9 +2641,6 @@ set_pioinfo_extra(void) pioinfo_extra = 0; } } -#else -#define pioinfo_extra 0 -#endif static inline ioinfo* _pioinfo(int fd) @@ -4235,7 +4217,6 @@ socketpair(int af, int type, int protocol, int *sv) return 0; } -#if !defined(_MSC_VER) || _MSC_VER >= 1400 /* License: Ruby's */ static void str2guid(const char *str, GUID *guid) @@ -4361,7 +4342,6 @@ freeifaddrs(struct ifaddrs *ifp) ifp = next; } } -#endif #if 0 // Have never been used // @@ -7592,20 +7572,6 @@ rb_w32_write_console(uintptr_t strarg, int fd) return (long)reslen; } -#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S) -/* License: Ruby's */ -static int -unixtime_to_filetime(time_t time, FILETIME *ft) -{ - ULARGE_INTEGER tmp; - - tmp.QuadPart = unix_to_filetime((ULONGLONG)time); - ft->dwLowDateTime = tmp.LowPart; - ft->dwHighDateTime = tmp.HighPart; - return 0; -} -#endif - /* License: Ruby's */ static int timespec_to_filetime(const struct timespec *ts, FILETIME *ft) @@ -7982,23 +7948,6 @@ rb_w32_isatty(int fd) return 1; } -#if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60 -extern long _ftol(double); -/* License: Ruby's */ -long -_ftol2(double d) -{ - return _ftol(d); -} - -/* License: Ruby's */ -long -_ftol2_sse(double d) -{ - return _ftol(d); -} -#endif - #ifndef signbit /* License: Ruby's */ int @@ -8030,68 +7979,6 @@ rb_w32_fd_is_text(int fd) return _osfile(fd) & FTEXT; } -#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S) -/* License: Ruby's */ -static int -unixtime_to_systemtime(const time_t t, SYSTEMTIME *st) -{ - FILETIME ft; - if (unixtime_to_filetime(t, &ft)) return -1; - if (!FileTimeToSystemTime(&ft, st)) return -1; - return 0; -} - -/* License: Ruby's */ -static void -systemtime_to_tm(const SYSTEMTIME *st, struct tm *t) -{ - int y = st->wYear, m = st->wMonth, d = st->wDay; - t->tm_sec = st->wSecond; - t->tm_min = st->wMinute; - t->tm_hour = st->wHour; - t->tm_mday = st->wDay; - t->tm_mon = st->wMonth - 1; - t->tm_year = y - 1900; - t->tm_wday = st->wDayOfWeek; - switch (m) { - case 1: - break; - case 2: - d += 31; - break; - default: - d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400))); - d += ((m - 3) * 153 + 2) / 5; - break; - } - t->tm_yday = d - 1; -} - -/* License: Ruby's */ -static int -systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst) -{ - TIME_ZONE_INFORMATION stdtz; - SYSTEMTIME sst; - - if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1; - if (!tz) { - GetTimeZoneInformation(&stdtz); - tz = &stdtz; - } - if (tz->StandardBias == tz->DaylightBias) return 0; - if (!tz->StandardDate.wMonth) return 0; - if (!tz->DaylightDate.wMonth) return 0; - if (tz != &stdtz) stdtz = *tz; - - stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0; - if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0; - if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour) - return 0; - return 1; -} -#endif - #ifdef HAVE__GMTIME64_S # ifndef HAVE__LOCALTIME64_S /* assume same as _gmtime64_s() */ @@ -8115,17 +8002,8 @@ gmtime_r(const time_t *tp, struct tm *rp) errno = e; return NULL; } -#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S) e = gmtime_s(rp, tp); if (e != 0) goto error; -#else - { - SYSTEMTIME st; - if (unixtime_to_systemtime(*tp, &st)) goto error; - rp->tm_isdst = 0; - systemtime_to_tm(&st, rp); - } -#endif return rp; } @@ -8139,17 +8017,8 @@ localtime_r(const time_t *tp, struct tm *rp) errno = e; return NULL; } -#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S) e = localtime_s(rp, tp); if (e) goto error; -#else - { - SYSTEMTIME gst, lst; - if (unixtime_to_systemtime(*tp, &gst)) goto error; - rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst); - systemtime_to_tm(&lst, rp); - } -#endif return rp; } From 3dd39134cde1a5ecd3c5d3128afcabd3c95e5bea Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 9 Dec 2024 14:58:15 +0900 Subject: [PATCH 06/16] Win32: Drop support for older than MSVC 9.0/_MSC_VER 1500 Visual C++ 2008 (9.0): - _MSC_VER: 1500 - MSVCRT_VERSION: 90 --- configure.ac | 2 +- ext/socket/rubysocket.h | 2 -- regint.h | 4 +--- win32/Makefile.sub | 6 ++---- win32/win32.c | 6 +++--- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 43e517f370982d..fc24e847366687 100644 --- a/configure.ac +++ b/configure.ac @@ -526,7 +526,7 @@ AS_CASE(["$target_os"], RT_VER=`echo "$rb_cv_msvcrt" | tr -cd [0-9]` test "$RT_VER" = "" && RT_VER=60 test "$rb_cv_msvcrt" = "ucrt" && RT_VER=140 - AS_IF([test $RT_VER -lt 80], AC_MSG_ERROR(Runtime library $RT_VER is not supported)) + AS_IF([test $RT_VER -lt 90], AC_MSG_ERROR(Runtime library $RT_VER is not supported)) AC_DEFINE_UNQUOTED(RUBY_MSVCRT_VERSION, $RT_VER) sysconfdir= ]) diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 29b8afc1634b80..1adccee4276da0 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -510,8 +510,6 @@ extern ID tcp_fast_fallback; const char *inet_ntop(int, const void *, char *, size_t); #elif defined __MINGW32__ # define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l) -#elif defined _MSC_VER && RUBY_MSVCRT_VERSION < 90 -const char *WSAAPI inet_ntop(int, const void *, char *, size_t); #endif #endif diff --git a/regint.h b/regint.h index 9f59ca6006deb7..9d69e2d25e51a8 100644 --- a/regint.h +++ b/regint.h @@ -215,9 +215,7 @@ #define xmemcpy memcpy #define xmemmove memmove -#if ((defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 90) \ - || (!defined(RUBY_MSVCRT_VERSION) && defined(_WIN32))) \ - && !defined(__GNUC__) +#if defined(_WIN32) && !defined(__GNUC__) # define xalloca _alloca # define xvsnprintf(buf,size,fmt,args) _vsnprintf_s(buf,size,_TRUNCATE,fmt,args) # define xsnprintf sprintf_s diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 5bad1d3d752861..d2b080c9392b9d 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -132,7 +132,7 @@ CAT_DEPEND = type !if !defined(MSC_VER) ! error MSC_VER not defined. Retry from configure pass. -!else if $(MSC_VER) < 1400 +!else if $(MSC_VER) < 1500 ! error MSVC $(MSC_VER) is not supported !endif !if !defined(MACHINE) @@ -174,7 +174,7 @@ PLATFORM = mswin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. -!else if $(RT_VER) < 80 +!else if $(RT_VER) < 90 ! error Runtime library $(RT_VER) is not supported !endif !ifndef NTVER @@ -749,11 +749,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define FUNC_STDCALL(x) __stdcall x #define FUNC_CDECL(x) __cdecl x #define FUNC_FASTCALL(x) __fastcall x -!if $(MSC_VER) >= 1500 #define RUBY_FUNCTION_NAME_STRING __FUNCTION__ #define RBIMPL_ATTR_PACKED_STRUCT_BEGIN() __pragma(pack(push, 1)) #define RBIMPL_ATTR_PACKED_STRUCT_END() __pragma(pack(pop)) -!endif #define RUBY_EXTERN extern __declspec(dllimport) #define RUBY_FUNC_EXPORTED extern __declspec(dllexport) #define RUBY_ALIGNAS(n) __declspec(align(n)) diff --git a/win32/win32.c b/win32/win32.c index 9cffd67597aae0..23233635819631 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -21,9 +21,9 @@ #undef __STRICT_ANSI__ -/* Visual C++ 2005 (8.0): - * - _MSC_VER: 1400 - * - MSVCRT_VERSION: 80 +/* Visual C++ 2008 (9.0): + * - _MSC_VER: 1500 + * - MSVCRT_VERSION: 90 */ #include "ruby/ruby.h" #include "ruby/encoding.h" From 25f9e678bfb118309300de90803fe1ba4751f7da Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 9 Dec 2024 15:00:05 +0900 Subject: [PATCH 07/16] Win32: Drop support for older than MSVC 10.0/_MSC_VER 1600 Visual C++ 2010 (10.0): - _MSC_VER: 1600 - MSVCRT_VERSION: 100 --- win32/Makefile.sub | 35 ++--------------------------------- win32/win32.c | 6 +++--- 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/win32/Makefile.sub b/win32/Makefile.sub index d2b080c9392b9d..5152e11d45d010 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -132,7 +132,7 @@ CAT_DEPEND = type !if !defined(MSC_VER) ! error MSC_VER not defined. Retry from configure pass. -!else if $(MSC_VER) < 1500 +!else if $(MSC_VER) < 1600 ! error MSVC $(MSC_VER) is not supported !endif !if !defined(MACHINE) @@ -174,7 +174,7 @@ PLATFORM = mswin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. -!else if $(RT_VER) < 90 +!else if $(RT_VER) < 100 ! error Runtime library $(RT_VER) is not supported !endif !ifndef NTVER @@ -262,11 +262,7 @@ OUTFLAG = -Fe COUTFLAG = -Fo !endif !if !defined(CPPOUTFLAG) -! if $(MSC_VER) < 1600 -CPPOUTFLAG = > -! else CPPOUTFLAG = -Fi -! endif !endif !if !defined(CSRCFLAG) CSRCFLAG = -Tc @@ -367,10 +363,8 @@ MAINLIBS = $(LIBS) SOLIBS = RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc !ifndef RCFLAGS -!if $(MSC_VER) >= 1600 RCFLAGS=-nologo !endif -!endif ENABLE_SHARED = yes LIBRUBY_LDSHARED = $(LDSHARED) @@ -770,31 +764,8 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub !if $(MSC_VER) >= 1900 #define HAVE_STRUCT_TIMESPEC !endif -!if $(MSC_VER) >= 1600 #define HAVE_INTTYPES_H 1 #define HAVE_STDINT_H 1 -!else -#define int8_t signed char -#define uint8_t unsigned char -#define int16_t short -#define uint16_t unsigned short -#define int32_t int -#define uint32_t unsigned int -#define int64_t __int64 -#define uint64_t unsigned __int64 -#define INT8_MIN _I8_MIN -#define INT8_MAX _I8_MAX -#define UINT8_MAX _UI8_MAX -#define INT16_MIN _I16_MIN -#define INT16_MAX _I16_MAX -#define UINT16_MAX _UI16_MAX -#define INT32_MIN _I32_MIN -#define INT32_MAX _I32_MAX -#define UINT32_MAX _UI32_MAX -#define INT64_MIN _I64_MIN -#define INT64_MAX _I64_MAX -#define UINT64_MAX _UI64_MAX -!endif #define HAVE_INT8_T 1 #define HAVE_UINT8_T 1 #define SIZEOF_INT8_T 1 @@ -911,9 +882,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define HAVE_QSORT_S !endif #define HAVE_TYPE_NET_LUID 1 -!if $(MSC_VER) >= 1600 #define HAVE_NULLPTR 1 -!endif #define SETPGRP_VOID 1 #define RSHIFT(x,y) ((x)>>(int)y) #define HAVE_RB_FD_INIT 1 diff --git a/win32/win32.c b/win32/win32.c index 23233635819631..e10d4743ec420a 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -21,9 +21,9 @@ #undef __STRICT_ANSI__ -/* Visual C++ 2008 (9.0): - * - _MSC_VER: 1500 - * - MSVCRT_VERSION: 90 +/* Visual C++ 2010 (10.0): + * - _MSC_VER: 1600 + * - MSVCRT_VERSION: 100 */ #include "ruby/ruby.h" #include "ruby/encoding.h" From 7743123551eded908f0606319a66df1f123c7cd9 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 9 Dec 2024 15:04:01 +0900 Subject: [PATCH 08/16] Win32: Drop support for older than MSVC 12.0/_MSC_VER 1800 Visual C++ 2013 (12.0): - _MSC_VER: 1800 - MSVCRT_VERSION: 120 --- configure.ac | 2 +- include/ruby/win32.h | 7 +---- win32/Makefile.sub | 62 ++------------------------------------------ win32/win32.c | 10 +++---- 4 files changed, 7 insertions(+), 74 deletions(-) diff --git a/configure.ac b/configure.ac index fc24e847366687..55d65534db9ee6 100644 --- a/configure.ac +++ b/configure.ac @@ -526,7 +526,7 @@ AS_CASE(["$target_os"], RT_VER=`echo "$rb_cv_msvcrt" | tr -cd [0-9]` test "$RT_VER" = "" && RT_VER=60 test "$rb_cv_msvcrt" = "ucrt" && RT_VER=140 - AS_IF([test $RT_VER -lt 90], AC_MSG_ERROR(Runtime library $RT_VER is not supported)) + AS_IF([test $RT_VER -lt 120], AC_MSG_ERROR(Runtime library $RT_VER is not supported)) AC_DEFINE_UNQUOTED(RUBY_MSVCRT_VERSION, $RT_VER) sysconfdir= ]) diff --git a/include/ruby/win32.h b/include/ruby/win32.h index 57e8ab471b8fc4..8d9f9ddd80be6b 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -342,7 +342,7 @@ extern int rb_w32_dup2(int, int); #include -#if defined _MSC_VER && _MSC_VER >= 1800 && defined INFINITY +#if defined _MSC_VER && defined INFINITY #pragma warning(push) #pragma warning(disable:4756) static inline float @@ -425,11 +425,6 @@ extern int rb_w32_utruncate(const char *path, rb_off_t length); #define HAVE_TRUNCATE 1 #define truncate rb_w32_utruncate -#if defined(_MSC_VER) && _MSC_VER < 1800 -#define strtoll _strtoi64 -#define strtoull _strtoui64 -#endif - /* * stubs */ diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 5152e11d45d010..ab787d8ddd71c2 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -132,7 +132,7 @@ CAT_DEPEND = type !if !defined(MSC_VER) ! error MSC_VER not defined. Retry from configure pass. -!else if $(MSC_VER) < 1600 +!else if $(MSC_VER) < 1800 ! error MSVC $(MSC_VER) is not supported !endif !if !defined(MACHINE) @@ -174,7 +174,7 @@ PLATFORM = mswin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. -!else if $(RT_VER) < 100 +!else if $(RT_VER) < 120 ! error Runtime library $(RT_VER) is not supported !endif !ifndef NTVER @@ -318,9 +318,6 @@ LIBS = $(LIBS) imagehlp.lib shlwapi.lib bcrypt.lib $(EXTLIBS) !endif !if !defined(MISSING) MISSING = crypt.obj ffs.obj langinfo.obj lgamma_r.obj strlcat.obj strlcpy.obj win32/win32.obj win32/file.obj setproctitle.obj -!if $(RT_VER) < 120 -MISSING = $(MISSING) acosh.obj cbrt.obj erf.obj nan.obj tgamma.obj -!endif MISSING = $(MISSING) explicit_bzero.obj !endif DLNOBJ = dln.obj @@ -343,15 +340,7 @@ ARFLAGS = -machine:$(MACHINE) -out: LD = $(CC) LDSHARED = $(LD) -LD XCFLAGS = -DRUBY_EXPORT $(INCFLAGS) $(XCFLAGS) $(XINCFLAGS) -!if $(MSC_VER) >= 1800 LDFLAGS = $(LDFLAGS) -manifest:embed,ID=2 -!elseif $(MSC_VER) >= 1400 -# Prevents VC++ 2005 (cl ver 14) warnings -MANIFESTTOOL = mt -nologo -LDSHARED_0 = @if exist $(@).manifest $(MINIRUBY) -run -e wait_writable -- -n 10 $@ -LDSHARED_1 = @if exist $(@).manifest $(MANIFESTTOOL) -manifest $(@).manifest -outputresource:$(@);2 -LDSHARED_2 = @if exist $(@).manifest @$(RM) $(@:/=\).manifest -!endif CPPFLAGS = $(DEFS) $(ARCHDEFS) $(CPPFLAGS) !if "$(USE_RUBYGEMS)" == "no" CPPFLAGS = -DDISABLE_RUBYGEMS $(CPPFLAGS) @@ -675,9 +664,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define STDC_HEADERS 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_STAT_H 1 -!if $(MSC_VER) >= 1800 #define HAVE_STDBOOL_H 1 -!endif #define HAVE_STDLIB_H 1 #define HAVE_STDDEF_H 1 #define HAVE_STRING_H 1 @@ -727,11 +714,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define SIZEOF_INTPTR_T 4 #define SIZEOF_UINTPTR_T 4 !endif -!if $(MSC_VER) >= 1800 #define HAVE_VA_COPY 1 -!else -#define HAVE_VA_COPY_VIA_STRUCT_ASSIGNMENT 1 -!endif #define NORETURN(x) __declspec(noreturn) x #define DEPRECATED(x) __declspec(deprecated) x #define RUBY_CXX_DEPRECATED(mesg) __declspec(deprecated(mesg)) @@ -796,7 +779,6 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define PRI_PIDT_PREFIX PRI_INT_PREFIX #define GETGROUPS_T int #define TYPEOF_TIMEVAL_TV_SEC long -!if $(RT_VER) >= 120 #define HAVE_ACOSH 1 #define HAVE_ASINH 1 #define HAVE_ATANH 1 @@ -808,7 +790,6 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define HAVE_ROUND 1 #define HAVE_TGAMMA 1 #define HAVE_NEXTAFTER 1 -!endif #define HAVE_ALLOCA 1 #define HAVE_DUP2 1 #define HAVE_MEMCMP 1 @@ -825,14 +806,10 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define HAVE_STRCHR 1 #define HAVE_STRSTR 1 #define HAVE_FLOCK 1 -!if $(MSC_VER) >= 1800 #define HAVE_ISINF 1 -!endif #define HAVE_ISNAN 1 #define HAVE_FINITE 1 -!if $(RT_VER) >= 120 #define HAVE_NAN 1 -!endif #define HAVE_HYPOT 1 #define HAVE_FMOD 1 #define HAVE_FREXP 1 @@ -891,11 +868,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define RUBY_JMP_BUF jmp_buf #ifndef __cplusplus #define inline __inline -!if $(MSC_VER) >= 1800 #define restrict __restrict -!else -#define restrict /* not supported */ -!endif #endif #define NEED_IO_SEEK_BETWEEN_RW 1 !if "$(MACHINE)" == "x86" || "$(ARCH)" == "x64" @@ -1059,11 +1032,6 @@ s,@LIBPATHFLAG@,-libpath:%s,;t t s,@RPATHFLAG@,,;t t s,@LIBARG@,%s.lib,;t t s,@LINK_SO@,$$(LDSHARED) -Fe$$(@) $$(OBJS) $$(LIBS) $$(LOCAL_LIBS) -link $$(DLDFLAGS) -implib:$$(*F:.so=)-$$(arch).lib -pdb:$$(*F:.so=)-$$(arch).pdb -def:$$(DEFFILE),;t t -!if $(MSC_VER) < 1800 -s,@LINK_SO@,@if exist $$(@).manifest $$(RUBY) -run -e wait_writable -- -n 10 $$(@),;t t -s,@LINK_SO@,@if exist $$(@).manifest $(MANIFESTTOOL) -manifest $$(@).manifest -outputresource:$$(@);2,;t t -s,@LINK_SO@,@if exist $$(@).manifest $$(RM) $$(@:/=\).manifest,;t t -!endif s,@COMPILE_C@,$$(CC) $$(INCFLAGS) $$(CFLAGS) $$(CPPFLAGS) $$(COUTFLAG)$$(@) -c $$(CSRCFLAG)$$(<:\=/),;t t s,@COMPILE_CXX@,$$(CXX) $$(INCFLAGS) $$(CXXFLAGS) $$(CPPFLAGS) $$(COUTFLAG)$$(@) -c -Tp$$(<:\=/),;t t s,@ASSEMBLE_C@,$$(CC) $$(CFLAGS) $$(CPPFLAGS) -Fa$$(@) -c $$(CSRCFLAG)$$(<:\=/),;t t @@ -1145,11 +1113,6 @@ $(PROGRAM): $(MAINOBJ) $(LIBRUBY_SO) $(RUBY_INSTALL_NAME).res $(ECHO) linking $(@:\=/) $(Q) $(PURIFY) $(CC) $(MAINOBJ) $(EXTOBJS) $(RUBY_INSTALL_NAME).res \ $(OUTFLAG)$@ $(LIBRUBYARG) -link $(LDFLAGS) $(XLDFLAGS) -! if defined(LDSHARED_0) - $(Q) $(LDSHARED_0) - $(Q) $(LDSHARED_1) - $(Q) $(LDSHARED_2) -! endif !endif !if "$(WPROGRAM)" != "" @@ -1158,11 +1121,6 @@ $(WPROGRAM): $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_SO) $(RUBYW_INSTALL_NAME).res $(Q) $(PURIFY) $(CC) $(MAINOBJ) $(WINMAINOBJ) \ $(RUBYW_INSTALL_NAME).res $(OUTFLAG)$@ $(LIBRUBYARG) \ -link $(LDFLAGS) $(XLDFLAGS) -subsystem:Windows -! if defined(LDSHARED_0) - $(Q) $(LDSHARED_0) - $(Q) $(LDSHARED_1) - $(Q) $(LDSHARED_2) -! endif !endif !if "$(STUBPROGRAM)" != "" @@ -1170,11 +1128,6 @@ $(STUBPROGRAM): rubystub.$(OBJEXT) $(LIBRUBY) $(LIBRUBY_SO) $(RUBY_INSTALL_NAME) $(ECHO) linking $(@:\=/) $(Q) $(PURIFY) $(CC) rubystub.$(OBJEXT) $(RUBY_INSTALL_NAME).res \ $(OUTFLAG)$@ $(LIBRUBYARG) -link $(LDFLAGS) $(XLDFLAGS) -! if defined(LDSHARED_0) - $(Q) $(LDSHARED_0) - $(Q) $(LDSHARED_1) - $(Q) $(LDSHARED_2) -! endif !endif !if "$(LIBRUBY_SO_UPDATE)" == "" @@ -1205,12 +1158,6 @@ $(LIBRUBY_SO): $(LIBRUBY_A) $(DLDOBJS) $(RUBYDEF) $(RUBY_SO_NAME).res $(OUTFLAG)$@ -link $(LDFLAGS) $(XLDFLAGS) \ $(LIBRUBY_DLDFLAGS) @$(RM) dummy.lib dummy.exp -!if defined(LDSHARED_0) - $(Q) $(LDSHARED_0) - $(Q) $(LDSHARED_1) - $(Q) $(LDSHARED_2) -# | findstr -v -c:LNK4049 -c:LNK4217 -!endif $(RUBYDEF): $(LIBRUBY_A) $(RBCONFIG) $(ECHO) generating $(@:\=/) @@ -1445,11 +1392,6 @@ rubyspec-capiext: $(RUBYSPEC_CAPIEXT_EXTS) $(Q)$(MAKEDIRS) $(@D) $(Q)(echo EXPORTS&&echo Init_$(*F))> $*.def $(Q)$(LDSHARED) -Fe$(@) -Fo$(*).obj $(INCFLAGS) $(CFLAGS) $(CPPFLAGS) $< $(LIBRUBYARG) -link $(DLDFLAGS) $(XLDFLAGS) $(LIBS) $(LOCAL_LIBS) -implib:$*.lib -pdb:$*.pdb -def:$*.def -!if defined(LDSHARED_0) - $(Q)$(LDSHARED_0) - $(Q)$(LDSHARED_1) - $(Q)$(LDSHARED_2) -!endif $(Q)$(RM) $*.def $*.exp $*.lib $*.obj $*.pdb exts: rubyspec-capiext diff --git a/win32/win32.c b/win32/win32.c index e10d4743ec420a..a1e63283b9a9bd 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -21,9 +21,9 @@ #undef __STRICT_ANSI__ -/* Visual C++ 2010 (10.0): - * - _MSC_VER: 1600 - * - MSVCRT_VERSION: 100 +/* Visual C++ 2013 (12.0): + * - _MSC_VER: 1800 + * - MSVCRT_VERSION: 120 */ #include "ruby/ruby.h" #include "ruby/encoding.h" @@ -8235,10 +8235,6 @@ rb_w32_set_thread_description_str(HANDLE th, VALUE name) VALUE (*const rb_f_notimplement_)(int, const VALUE *, VALUE, VALUE) = rb_f_notimplement; -#if RUBY_MSVCRT_VERSION < 120 -#include "missing/nextafter.c" -#endif - void * rb_w32_mmap(void *addr, size_t len, int prot, int flags, int fd, rb_off_t offset) { From 1f2913e7417f5193ba52028e2a18c1e01b10d358 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 9 Dec 2024 15:06:13 +0900 Subject: [PATCH 09/16] Win32: Drop support for older than MSVC 14.0/_MSC_VER 1900 Visual C++ 2015 (14.0): - _MSC_VER: 1900 - MSVCRT_VERSION: 140 --- win32/Makefile.sub | 10 ++-------- win32/win32.c | 49 +++++++++++----------------------------------- 2 files changed, 13 insertions(+), 46 deletions(-) diff --git a/win32/Makefile.sub b/win32/Makefile.sub index ab787d8ddd71c2..f95b583fb82a5e 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -132,7 +132,7 @@ CAT_DEPEND = type !if !defined(MSC_VER) ! error MSC_VER not defined. Retry from configure pass. -!else if $(MSC_VER) < 1800 +!else if $(MSC_VER) < 1900 ! error MSVC $(MSC_VER) is not supported !endif !if !defined(MACHINE) @@ -163,9 +163,7 @@ XCFLAGS = $(XCFLAGS) -Dmodular_gc_dir="$(modular_gc_dir)" !if !defined(OPTFLAGS) OPTFLAGS = -O2sy- !endif -!if $(MSC_VER) >= 1900 OPTFLAGS = $(OPTFLAGS) -Zc:inline -!endif !if !defined(incflags) incflags = !endif @@ -174,7 +172,7 @@ PLATFORM = mswin32 !endif !if !defined(RT) !error RT not defined. Retry from configure pass. -!else if $(RT_VER) < 120 +!else if $(RT_VER) < 140 ! error Runtime library $(RT_VER) is not supported !endif !ifndef NTVER @@ -744,9 +742,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define rb_uid_t int #define HAVE_STRUCT_STAT_ST_RDEV 1 #define HAVE_STRUCT_TIMEVAL 1 -!if $(MSC_VER) >= 1900 #define HAVE_STRUCT_TIMESPEC -!endif #define HAVE_INTTYPES_H 1 #define HAVE_STDINT_H 1 #define HAVE_INT8_T 1 @@ -855,9 +851,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define HAVE_SYSTEM 1 #define HAVE_TZSET 1 #define HAVE_UMASK 1 -!if $(RT_VER) > 120 #define HAVE_QSORT_S -!endif #define HAVE_TYPE_NET_LUID 1 #define HAVE_NULLPTR 1 #define SETPGRP_VOID 1 diff --git a/win32/win32.c b/win32/win32.c index a1e63283b9a9bd..66ce195092f5e5 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -21,9 +21,9 @@ #undef __STRICT_ANSI__ -/* Visual C++ 2013 (12.0): - * - _MSC_VER: 1800 - * - MSVCRT_VERSION: 120 +/* Visual C++ 2015 (14.0): + * - _MSC_VER: 1900 + * - MSVCRT_VERSION: 140 */ #include "ruby/ruby.h" #include "ruby/encoding.h" @@ -113,10 +113,8 @@ static char *w32_getenv(const char *name, UINT cp); #undef dup2 #undef strdup -#if RUBY_MSVCRT_VERSION >= 140 -# define _filbuf _fgetc_nolock -# define _flsbuf _fputc_nolock -#endif +#define _filbuf _fgetc_nolock +#define _flsbuf _fputc_nolock #define enough_to_get(n) (--(n) >= 0) #define enough_to_put(n) (--(n) >= 0) @@ -2401,7 +2399,6 @@ rb_w32_closedir(DIR *dirp) return 0; } -#if RUBY_MSVCRT_VERSION >= 140 typedef struct { union { @@ -2421,14 +2418,8 @@ typedef struct { #define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt #define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr #define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file -#else -#define FILE_COUNT(stream) stream->_cnt -#define FILE_READPTR(stream) stream->_ptr -#define FILE_FILENO(stream) stream->_file -#endif /* License: Ruby's */ -#if RUBY_MSVCRT_VERSION >= 140 typedef char lowio_text_mode; typedef char lowio_pipe_lookahead[3]; @@ -2445,30 +2436,14 @@ typedef struct { uint8_t dbcsBufferUsed : 1; // Is the dbcsBuffer in use? char dbcsBuffer; // Buffer for the lead byte of DBCS when converting from DBCS to Unicode } ioinfo; -#else -typedef struct { - intptr_t osfhnd; /* underlying OS file HANDLE */ - char osfile; /* attributes of file (e.g., open in text mode?) */ - char pipech; /* one char buffer for handles opened on pipes */ - int lockinitflag; - CRITICAL_SECTION lock; - char textmode; - char pipech2[2]; -} ioinfo; -#endif #if !defined _CRTIMP || defined __MINGW32__ #undef _CRTIMP #define _CRTIMP __declspec(dllimport) #endif -#if RUBY_MSVCRT_VERSION >= 140 static ioinfo ** __pioinfo = NULL; #define IOINFO_L2E 6 -#else -EXTERN_C _CRTIMP ioinfo * __pioinfo[]; -#define IOINFO_L2E 5 -#endif static inline ioinfo* _pioinfo(int); @@ -2484,13 +2459,12 @@ static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */ static void set_pioinfo_extra(void) { -#if RUBY_MSVCRT_VERSION >= 140 -# define FUNCTION_RET 0xc3 /* ret */ -# ifdef _DEBUG -# define UCRTBASE "ucrtbased.dll" -# else -# define UCRTBASE "ucrtbase.dll" -# endif +#define FUNCTION_RET 0xc3 /* ret */ +#ifdef _DEBUG +# define UCRTBASE "ucrtbased.dll" +#else +# define UCRTBASE "ucrtbase.dll" +#endif /* get __pioinfo addr with _isatty */ /* * Why Ruby depends to _pioinfo is @@ -2625,7 +2599,6 @@ set_pioinfo_extra(void) __pioinfo = *(ioinfo***)(p); #endif #endif /* _M_ARM64 */ -#endif /* RUBY_MSVCRT_VERSION */ int fd; fd = _open("NUL", O_RDONLY); From 69b1c567d71b269edb59a026a9a9f04a6a9a0a49 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 17 Nov 2025 21:28:51 -0500 Subject: [PATCH 10/16] [ruby/mmtk] Add VM barrier in rb_gc_impl_before_fork We need the VM barrier in rb_gc_impl_before_fork to stop the other Ractors because otherwise they could be allocating objects in the fast path which could be calling mmtk_add_obj_free_candidate. Since mmtk_add_obj_free_candidate acquires a lock on obj_free_candidates in weak_proc.rs, this lock may not be released in the child process after the Ractor dies. For example, the following script demonstrates the issue: puts "Hello #{Process.pid}" 100.times do |i| puts "i = #{i}" Ractor.new(i) do |j| puts "Ractor #{j} hello" 1000.times do |i| s = "#{j}-#{i}" end Ractor.receive puts "Ractor #{j} goodbye" end pid = fork { } puts "Child pid is #{pid}" _, status = Process.waitpid2 pid puts status.success? end puts "Goodbye" In the child process, we can see that it is stuck trying to acquire the lock on obj_free_candidates: #5 0x00007192bfb53f10 in mmtk_ruby::weak_proc::WeakProcessor::get_all_obj_free_candidates (self=0x7192c0657498 ) at src/weak_proc.rs:52 #6 0x00007192bfa634c3 in mmtk_ruby::api::mmtk_get_all_obj_free_candidates () at src/api.rs:295 #7 0x00007192bfa61d50 in rb_gc_impl_shutdown_call_finalizer (objspace_ptr=0x578c17abfc50) at gc/mmtk/mmtk.c:1032 #8 0x0000578c1601e48e in rb_ec_finalize (ec=0x578c17ac06d0) at eval.c:166 #9 rb_ec_cleanup (ec=, ex=) at eval.c:257 #10 0x0000578c1601ebf6 in ruby_cleanup (ex=) at eval.c:180 #11 ruby_stop (ex=) at eval.c:292 #12 0x0000578c16127124 in rb_f_fork (obj=) at process.c:4291 #13 rb_f_fork (obj=) at process.c:4281 https://github.com/ruby/mmtk/commit/eb4b229858 --- gc/mmtk/mmtk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index 0d78d61b7fb4b6..428833488c73ed 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -1050,6 +1050,7 @@ rb_gc_impl_before_fork(void *objspace_ptr) struct objspace *objspace = objspace_ptr; objspace->fork_hook_vm_lock_lev = RB_GC_VM_LOCK(); + rb_gc_vm_barrier(); mmtk_before_fork(); } From f040b94cf559855ab3755f6333fb2d4a8f81e0d5 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 17 Nov 2025 21:39:02 -0500 Subject: [PATCH 11/16] [ruby/mmtk] Ensure not blocking for GC in rb_gc_impl_before_fork In rb_gc_impl_before_fork, it locks the VM and barriers all the Ractors before calling mmtk_before_fork. However, since rb_mmtk_block_for_gc is a barrier point, one or more Ractors could be paused there. However, mmtk_before_fork is not compatible with that because it assumes that the MMTk workers are idle, but the workers are not idle because they are busy working on a GC. This commit essentially implements a trylock. It will optimistically lock but will release the lock if it detects that any other Ractors are waiting in rb_mmtk_block_for_gc. For example, the following script demonstrates the issue: puts "Hello #{Process.pid}" 100.times do |i| puts "i = #{i}" Ractor.new(i) do |j| puts "Ractor #{j} hello" 1000.times do |i| s = "#{j}-#{i}" end Ractor.receive puts "Ractor #{j} goodbye" end pid = fork { } puts "Child pid is #{pid}" _, status = Process.waitpid2 pid puts status.success? end puts "Goodbye" We can see the MMTk worker thread is waiting to start the GC: #4 0x00007ffff66538b1 in rb_mmtk_stop_the_world () at gc/mmtk/mmtk.c:101 #5 0x00007ffff6d04caf in mmtk_ruby::collection::{impl#0}::stop_all_mutators>> (_tls=..., mutator_visitor=...) at src/collection.rs:23 However, the mutator thread is stuck in mmtk_before_fork trying to stop that worker thread: #4 0x00007ffff6c0b621 in std::sys::thread::unix::Thread::join () at library/std/src/sys/thread/unix.rs:134 #5 0x00007ffff6658b6e in std::thread::JoinInner<()>::join<()> (self=...) #6 0x00007ffff6658d4c in std::thread::JoinHandle<()>::join<()> (self=...) #7 0x00007ffff665795e in mmtk_ruby::binding::RubyBinding::join_all_gc_threads (self=0x7ffff72462d0 ) at src/binding.rs:115 #8 0x00007ffff66561a8 in mmtk_ruby::api::mmtk_before_fork () at src/api.rs:309 #9 0x00007ffff66556ff in rb_gc_impl_before_fork (objspace_ptr=0x555555d17980) at gc/mmtk/mmtk.c:1054 #10 0x00005555556bbc3e in rb_gc_before_fork () at gc.c:5429 https://github.com/ruby/mmtk/commit/1a629504a7 --- gc/mmtk/mmtk.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index 428833488c73ed..e1678dcf6ab0b4 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -32,6 +32,7 @@ struct objspace { unsigned long live_ractor_cache_count; pthread_mutex_t mutex; + rb_atomic_t mutator_blocking_count; bool world_stopped; pthread_cond_t cond_world_stopped; pthread_cond_t cond_world_started; @@ -131,7 +132,9 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator) struct objspace *objspace = rb_gc_get_objspace(); size_t starting_gc_count = objspace->gc_count; + RUBY_ATOMIC_INC(objspace->mutator_blocking_count); int lock_lev = RB_GC_VM_LOCK(); + RUBY_ATOMIC_DEC(objspace->mutator_blocking_count); int err; if ((err = pthread_mutex_lock(&objspace->mutex)) != 0) { rb_bug("ERROR: cannot lock objspace->mutex: %s", strerror(err)); @@ -1049,9 +1052,26 @@ rb_gc_impl_before_fork(void *objspace_ptr) { struct objspace *objspace = objspace_ptr; + retry: objspace->fork_hook_vm_lock_lev = RB_GC_VM_LOCK(); rb_gc_vm_barrier(); + /* At this point, we know that all the Ractors are paused because of the + * rb_gc_vm_barrier above. Since rb_mmtk_block_for_gc is a barrier point, + * one or more Ractors could be paused there. However, mmtk_before_fork is + * not compatible with that because it assumes that the MMTk workers are idle, + * but the workers are not idle because they are busy working on a GC. + * + * This essentially implements a trylock. It will optimistically lock but will + * release the lock if it detects that any other Ractors are waiting in + * rb_mmtk_block_for_gc. + */ + rb_atomic_t mutator_blocking_count = RUBY_ATOMIC_LOAD(objspace->mutator_blocking_count); + if (mutator_blocking_count != 0) { + RB_GC_VM_UNLOCK(objspace->fork_hook_vm_lock_lev); + goto retry; + } + mmtk_before_fork(); } From 685903e56efd9e4db178d8209c4eb079127b625a Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 19 Nov 2025 11:00:40 +0900 Subject: [PATCH 12/16] [ruby/etc] Bump up the required ruby version to 2.7 https://github.com/ruby/etc/commit/d047bb6856 --- ext/etc/etc.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/etc/etc.gemspec b/ext/etc/etc.gemspec index 3facc7486669a9..0e9803dc624cb1 100644 --- a/ext/etc/etc.gemspec +++ b/ext/etc/etc.gemspec @@ -40,5 +40,5 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.extensions = %w{ext/etc/extconf.rb} - spec.required_ruby_version = ">= 2.6.0" + spec.required_ruby_version = ">= 2.7.0" end From a6cecda1dcf57d4db09c92706f69b018915f6530 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 19 Nov 2025 11:02:22 +0900 Subject: [PATCH 13/16] [ruby/etc] Win32: Drop support for older MSVC Ruby 2.7 supports MSVC 12.0/_MSC_VER 1800 or later. https://github.com/ruby/etc/commit/6f4404ec88 --- ext/etc/etc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ext/etc/etc.c b/ext/etc/etc.c index 66ef8fc9a4f3d0..8d50a96a621035 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -832,11 +832,7 @@ etc_uname(VALUE obj) rb_w32_conv_from_wchar(v.szCSDVersion, rb_utf8_encoding())); rb_hash_aset(result, SYMBOL_LIT("version"), version); -# if defined _MSC_VER && _MSC_VER < 1300 -# define GET_COMPUTER_NAME(ptr, plen) GetComputerNameW(ptr, plen) -# else # define GET_COMPUTER_NAME(ptr, plen) GetComputerNameExW(ComputerNameDnsFullyQualified, ptr, plen) -# endif GET_COMPUTER_NAME(NULL, &len); buf = ALLOCV_N(WCHAR, vbuf, len); if (GET_COMPUTER_NAME(buf, &len)) { From 3ee08c8df8581ca5b1a95dae0f5825abf54700f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Nov 2025 02:08:11 +0000 Subject: [PATCH 14/16] Bump actions/checkout in /.github/actions/setup/directories Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/08c6903cd8c0fde910a37f88322edcfb5dd907a8...93cb6efe18208431cddfb8368fd83d5badbf9bfd) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 5.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/actions/setup/directories/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml index c0fc75ad7d9b2f..f93733a919066c 100644 --- a/.github/actions/setup/directories/action.yml +++ b/.github/actions/setup/directories/action.yml @@ -88,7 +88,7 @@ runs: git config --global init.defaultBranch garbage - if: inputs.checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: path: ${{ inputs.srcdir }} fetch-depth: ${{ inputs.fetch-depth }} From 319001192d59bc57923ba3838eb83685cb3af014 Mon Sep 17 00:00:00 2001 From: Burdette Lamar Date: Tue, 18 Nov 2025 20:56:14 -0600 Subject: [PATCH 15/16] [DOC] Tweaks for String#dump and String#undump --- doc/string.rb | 3 +- doc/string/dump.rdoc | 137 ++++++++++++++++++++++++++++--------------- string.c | 12 +--- 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/doc/string.rb b/doc/string.rb index 4304b96aee7f9a..b37cb5d324ec95 100644 --- a/doc/string.rb +++ b/doc/string.rb @@ -322,8 +322,7 @@ # _Substitution_ # # - #dump: Returns a printable version of +self+, enclosed in double-quotes. -# - #undump: Returns a copy of +self+ with all \xNN notations replaced by \uNNNN notations -# and all escaped characters unescaped. +# - #undump: Inverse of #dump; returns a copy of +self+ with changes of the kinds made by #dump "undone." # - #sub: Returns a copy of +self+ with the first substring matching a given pattern # replaced with a given replacement string. # - #gsub: Returns a copy of +self+ with each substring that matches a given pattern diff --git a/doc/string/dump.rdoc b/doc/string/dump.rdoc index a5ab0bb42f2464..2ab9521540dcda 100644 --- a/doc/string/dump.rdoc +++ b/doc/string/dump.rdoc @@ -1,52 +1,97 @@ -Returns a printable version of +self+, enclosed in double-quotes: +For an ordinary string, this method, +String#dump+, +returns a printable ASCII-only version of +self+, enclosed in double-quotes. - 'hello'.dump # => "\"hello\"" +For a dumped string, method String#undump is the inverse of +String#dump+; +it returns a "restored" version of +self+, +where all the dumping changes have been undone. -Certain special characters are rendered with escapes: +In the simplest case, the dumped string contains the original string, +enclosed in double-quotes; +this example is done in +irb+ (interactive Ruby), which uses method `inspect` to render the results: - '"'.dump # => "\"\\\"\"" - '\\'.dump # => "\"\\\\\"" + s = 'hello' # => "hello" + s.dump # => "\"hello\"" + s.dump.undump # => "hello" -Non-printing characters are rendered with escapes: +Keep in mind that in the second line above: + +- The outer double-quotes are put on by +inspect+, + and _are_ _not_ part of the output of #dump. +- The inner double-quotes _are_ part of the output of +dump+, + and are escaped by +inspect+ because they are within the outer double-quotes. + +To avoid confusion, we'll use this helper method to omit the outer double-quotes: + + def dump(s) + print "String: ", s, "\n" + print "Dumped: ", s.dump, "\n" + print "Undumped: ", s.dump.undump, "\n" + end + +So that for string 'hello', we'll see: + + String: hello + Dumped: "hello" + Undumped: hello + +In a dump, certain special characters are escaped: + + String: " + Dumped: "\"" + Undumped: " + + String: \ + Dumped: "\\" + Undumped: \ + +In a dump, unprintable characters are replaced by printable ones; +the unprintable characters are the whitespace characters (other than space itself); +here we see the ordinals for those characers, together with explanatory text: + + h = { + 7 => 'Alert (BEL)', + 8 => 'Backspace (BS)', + 9 => 'Horizontal tab (HT)', + 10 => 'Linefeed (LF)', + 11 => 'Vertical tab (VT)', + 12 => 'Formfeed (FF)', + 13 => 'Carriage return (CR)' + } + +In this example, the dumped output is printed by method #inspect, +and so contains both outer double-quotes and escaped inner double-quotes: s = '' - s << 7 # Alarm (bell). - s << 8 # Back space. - s << 9 # Horizontal tab. - s << 10 # Line feed. - s << 11 # Vertical tab. - s << 12 # Form feed. - s << 13 # Carriage return. - s # => "\a\b\t\n\v\f\r" - s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\"" - -If +self+ is encoded in UTF-8 and contains Unicode characters, renders Unicode -characters in Unicode escape sequence: - - 'тест'.dump # => "\"\\u0442\\u0435\\u0441\\u0442\"" - 'こんにちは'.dump # => "\"\\u3053\\u3093\\u306B\\u3061\\u306F\"" - -If the encoding of +self+ is not ASCII-compatible (i.e., +self.encoding.ascii_compatible?+ -returns +false+), renders all ASCII-compatible bytes as ASCII characters and all -other bytes as hexadecimal. Appends .dup.force_encoding(\"encoding\"), where - is +self.encoding.name+: - - s = 'hello' - s.encoding # => # - s.dump # => "\"hello\"" - s.encode('utf-16').dump # => "\"\\xFE\\xFF\\x00h\\x00e\\x00l\\x00l\\x00o\".dup.force_encoding(\"UTF-16\")" - s.encode('utf-16le').dump # => "\"h\\x00e\\x00l\\x00l\\x00o\\x00\".dup.force_encoding(\"UTF-16LE\")" - - s = 'тест' - s.encoding # => # - s.dump # => "\"\\u0442\\u0435\\u0441\\u0442\"" - s.encode('utf-16').dump # => "\"\\xFE\\xFF\\x04B\\x045\\x04A\\x04B\".dup.force_encoding(\"UTF-16\")" - s.encode('utf-16le').dump # => "\"B\\x045\\x04A\\x04B\\x04\".dup.force_encoding(\"UTF-16LE\")" - - s = 'こんにちは' - s.encoding # => # - s.dump # => "\"\\u3053\\u3093\\u306B\\u3061\\u306F\"" - s.encode('utf-16').dump # => "\"\\xFE\\xFF0S0\\x930k0a0o\".dup.force_encoding(\"UTF-16\")" - s.encode('utf-16le').dump # => "\"S0\\x930k0a0o0\".dup.force_encoding(\"UTF-16LE\")" - -Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String]. + h.keys.each {|i| s << i } # => [7, 8, 9, 10, 11, 12, 13] + s # => "\a\b\t\n\v\f\r" + s.dump # => "\"\\a\\b\\t\\n\\v\\f\\r\"" + +If +self+ is encoded in UTF-8 and contains Unicode characters, +each Unicode character is dumped as a Unicode escape sequence: + + String: тест + Dumped: "\u0442\u0435\u0441\u0442" + Undumped: тест + + String: こんにちは + Dumped: "\u3053\u3093\u306B\u3061\u306F" + Undumped: こんにちは + +If the encoding of +self+ is not ASCII-compatible +(i.e., if self.encoding.ascii_compatible? returns +false+), +each ASCII-compatible byte is dumped as an ASCII character, +and all other bytes are dumped as hexadecimal; +also appends .dup.force_encoding(\"encoding\"), +where is self.encoding.name: + + String: hello + Dumped: "\xFE\xFF\x00h\x00e\x00l\x00l\x00o".dup.force_encoding("UTF-16") + Undumped: hello + + String: тест + Dumped: "\xFE\xFF\x04B\x045\x04A\x04B".dup.force_encoding("UTF-16") + Undumped: тест + + String: こんにちは + Dumped: "\xFE\xFF0S0\x930k0a0o".dup.force_encoding("UTF-16") + Undumped: こんにちは diff --git a/string.c b/string.c index 827555d9e0faab..f371e185d618b0 100644 --- a/string.c +++ b/string.c @@ -7628,17 +7628,11 @@ static VALUE rb_str_is_ascii_only_p(VALUE str); /* * call-seq: - * undump -> string + * undump -> new_string * - * Returns an unescaped version of +self+: - * - * s_orig = "\f\x00\xff\\\"" # => "\f\u0000\xFF\\\"" - * s_dumped = s_orig.dump # => "\"\\f\\x00\\xFF\\\\\\\"\"" - * s_undumped = s_dumped.undump # => "\f\u0000\xFF\\\"" - * s_undumped == s_orig # => true - * - * Related: String#dump (inverse of String#undump). + * Inverse of String#dump; returns a copy of +self+ with changes of the kinds made by String#dump "undone." * + * Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String]. */ static VALUE From 1443f89d6942e19516a0fb10d25876021202ec5e Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Sun, 16 Nov 2025 19:46:03 +0000 Subject: [PATCH 16/16] [DOC] Tweaks for String#unicode_normalize --- doc/string/unicode_normalize.rdoc | 28 ++++++++++++++++++++++++++++ string.c | 28 +--------------------------- 2 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 doc/string/unicode_normalize.rdoc diff --git a/doc/string/unicode_normalize.rdoc b/doc/string/unicode_normalize.rdoc new file mode 100644 index 00000000000000..5f733c0fb84f58 --- /dev/null +++ b/doc/string/unicode_normalize.rdoc @@ -0,0 +1,28 @@ +Returns a copy of +self+ with +{Unicode normalization}[https://unicode.org/reports/tr15] applied. + +Argument +form+ must be one of the following symbols +(see {Unicode normalization forms}[https://unicode.org/reports/tr15/#Norm_Forms]): + +- +:nfc+: Canonical decomposition, followed by canonical composition. +- +:nfd+: Canonical decomposition. +- +:nfkc+: Compatibility decomposition, followed by canonical composition. +- +:nfkd+: Compatibility decomposition. + +The encoding of +self+ must be one of: + +- Encoding::UTF_8. +- Encoding::UTF_16BE. +- Encoding::UTF_16LE. +- Encoding::UTF_32BE. +- Encoding::UTF_32LE. +- Encoding::GB18030. +- Encoding::UCS_2BE. +- Encoding::UCS_4BE. + +Examples: + + "a\u0300".unicode_normalize # => "à" # Lowercase 'a' with grave accens. + "a\u0300".unicode_normalize(:nfd) # => "à" # Same. + +Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String]. diff --git a/string.c b/string.c index f371e185d618b0..d78d7320be2b2b 100644 --- a/string.c +++ b/string.c @@ -11926,34 +11926,8 @@ unicode_normalize_common(int argc, VALUE *argv, VALUE str, ID id) * call-seq: * unicode_normalize(form = :nfc) -> string * - * Returns a copy of +self+ with - * {Unicode normalization}[https://unicode.org/reports/tr15] applied. + * :include: doc/string/unicode_normalize.rdoc * - * Argument +form+ must be one of the following symbols - * (see {Unicode normalization forms}[https://unicode.org/reports/tr15/#Norm_Forms]): - * - * - +:nfc+: Canonical decomposition, followed by canonical composition. - * - +:nfd+: Canonical decomposition. - * - +:nfkc+: Compatibility decomposition, followed by canonical composition. - * - +:nfkd+: Compatibility decomposition. - * - * The encoding of +self+ must be one of: - * - * - Encoding::UTF_8 - * - Encoding::UTF_16BE - * - Encoding::UTF_16LE - * - Encoding::UTF_32BE - * - Encoding::UTF_32LE - * - Encoding::GB18030 - * - Encoding::UCS_2BE - * - Encoding::UCS_4BE - * - * Examples: - * - * "a\u0300".unicode_normalize # => "a" - * "\u00E0".unicode_normalize(:nfd) # => "a " - * - * Related: String#unicode_normalize!, String#unicode_normalized?. */ static VALUE rb_str_unicode_normalize(int argc, VALUE *argv, VALUE str)