Ruby: eval_error.c Source File

Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)

eval_error.c
1/* -*-c-*- */
2/*
3 * included by eval.c
4 */
5
6#define write_warn(str, x) \
7 (NIL_P(str) ? warn_print(x) : (void)rb_str_cat_cstr(str, x))
8#define write_warn2(str, x, l) \
9 (NIL_P(str) ? warn_print2(x, l) : (void)rb_str_cat(str, x, l))
10#ifdef HAVE_BUILTIN___BUILTIN_CONSTANT_P
11#define warn_print(x) RB_GNUC_EXTENSION_BLOCK( \
12 (__builtin_constant_p(x)) ? \
13 rb_write_error2((x), (long)strlen(x)) : \
14 rb_write_error(x) \
15)
16#else
17#define warn_print(x) rb_write_error(x)
18#endif
19
20#define warn_print2(x,l) rb_write_error2((x),(l))
21
22#define write_warn_str(str,x) NIL_P(str) ? rb_write_error_str(x) : (void)rb_str_concat((str), (x))
23#define warn_print_str(x) rb_write_error_str(x)
24
25static VALUE error_pos_str(void);
26
27static void
28error_pos(const VALUE str)
29{
30 VALUE pos = error_pos_str();
31 if (!NIL_P(pos)) {
32 write_warn_str(str, pos);
33 }
34}
35
36static VALUE
37error_pos_str(void)
38{
39 int sourceline;
40 VALUE sourcefile = rb_source_location(&sourceline);
41
42 if (!NIL_P(sourcefile)) {
43 ID caller_name;
44 if (sourceline == 0) {
45 return rb_sprintf("%"PRIsVALUE": ", sourcefile);
46 }
47 else if ((caller_name = rb_frame_callee()) != 0) {
48 return rb_sprintf("%"PRIsVALUE":%d:in `%"PRIsVALUE"': ",
49 sourcefile, sourceline,
50 rb_id2str(caller_name));
51 }
52 else {
53 return rb_sprintf("%"PRIsVALUE":%d: ", sourcefile, sourceline);
54 }
55 }
56 return Qnil;
57}
58
59static void
60set_backtrace(VALUE info, VALUE bt)
61{
62 ID set_backtrace = rb_intern("set_backtrace");
63
64 if (rb_backtrace_p(bt)) {
65 if (rb_method_basic_definition_p(CLASS_OF(info), set_backtrace)) {
66 rb_exc_set_backtrace(info, bt);
67 return;
68 }
69 else {
70 bt = rb_backtrace_to_str_ary(bt);
71 }
72 }
73 rb_check_funcall(info, set_backtrace, 1, &bt);
74}
75
76#define CSI_BEGIN "\033["
77#define CSI_SGR "m"
78
79static const char underline[] = CSI_BEGIN"1;4"CSI_SGR;
80static const char bold[] = CSI_BEGIN"1"CSI_SGR;
81static const char reset[] = CSI_BEGIN""CSI_SGR;
82
83static void
84print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VALUE str, int highlight)
85{
86 long elen = 0;
87 VALUE mesg;
88
89 if (NIL_P(errat) || RARRAY_LEN(errat) == 0 ||
90 NIL_P(mesg = RARRAY_AREF(errat, 0))) {
91 error_pos(str);
92 }
93 else {
94 write_warn_str(str, mesg);
95 write_warn(str, ": ");
96 }
97
98 if (!NIL_P(emesg)) {
99 elen = RSTRING_LEN(emesg);
100 }
101
102 if (eclass == rb_eRuntimeError && elen == 0) {
103 if (highlight) write_warn(str, underline);
104 write_warn(str, "unhandled exception");
105 if (highlight) write_warn(str, reset);
106 write_warn2(str, "\n", 1);
107 }
108 else {
109 VALUE epath;
110
111 epath = rb_class_name(eclass);
112 if (elen == 0) {
113 if (highlight) write_warn(str, underline);
114 write_warn_str(str, epath);
115 if (highlight) write_warn(str, reset);
116 write_warn(str, "\n");
117 }
118 else {
119 write_warn_str(str, emesg);
120 write_warn(str, "\n");
121 }
122 }
123}
124
125 VALUE
126rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight)
127{
128 const char *einfo = "";
129 long elen = 0;
130
131 VALUE str = rb_str_new2("");
132
133 if (!NIL_P(emesg)) {
134 einfo = RSTRING_PTR(emesg);
135 elen = RSTRING_LEN(emesg);
136 }
137 if (eclass == rb_eRuntimeError && elen == 0) {
138 if (highlight) write_warn(str, underline);
139 write_warn(str, "unhandled exception");
140 if (highlight) write_warn(str, reset);
141 }
142 else {
143 VALUE epath;
144
145 epath = rb_class_name(eclass);
146 if (elen == 0) {
147 if (highlight) write_warn(str, underline);
148 write_warn_str(str, epath);
149 if (highlight) write_warn(str, reset);
150 }
151 else {
152 /* emesg is a String instance */
153 const char *tail = 0;
154
155 if (highlight) write_warn(str, bold);
156 if (RSTRING_PTR(epath)[0] == '#')
157 epath = 0;
158 if ((tail = memchr(einfo, '\n', elen)) != 0) {
159 write_warn2(str, einfo, tail - einfo);
160 tail++; /* skip newline */
161 }
162 else {
163 write_warn_str(str, emesg);
164 }
165 if (epath) {
166 write_warn(str, " (");
167 if (highlight) write_warn(str, underline);
168 write_warn_str(str, epath);
169 if (highlight) {
170 write_warn(str, reset);
171 write_warn(str, bold);
172 }
173 write_warn2(str, ")", 1);
174 if (highlight) write_warn(str, reset);
175 }
176 if (tail && einfo+elen > tail) {
177 if (!highlight) {
178 write_warn2(str, "\n", 1);
179 write_warn2(str, tail, einfo+elen-tail);
180 }
181 else {
182 elen -= tail - einfo;
183 einfo = tail;
184 write_warn2(str, "\n", 1);
185 while (elen > 0) {
186 tail = memchr(einfo, '\n', elen);
187 if (!tail || tail > einfo) {
188 write_warn(str, bold);
189 write_warn2(str, einfo, tail ? tail-einfo : elen);
190 write_warn(str, reset);
191 if (!tail) {
192 break;
193 }
194 }
195 elen -= tail - einfo;
196 einfo = tail;
197 do ++tail; while (tail < einfo+elen && *tail == '\n');
198 write_warn2(str, einfo, tail-einfo);
199 elen -= tail - einfo;
200 einfo = tail;
201 }
202 }
203 }
204 }
205 }
206
207 return str;
208}
209
210static void
211print_backtrace(const VALUE eclass, const VALUE errat, const VALUE str, int reverse, long backtrace_limit)
212{
213 if (!NIL_P(errat)) {
214 long i;
215 long len = RARRAY_LEN(errat);
216 const int threshold = 1000000000;
217 int width = (len <= 1) ? INT_MIN : ((int)log10((double)(len > threshold ?
218 ((len - 1) / threshold) :
219 len - 1)) +
220 (len < threshold ? 0 : 9) + 1);
221
222 long skip_start = -1, skip_len = 0;
223
224 // skip for stackoverflow
225 if (eclass == rb_eSysStackError) {
226 long trace_head = 9;
227 long trace_tail = 4;
228 long trace_max = trace_head + trace_tail + 5;
229 if (len > trace_max) {
230 skip_start = trace_head;
231 skip_len = len - trace_max + 5;
232 }
233 }
234
235 // skip for explicit limit
236 if (backtrace_limit >= 0 && len > backtrace_limit + 2) {
237 skip_start = backtrace_limit + 1;
238 skip_len = len - skip_start;
239 }
240
241 for (i = 1; i < len; i++) {
242 if (i == skip_start) {
243 write_warn_str(str, rb_sprintf("\t ... %ld levels...\n", skip_len));
244 i += skip_len;
245 if (i >= len) break;
246 }
247 VALUE line = RARRAY_AREF(errat, reverse ? len - i : i);
248 if (RB_TYPE_P(line, T_STRING)) {
249 VALUE bt = rb_str_new_cstr("\t");
250 if (reverse) rb_str_catf(bt, "%*ld: ", width, len - i);
251 write_warn_str(str, rb_str_catf(bt, "from %"PRIsVALUE"\n", line));
252 }
253 }
254 }
255}
256
257 VALUE rb_get_detailed_message(VALUE exc, VALUE opt);
258
259static int
260shown_cause_p(VALUE cause, VALUE *shown_causes)
261{
262 VALUE shown = *shown_causes;
263 if (!shown) {
264 *shown_causes = shown = rb_obj_hide(rb_ident_hash_new());
265 }
266 if (rb_hash_has_key(shown, cause)) return TRUE;
267 rb_hash_aset(shown, cause, Qtrue);
268 return FALSE;
269}
270
271static void
272show_cause(VALUE errinfo, VALUE str, VALUE opt, VALUE highlight, VALUE reverse, long backtrace_limit, VALUE *shown_causes)
273{
274 VALUE cause = rb_attr_get(errinfo, id_cause);
275 if (!NIL_P(cause) && rb_obj_is_kind_of(cause, rb_eException) &&
276 !shown_cause_p(cause, shown_causes)) {
277 volatile VALUE eclass = CLASS_OF(cause);
278 VALUE errat = rb_get_backtrace(cause);
279 VALUE emesg = rb_get_detailed_message(cause, opt);
280 if (reverse) {
281 show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes);
282 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
283 print_errinfo(eclass, errat, emesg, str, RTEST(highlight));
284 }
285 else {
286 print_errinfo(eclass, errat, emesg, str, RTEST(highlight));
287 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
288 show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes);
289 }
290 }
291}
292
293void
294rb_exc_check_circular_cause(VALUE exc)
295{
296 VALUE cause = exc, shown_causes = 0;
297 do {
298 if (shown_cause_p(cause, &shown_causes)) {
299 rb_raise(rb_eArgError, "circular causes");
300 }
301 } while (!NIL_P(cause = rb_attr_get(cause, id_cause)));
302}
303
304void
305rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE opt, VALUE highlight, VALUE reverse)
306{
307 volatile VALUE eclass;
308 VALUE shown_causes = 0;
309 long backtrace_limit = rb_backtrace_length_limit;
310
311 if (NIL_P(errinfo))
312 return;
313
314 if (UNDEF_P(errat)) {
315 errat = Qnil;
316 }
317 eclass = CLASS_OF(errinfo);
318 if (reverse) {
319 static const char traceback[] = "Traceback "
320 "(most recent call last):\n";
321 const int bold_part = rb_strlen_lit("Traceback");
322 char buff[sizeof(traceback)+sizeof(bold)+sizeof(reset)-2], *p = buff;
323 const char *msg = traceback;
324 long len = sizeof(traceback) - 1;
325 if (RTEST(highlight)) {
326#define APPEND(s, l) (memcpy(p, s, l), p += (l))
327 APPEND(bold, sizeof(bold)-1);
328 APPEND(traceback, bold_part);
329 APPEND(reset, sizeof(reset)-1);
330 APPEND(traceback + bold_part, sizeof(traceback)-bold_part-1);
331#undef APPEND
332 len = p - (msg = buff);
333 }
334 write_warn2(str, msg, len);
335 show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes);
336 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
337 print_errinfo(eclass, errat, emesg, str, RTEST(highlight));
338 }
339 else {
340 print_errinfo(eclass, errat, emesg, str, RTEST(highlight));
341 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
342 show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes);
343 }
344}
345
346static void
347rb_ec_error_print_detailed(rb_execution_context_t *const ec, const VALUE errinfo, const VALUE str, VALUE emesg0)
348{
349 volatile uint8_t raised_flag = ec->raised_flag;
350 volatile VALUE errat = Qundef;
351 volatile bool written = false;
352 volatile VALUE emesg = emesg0;
353
354 VALUE opt = rb_hash_new();
355 VALUE highlight = rb_stderr_tty_p() ? Qtrue : Qfalse;
356 rb_hash_aset(opt, ID2SYM(rb_intern_const("highlight")), highlight);
357
358 if (NIL_P(errinfo))
359 return;
360 rb_ec_raised_clear(ec);
361
362 EC_PUSH_TAG(ec);
363 if (EC_EXEC_TAG() == TAG_NONE) {
364 errat = rb_get_backtrace(errinfo);
365 }
366 if (UNDEF_P(emesg)) {
367 emesg = Qnil;
368 emesg = rb_get_detailed_message(errinfo, opt);
369 }
370
371 if (!written) {
372 written = true;
373 rb_error_write(errinfo, emesg, errat, str, opt, highlight, Qfalse);
374 }
375
376 EC_POP_TAG();
377 ec->errinfo = errinfo;
378 rb_ec_raised_set(ec, raised_flag);
379}
380
381void
382rb_ec_error_print(rb_execution_context_t *volatile ec, volatile VALUE errinfo)
383{
384 rb_ec_error_print_detailed(ec, errinfo, Qnil, Qundef);
385}
386
387#define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method `%1$s' for "k" `%2$s'")
388#define undef_mesg(v) ( \
389 is_mod ? \
390 undef_mesg_for(v, "module") : \
391 undef_mesg_for(v, "class"))
392
393void
394rb_print_undef(VALUE klass, ID id, rb_method_visibility_t visi)
395{
396 const int is_mod = RB_TYPE_P(klass, T_MODULE);
397 VALUE mesg;
398 switch (visi & METHOD_VISI_MASK) {
399 case METHOD_VISI_UNDEF:
400 case METHOD_VISI_PUBLIC: mesg = undef_mesg(""); break;
401 case METHOD_VISI_PRIVATE: mesg = undef_mesg(" private"); break;
402 case METHOD_VISI_PROTECTED: mesg = undef_mesg(" protected"); break;
403 default: UNREACHABLE;
404 }
405 rb_name_err_raise_str(mesg, klass, ID2SYM(id));
406}
407
408void
409rb_print_undef_str(VALUE klass, VALUE name)
410{
411 const int is_mod = RB_TYPE_P(klass, T_MODULE);
412 rb_name_err_raise_str(undef_mesg(""), klass, name);
413}
414
415#define inaccessible_mesg_for(v, k) rb_fstring_lit("method `%1$s' for "k" `%2$s' is "v)
416#define inaccessible_mesg(v) ( \
417 is_mod ? \
418 inaccessible_mesg_for(v, "module") : \
419 inaccessible_mesg_for(v, "class"))
420
421void
422rb_print_inaccessible(VALUE klass, ID id, rb_method_visibility_t visi)
423{
424 const int is_mod = RB_TYPE_P(klass, T_MODULE);
425 VALUE mesg;
426 switch (visi & METHOD_VISI_MASK) {
427 case METHOD_VISI_UNDEF:
428 case METHOD_VISI_PUBLIC: mesg = inaccessible_mesg(""); break;
429 case METHOD_VISI_PRIVATE: mesg = inaccessible_mesg("private"); break;
430 case METHOD_VISI_PROTECTED: mesg = inaccessible_mesg("protected"); break;
431 default: UNREACHABLE;
432 }
433 rb_name_err_raise_str(mesg, klass, ID2SYM(id));
434}
435
436static int
437sysexit_status(VALUE err)
438{
439 VALUE st = rb_ivar_get(err, id_status);
440 return NUM2INT(st);
441}
442
443enum {
444 EXITING_WITH_MESSAGE = 1,
445 EXITING_WITH_STATUS = 2,
446 EXITING_WITH_SIGNAL = 4
447};
448static int
449exiting_split(VALUE errinfo, volatile int *exitcode, volatile int *sigstatus)
450{
451 int ex = EXIT_SUCCESS;
452 VALUE signo;
453 int sig = 0;
454 int result = 0;
455
456 if (NIL_P(errinfo)) return 0;
457
458 if (THROW_DATA_P(errinfo)) {
459 int throw_state = ((const struct vm_throw_data *)errinfo)->throw_state;
460 ex = throw_state & VM_THROW_STATE_MASK;
461 result |= EXITING_WITH_STATUS;
462 }
463 else if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
464 ex = sysexit_status(errinfo);
465 result |= EXITING_WITH_STATUS;
466 }
467 else if (rb_obj_is_kind_of(errinfo, rb_eSignal)) {
468 signo = rb_ivar_get(errinfo, id_signo);
469 sig = FIX2INT(signo);
470 result |= EXITING_WITH_SIGNAL;
471 /* no message when exiting by signal */
472 if (signo == INT2FIX(SIGSEGV) || !rb_obj_is_instance_of(errinfo, rb_eSignal))
473 /* except for SEGV and subclasses */
474 result |= EXITING_WITH_MESSAGE;
475 }
476 else if (rb_obj_is_kind_of(errinfo, rb_eSystemCallError) &&
477 FIXNUM_P(signo = rb_attr_get(errinfo, id_signo))) {
478 sig = FIX2INT(signo);
479 result |= EXITING_WITH_SIGNAL;
480 /* no message when exiting by error to be mapped to signal */
481 }
482 else {
483 ex = EXIT_FAILURE;
484 result |= EXITING_WITH_STATUS | EXITING_WITH_MESSAGE;
485 }
486
487 if (exitcode && (result & EXITING_WITH_STATUS))
488 *exitcode = ex;
489 if (sigstatus && (result & EXITING_WITH_SIGNAL))
490 *sigstatus = sig;
491
492 return result;
493}
494
495#define unknown_longjmp_status(status) \
496 rb_bug("Unknown longjmp status %d", status)
497
498static int
499error_handle(rb_execution_context_t *ec, VALUE errinfo, enum ruby_tag_type ex)
500{
501 int status = EXIT_FAILURE;
502
503 if (rb_ec_set_raised(ec))
504 return EXIT_FAILURE;
505 switch (ex & TAG_MASK) {
506 case 0:
507 status = EXIT_SUCCESS;
508 break;
509
510 case TAG_RETURN:
511 error_pos(Qnil);
512 warn_print("unexpected return\n");
513 break;
514 case TAG_NEXT:
515 error_pos(Qnil);
516 warn_print("unexpected next\n");
517 break;
518 case TAG_BREAK:
519 error_pos(Qnil);
520 warn_print("unexpected break\n");
521 break;
522 case TAG_REDO:
523 error_pos(Qnil);
524 warn_print("unexpected redo\n");
525 break;
526 case TAG_RETRY:
527 error_pos(Qnil);
528 warn_print("retry outside of rescue clause\n");
529 break;
530 case TAG_THROW:
531 /* TODO: fix me */
532 error_pos(Qnil);
533 warn_print("unexpected throw\n");
534 break;
535 case TAG_RAISE:
536 if (!(exiting_split(errinfo, &status, NULL) & EXITING_WITH_MESSAGE)) {
537 break;
538 }
539 /* fallthrough */
540 case TAG_FATAL:
541 rb_ec_error_print(ec, errinfo);
542 break;
543 default:
544 unknown_longjmp_status(ex);
545 break;
546 }
547 rb_ec_reset_raised(ec);
548 return status;
549}
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
ID2SYM
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
CLASS_OF
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
FIX2INT
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
T_MODULE
#define T_MODULE
Old name of RUBY_T_MODULE.
Definition value_type.h:70
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
NUM2INT
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
FIXNUM_P
#define FIXNUM_P
Old name of RB_FIXNUM_P.
Definition special_consts.h:53
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3150
rb_eSystemExit
VALUE rb_eSystemExit
SystemExit exception.
Definition error.c:1084
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
rb_eArgError
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
rb_eException
VALUE rb_eException
Mother of all exceptions.
Definition error.c:1083
rb_eSysStackError
VALUE rb_eSysStackError
SystemStackError exception.
Definition eval.c:50
rb_eSystemCallError
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1111
rb_eSignal
VALUE rb_eSignal
SignalException exception.
Definition error.c:1086
rb_obj_hide
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:84
rb_obj_is_instance_of
VALUE rb_obj_is_instance_of(VALUE obj, VALUE klass)
Queries if the given object is a direct instance of the given class.
Definition object.c:732
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:788
rb_strlen_lit
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1692
rb_str_new_cstr
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
rb_attr_get
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
Definition variable.c:1226
rb_ivar_get
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1218
rb_class_name
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:310
rb_check_funcall
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:664
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
rb_intern
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition symbol.c:796
rb_sprintf
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
rb_str_catf
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:583
RSTRING_LEN
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
RSTRING_PTR
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
rb_execution_context_struct
Definition vm_core.h:899
vm_throw_data
THROW_DATA.
Definition imemo.h:62
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
RB_TYPE_P
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375