From: kamil-gwozdz via ruby-core Date: 2023-06-23T10:36:06+00:00 Subject: [ruby-core:114014] [Ruby master Feature#19057] Hide implementation of `rb_io_t`. Issue #19057 has been updated by kamil-gwozdz (Kamil Gw����d��). byroot (Jean Boussier) wrote in #note-17: > @ioquatix I'm not sure which change exactly is the cause, but it appears that the recent `rb_io_t` changes broke `raindrops` I've noticed the same thing while trying to install `kgio` with the latest ruby HEAD. {{collapse ``` make DESTDIR\= sitearchdir\=./.gem.20230623-102030-g2vcyh sitelibdir\=./.gem.20230623-102030-g2vcyh compiling accept.c In file included from accept.c:7: my_fileno.h:9:7: warning: "HAVE_RB_IO_T" is not defined, evaluates to 0 [-Wundef] 9 | #if ! HAVE_RB_IO_T | ^~~~~~~~~~~~ my_fileno.h:16:8: warning: "HAVE_RB_IO_T" is not defined, evaluates to 0 [-Wundef] 16 | # if !HAVE_RB_IO_T || (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8) | ^~~~~~~~~~~~ my_fileno.h: In function ���my_fileno���: my_fileno.h:10:19: error: unknown type name ���OpenFile���; did you mean ���GetOpenFile���? 10 | # define rb_io_t OpenFile | ^~~~~~~~ my_fileno.h:25:2: note: in expansion of macro ���rb_io_t��� 25 | rb_io_t *fptr; | ^~~~~~~ In file included from kgio.h:6, from accept.c:4: /workspaces/project/vendor/ruby/30c1fc4087744da4dcc1138e23cf43118e10f5af/include/ruby-3.3.0+0/ruby/io.h:395:55: warning: assignment to ���int *��� from incompatible pointer type ���struct rb_io *��� [-Wincompatible-pointer-types] 395 | #define RB_IO_POINTER(obj,fp) rb_io_check_closed((fp) = RFILE(rb_io_taint_check(obj))->fptr) | ^ /workspaces/project/vendor/ruby/30c1fc4087744da4dcc1138e23cf43118e10f5af/include/ruby-3.3.0+0/ruby/io.h:401:21: note: in expansion of macro ���RB_IO_POINTER��� 401 | #define GetOpenFile RB_IO_POINTER | ^~~~~~~~~~~~~ my_fileno.h:30:2: note: in expansion of macro ���GetOpenFile��� 30 | GetOpenFile(io, fptr); | ^~~~~~~~~~~ /workspaces/project/vendor/ruby/30c1fc4087744da4dcc1138e23cf43118e10f5af/include/ruby-3.3.0+0/ruby/io.h:395:55: warning: passing argument 1 of ���rb_io_check_closed��� from incompatible pointer type [-Wincompatible-pointer-types] 395 | #define RB_IO_POINTER(obj,fp) rb_io_check_closed((fp) = RFILE(rb_io_taint_check(obj))->fptr) | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | int * /workspaces/project/vendor/ruby/30c1fc4087744da4dcc1138e23cf43118e10f5af/include/ruby-3.3.0+0/ruby/io.h:401:21: note: in expansion of macro ���RB_IO_POINTER��� 401 | #define GetOpenFile RB_IO_POINTER | ^~~~~~~~~~~~~ my_fileno.h:30:2: note: in expansion of macro ���GetOpenFile��� 30 | GetOpenFile(io, fptr); | ^~~~~~~~~~~ /workspaces/project/vendor/ruby/30c1fc4087744da4dcc1138e23cf43118e10f5af/include/ruby-3.3.0+0/ruby/io.h:638:34: note: expected ���rb_io_t *��� {aka ���struct rb_io *���} but argument is of type ���int *��� 638 | void rb_io_check_closed(rb_io_t *fptr); | ~~~~~~~~~^~~~ In file included from accept.c:7: my_fileno.h:17:41: error: request for member ���f��� in something not a structure or union 17 | # define FPTR_TO_FD(fptr) fileno(fptr->f) | ^~ my_fileno.h:31:7: note: in expansion of macro ���FPTR_TO_FD��� 31 | fd = FPTR_TO_FD(fptr); | ^~~~~~~~~~ accept.c: 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:248: accept.o] Error 1 make failed, exit code 2 ``` }} ---------------------------------------- Feature #19057: Hide implementation of `rb_io_t`. https://bugs.ruby-lang.org/issues/19057#change-103675 * Author: ioquatix (Samuel Williams) * Status: Assigned * Priority: Normal * Assignee: ioquatix (Samuel Williams) ---------------------------------------- In order to make improvements to the IO implementation like , we need to add new fields to `struct rb_io_t`. By the way, ending types in `_t` is not recommended by POSIX, so I'm also trying to rename the internal implementation to drop `_t` where possible during this conversion. Anyway, we should try to hide the implementation of `struct rb_io`. Ideally, we don't expose any of it, but the problem is backwards compatibility. So, in order to remain backwards compatibility, we should expose some fields of `struct rb_io`, the most commonly used one is `fd` and `mode`, but several others are commonly used. There are many fields which should not be exposed because they are implementation details. ## Current proposal The current proposed change creates two structs: ```c // include/ruby/io.h #ifndef RB_IO_T struct rb_io { int fd; // ... public fields ... }; #else struct rb_io; #endif // internal/io.h #define RB_IO_T struct rb_io { int fd; // ... public fields ... // ... private fields ... }; ``` However, we are not 100% confident this is safe according to the C specification. My experience is not sufficiently wide to say this is safe in practice, but it does look okay to both myself, and @Eregon + @tenderlovemaking have both given some kind of approval. That being said, maybe it's not safe. There are two alternatives: ## Hide all details We can make public `struct rb_io` completely invisible. ```c // include/ruby/io.h #define RB_IO_HIDDEN struct rb_io; int rb_ioptr_descriptor(struct rb_io *ioptr); // accessor for previously visible state. // internal/io.h struct rb_io { // ... all fields ... }; ``` This would only be forwards compatible, and code would need to feature detect like this: ```c #ifdef RB_IO_HIDDEN #define RB_IOPTR_DESCRIPTOR rb_ioptr_descriptor #else #define RB_IOPTR_DESCRIPTOR(ioptr) rb_ioptr_descriptor(ioptr) #endif ``` ## Nested public interface Alternatively, we can nest the public fields into the private struct: ```c // include/ruby/io.h struct rb_io_public { int fd; // ... public fields ... }; // internal/io.h #define RB_IO_T struct rb_io { struct rb_io_public public; // ... private fields ... }; ``` ## Considerations I personally think the "Hide all details" implementation is the best, but it's also the lest compatible. This is also what we are ultimately aiming for, whether we decide to take an intermediate "compatibility step" is up to us. I think "Nested public interface" is messy and introduces more complexity, but it might be slightly better defined than the "Current proposal" which might create undefined behaviour. That being said, all the tests are passing. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/