summaryrefslogtreecommitdiff
path: root/include/ruby/internal/intern/error.h
blob: 11e147a12103fbfe6e43c38f64a771ce7d4e6933 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#ifndef RBIMPL_INTERN_ERROR_H                        /*-*-C++-*-vi:se ft=cpp:*/
#define RBIMPL_INTERN_ERROR_H
/**
 * @file
 * @author     Ruby developers <ruby-core@ruby-lang.org>
 * @copyright  This  file  is   a  part  of  the   programming  language  Ruby.
 *             Permission  is hereby  granted,  to  either redistribute  and/or
 *             modify this file, provided that  the conditions mentioned in the
 *             file COPYING are met.  Consult the file for details.
 * @warning    Symbols   prefixed  with   either  `RBIMPL`   or  `rbimpl`   are
 *             implementation details.   Don't take  them as canon.  They could
 *             rapidly appear then vanish.  The name (path) of this header file
 *             is also an  implementation detail.  Do not expect  it to persist
 *             at the place it is now.  Developers are free to move it anywhere
 *             anytime at will.
 * @note       To  ruby-core:  remember  that   this  header  can  be  possibly
 *             recursively included  from extension  libraries written  in C++.
 *             Do not  expect for  instance `__VA_ARGS__` is  always available.
 *             We assume C99  for ruby itself but we don't  assume languages of
 *             extension libraries.  They could be written in C++98.
 * @brief      Public APIs related to ::rb_eException.
 */
#include "ruby/internal/attr/format.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
#include "ruby/internal/fl_type.h"
#include "ruby/backward/2/assume.h"

/**
 * This macro is used in conjunction  with rb_check_arity().  If you pass it to
 * the function's last  (max) argument, that means the function  does not check
 * upper limit.
 */
#define UNLIMITED_ARGUMENTS     (-1)

#define rb_exc_new2             rb_exc_new_cstr  /**< @old{rb_exc_new_cstr} */
#define rb_exc_new3             rb_exc_new_str  /**< @old{rb_exc_new_str} */

/** @cond INTERNAL_MACRO */
#define rb_check_arity          rb_check_arity
/** @endcond */

RBIMPL_SYMBOL_EXPORT_BEGIN()

/* error.c */

/**
 * Creates an instance of the passed exception class.
 *
 * @param[in]  etype           A subclass of ::rb_eException.
 * @param[in]  ptr             Buffer contains error message.
 * @param[in]  len             Length  of `ptr`,  in bytes,  not including  the
 *                             terminating NUL character.
 * @exception  rb_eTypeError  `etype` is not a class.
 * @exception  rb_eArgError   `len` is negative.
 * @return     An instance of `etype`.
 * @pre        At  least  `len` bytes  of  continuous  memory region  shall  be
 *             accessible via `ptr`.
 *
 * @internal
 *
 * This function works for non-exception classes  as well, as long as they take
 * one string argument.
 */
VALUE rb_exc_new(VALUE etype, const char *ptr, long len);

RBIMPL_ATTR_NONNULL(())
/**
 * Identical to rb_exc_new(), except it assumes the passed pointer is a pointer
 * to a C string.
 *
 * @param[in]  etype           A subclass of ::rb_eException.
 * @param[in]  str             A C string (becomes an error message).
 * @exception  rb_eTypeError  `etype` is not a class.
 * @return     An instance of `etype`.
 */
VALUE rb_exc_new_cstr(VALUE etype, const char *str);

/**
 * Identical to rb_exc_new_cstr(),  except it takes a Ruby's  string instead of
 * C's.
 *
 * @param[in]  etype           A subclass of ::rb_eException.
 * @param[in]  str             An instance of ::rb_cString.
 * @exception  rb_eTypeError  `etype` is not a class.
 * @return     An instance of `etype`.
 */
VALUE rb_exc_new_str(VALUE etype, VALUE str);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
 * Raises an instance of ::rb_eLoadError.
 *
 * @param[in]  fmt  Format specifier string compatible with rb_sprintf().
 * @exception  rb_eLoadError  Always raises this.
 * @note       It never returns.
 *
 * @internal
 *
 * Who needs this?  Except ruby itself?
 */
void rb_loaderror(const char *fmt, ...);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
 * Identical  to rb_loaderror(),  except it  additionally takes  which file  is
 * unable to  load.  The path can  be obtained later using  `LoadError#path` of
 * the raising exception.
 *
 * @param[in]  path  What failed.
 * @param[in]  fmt   Format specifier string compatible with rb_sprintf().
 * @exception  rb_eLoadError  Always raises this.
 * @note       It never returns.
 */
void rb_loaderror_with_path(VALUE path, const char *fmt, ...);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
 * Raises an instance of ::rb_eNameError.  The name can be obtained later using
 * `NameError#name` of the raising exception.
 *
 * @param[in]  name  What failed.
 * @param[in]  fmt   Format specifier string compatible with rb_sprintf().
 * @exception  rb_eNameError  Always raises this.
 * @note       It never returns.
 */
