Bug #21293
openC23/GCC 15 build breakage with rb_define_method() and friends
Description
GCC 15 defaults to -std=gnu23
, which breaks rb_define_method() in some corner cases:
diff --git a/object.c b/object.c
index 5a379e9..958f421 100644
--- a/object.c
+++ b/object.c
@@ -4613,7 +4613,8 @@ InitVM_Object(void)
rb_cFalseClass = rb_define_class("FalseClass", rb_cObject);
rb_cFalseClass_to_s = rb_fstring_enc_lit("false", rb_usascii_encoding());
rb_vm_register_global_object(rb_cFalseClass_to_s);
- rb_define_method(rb_cFalseClass, "to_s", rb_false_to_s, 0);
+ int zero = 0;
+ rb_define_method(rb_cFalseClass, "to_s", rb_false_to_s, zero);
rb_define_alias(rb_cFalseClass, "inspect", "to_s");
rb_define_method(rb_cFalseClass, "&", false_and, 1);
rb_define_method(rb_cFalseClass, "|", false_or, 1);
Applying the above is fine prior to C23, but on GCC 15 it triggers a build error:
compiling object.c
In file included from ./include/ruby/ruby.h:27,
from constant.h:13,
from object.c:22:
object.c: In function 'InitVM_Object':
./include/ruby/internal/anyargs.h:288:135: error: passing argument 3 of 'rb_define_method_m3' from incompatible pointer type [-Wincompatible-pointer-types]
288 | #define rb_define_method(klass, mid, func, arity) RBIMPL_ANYARGS_DISPATCH_rb_define_method((arity), (func))((klass), (mid), (func), (arity))
| ^~~~~~
| |
| VALUE (*)(VALUE) {aka long unsigned int (*)(long unsigned int)}
object.c:4617:5: note: in expansion of macro 'rb_define_method'
4617 | rb_define_method(rb_cFalseClass, "to_s", rb_false_to_s, kek);
| ^~~~~~~~~~~~~~~~
./include/ruby/internal/anyargs.h:277:21: note: expected 'VALUE (*)(void)' {aka 'long unsigned int (*)(void)'} but argument is of type 'VALUE (*)(VALUE)' {aka 'long unsigned int (*)(long unsigned int)'}
277 | RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *)
| ^~~~~~~~~~~~~~~~
./include/ruby/internal/anyargs.h:252:41: note: in definition of macro 'RBIMPL_ANYARGS_DECL'
252 | RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m3(__VA_ARGS__, VALUE(*)(ANYARGS), int); \
| ^~~
object.c:1605:1: note: 'rb_false_to_s' declared here
1605 | rb_false_to_s(VALUE obj)
| ^~~~~~~~~~~~~
At top level:
cc1: note: unrecognized command-line option '-Wno-self-assign' may have been intended to silence earlier diagnostics
cc1: note: unrecognized command-line option '-Wno-parentheses-equality' may have been intended to silence earlier diagnostics
cc1: note: unrecognized command-line option '-Wno-constant-logical-operand' may have been intended to silence earlier diagnostics
make: *** [Makefile:464: object.o] Error 1
This also happens for C method that takes a large number of arguments.
This is because in C23 void foo();
no longers means "foo takes an unspecified number of arguments", and there is no way to implement a working ANYARGS
AFAIK.
Not something people would run into in practice, I hope.
(related: #21286 but this one is not Windows specific)
Updated by alanwu (Alan Wu) 7 days ago
- Related to Bug #21286: Windows - MSYS2 just updated to GCC 15.1.0, builds failing added
Updated by shyouhei (Shyouhei Urabe) 5 days ago
Yes... This is a macro expansion glitch.
Basically if zero
was an integer constant expression (which it isn't, by the way, in your diff), __buiitin_constant_p
in this line would be true, and rb_define_method
macro would be expanded as expected. This normally works because a C function tends to have compile-time fixed arity. People do not need to pass dynamic value here. But if they do... It breaks, like you reported.
rb_define_method
is a rusty API. Its design dates back to when matz still used K&R C. C evolved since then. We have coped with the language updates but are having hard times recently. Maybe either we want a "modern" C API, or we want to stop following the C standard (which many projects do anyway).