void rb_name_error(ID name, const char *fmt, ...);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
 * Identical to rb_name_error(), except it takes a ::VALUE instead of ::ID.
 *
 * @param[in]  name  What failed.
 * @param[in]  fmt   Format specifier string compatible with rb_sprintf().
 * @exception  rb_eNameError  Always raises this.
 * @note       It never returns.
 */
void rb_name_error_str(VALUE name, const char *fmt, ...);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
 * Raises an instance  of ::rb_eFrozenError.  The object can  be obtained later
 * using `FrozenError#receiver` of the raising exception.
 *
 * @param[in]  recv  What is frozen.
 * @param[in]  fmt   Format specifier string compatible with rb_sprintf().
 * @exception  rb_eFrozenError  Always raises this.
 * @note       It never returns.
 *
 * @internal
 *
 * Note however,  that it  is often  not possible to  inspect a  frozen object,
 * because the inspection itself could be forbidden by the frozen-ness.
 */
void rb_frozen_error_raise(VALUE recv, const char *fmt, ...);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL(())
/**
 * Honestly  I  don't  understand  the  name, but  it  raises  an  instance  of
 * ::rb_eArgError.
 *
 * @param[in]  str           A message.
 * @param[in]  type          Another message.
 * @exception  rb_eArgError  Always raises this.
 * @note       It never returns.
 */
void rb_invalid_str(const char *str, const char *type);

RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_NONNULL(())
/**
 * Identical  to rb_frozen_error_raise(),  except its  raising exception  has a
 * message like "can't modify frozen /what/".
 *
 * @param[in]  what             What was frozen.
 * @exception  rb_eFrozenError  Always raises this.
 * @note       It never returns.
 */
void rb_error_frozen(const char *what);

/**
 * Identical  to  rb_error_frozen(),  except  it takes  arbitrary  Ruby  object
 * instead of C's string.
 *
 * @param[in]  what             What was frozen.
 * @exception  rb_eFrozenError  Always raises this.
 * @note       It never returns.
 */
void rb_error_frozen_object(VALUE what);

/**
 * Queries  if the  passed  object is  frozen.
 *
 * @param[in]  obj  Target object to test frozen-ness.
 * @exception  rb_eFrozenError  It is frozen.
 * @post       Upon successful return it is guaranteed _not_ frozen.
 */
void rb_check_frozen(VALUE obj);

/**
 * Ensures that the passed object  can be `initialize_copy` relationship.  When
 * you implement your own one you would better call this at the right beginning
 * of your implementation.
 *
 * @param[in]  obj              Destination object.
 * @param[in]  orig             Source object.
 * @exception  rb_eFrozenError  `obj` is frozen.
 * @post       Upon successful return obj is guaranteed safe to copy orig.
 */
void rb_check_copyable(VALUE obj, VALUE orig);

RBIMPL_ATTR_NORETURN()
/**
 * @private
 *
 * This  is an  implementation detail  of  rb_scan_args().  You  don't have  to
 * bother.
 *
 * @pre        `argc` is out of range of `min`..`max`, both inclusive.
 * @param[in]  argc          Arbitrary integer.
 * @param[in]  min           Minimum allowed `argc`.
 * @param[in]  max           Maximum allowed `argc`.
 * @exception  rb_eArgError  Always.
 */
void rb_error_arity(int argc, int min, int max);

RBIMPL_SYMBOL_EXPORT_END()

/**
 * @deprecated
 *
 * Does anyone use this?  Remain not deleted for compatibility.
 */
#define rb_check_frozen_internal(obj) do { \
        VALUE frozen_obj = (obj); \
        if (RB_UNLIKELY(RB_OBJ_FROZEN(frozen_obj))) { \
            rb_error_frozen_object(frozen_obj); \
        } \
    } while (0)

/** @alias{rb_check_frozen} */
static inline void
rb_check_frozen_inline(VALUE obj)
{
    if (RB_UNLIKELY(RB_OBJ_FROZEN(obj))) {
        rb_error_frozen_object(obj);
    }
}

/** @alias{rb_check_frozen} */
#define rb_check_frozen rb_check_frozen_inline

/**
 * Ensures that the  passed integer is in  the passed range.  When  you can use
 * rb_scan_args() that is preferred over this one (powerful, descriptive).  But
 * it can have its own application area.
 *
 * @param[in]  argc          Arbitrary integer.
 * @param[in]  min           Minimum allowed `argv`.
 * @param[in]  max           Maximum allowed `argv`, or `UNLIMITED_ARGUMENTS`.
 * @exception  rb_eArgError  `argc` out of range.
 * @return     The passed `argc`.
 * @post       Upon successful return `argc` is  in range of `min`..`max`, both
 *             inclusive.
 */
static inline int
rb_check_arity(int argc, int min, int max)
{
    if ((argc < min) || (max != UNLIMITED_ARGUMENTS && argc > max))
        rb_error_arity(argc, min, max);
    return argc;
}

#endif /* RBIMPL_INTERN_ERROR_H */