Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/freebl/verified/eurydice_glue.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#if defined(__cplusplus)
4
extern "C" {
5
#endif
6
7
#include <inttypes.h>
8
#include <stdbool.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
13
#ifdef _MSC_VER
14
#include <intrin.h>
15
#endif
16
17
#include "krml/internal/target.h"
18
#include "krml/lowstar_endianness.h"
19
20
#define LowStar_Ignore_ignore(e, t, _ret_t) ((void)e)
21
22
// SLICES, ARRAYS, ETC.
23
24
#if defined(__cplusplus)
25
#define CLITERAL(type) type
26
#else
27
0
#define CLITERAL(type) (type)
28
#endif
29
30
// We represent a slice as a pair of an (untyped) pointer, along with the length
31
// of the slice, i.e. the number of elements in the slice (this is NOT the
32
// number of bytes). This design choice has two important consequences.
33
// - if you need to use `ptr`, you MUST cast it to a proper type *before*
34
// performing pointer
35
//   arithmetic on it (remember that C desugars pointer arithmetic based on the
36
//   type of the address)
37
// - if you need to use `len` for a C style function (e.g. memcpy, memcmp), you
38
// need to multiply it
39
//   by sizeof t, where t is the type of the elements.
40
typedef struct {
41
    void *ptr;
42
    size_t len;
43
} Eurydice_slice;
44
45
// Helper macro to create a slice out of a pointer x, a start index in x
46
// (included), and an end index in x (excluded). The argument x must be suitably
47
// cast to something that can decay (see remark above about how pointer
48
// arithmetic works in C), meaning either pointer or array type.
49
#define EURYDICE_SLICE(x, start, end) \
50
0
    (CLITERAL(Eurydice_slice){ .ptr = (void *)(x + start), .len = end - start })
51
0
#define EURYDICE_SLICE_LEN(s, _) s.len
52
// This macro is a pain because in case the dereferenced element type is an
53
// array, you cannot simply write `t x` as it would yield `int[4] x` instead,
54
// which is NOT correct C syntax, so we add a dedicated phase in Eurydice that
55
// adds an extra argument to this macro at the last minute so that we have the
56
// correct type of *pointers* to elements.
57
0
#define Eurydice_slice_index(s, i, t, t_ptr_t) (((t_ptr_t)s.ptr)[i])
58
#define Eurydice_slice_subslice(s, r, t, _) \
59
    EURYDICE_SLICE((t *)s.ptr, r.start, r.end)
60
// Variant for when the start and end indices are statically known (i.e., the
61
// range argument `r` is a literal).
62
#define Eurydice_slice_subslice2(s, start, end, t) \
63
0
    EURYDICE_SLICE((t *)s.ptr, start, end)
64
#define Eurydice_slice_subslice_to(s, subslice_end_pos, t, _) \
65
0
    EURYDICE_SLICE((t *)s.ptr, 0, subslice_end_pos)
66
#define Eurydice_slice_subslice_from(s, subslice_start_pos, t, _) \
67
0
    EURYDICE_SLICE((t *)s.ptr, subslice_start_pos, s.len)
68
#define Eurydice_array_to_slice(end, x, t) \
69
0
    EURYDICE_SLICE(x, 0,                   \
70
0
                   end) /* x is already at an array type, no need for cast */
71
#define Eurydice_array_to_subslice(_arraylen, x, r, t, _) \
72
    EURYDICE_SLICE((t *)x, r.start, r.end)
73
// Same as above, variant for when start and end are statically known
74
#define Eurydice_array_to_subslice2(x, start, end, t) \
75
0
    EURYDICE_SLICE((t *)x, start, end)
76
#define Eurydice_array_to_subslice_to(_size, x, r, t, _range_t) \
77
0
    EURYDICE_SLICE((t *)x, 0, r)
78
#define Eurydice_array_to_subslice_from(size, x, r, t, _range_t) \
79
0
    EURYDICE_SLICE((t *)x, r, size)
80
#define Eurydice_array_repeat(dst, len, init, t) \
81
    ERROR "should've been desugared"
82
0
#define Eurydice_slice_len(s, t) EURYDICE_SLICE_LEN(s, t)
83
#define Eurydice_slice_copy(dst, src, t) \
84
0
    memcpy(dst.ptr, src.ptr, dst.len * sizeof(t))
85
#define core_array___Array_T__N__23__as_slice(len_, ptr_, t, _ret_t) \
86
    ((Eurydice_slice){ .ptr = ptr_, .len = len_ })
87
88
#define core_array___core__clone__Clone_for__Array_T__N___20__clone( \
89
    len, src, dst, elem_type, _ret_t)                                \
90
    (memcpy(dst, src, len * sizeof(elem_type)))
91
#define core_array_TryFromSliceError uint8_t
92
93
#define Eurydice_array_eq(sz, a1, a2, t, _) \
94
0
    (memcmp(a1, a2, sz * sizeof(t)) == 0)
95
#define core_array_equality___core__cmp__PartialEq__Array_U__N___for__Array_T__N____eq( \
96
    sz, a1, a2, t, _, _ret_t)                                                           \
97
0
    Eurydice_array_eq(sz, a1, a2, t, _)
98
#define core_array_equality___core__cmp__PartialEq__0___Slice_U____for__Array_T__N___3__eq( \
99
    sz, a1, a2, t, _, _ret_t)                                                               \
100
0
    Eurydice_array_eq(sz, a1, ((a2)->ptr), t, _)
101
102
#define Eurydice_slice_split_at(slice, mid, element_type, ret_t)  \
103
0
    (CLITERAL(ret_t){                                             \
104
0
        .fst = EURYDICE_SLICE((element_type *)slice.ptr, 0, mid), \
105
0
        .snd = EURYDICE_SLICE((element_type *)slice.ptr, mid, slice.len) })
106
#define Eurydice_slice_split_at_mut(slice, mid, element_type, ret_t)    \
107
0
    (CLITERAL(ret_t){                                                   \
108
0
        .fst = { .ptr = slice.ptr, .len = mid },                        \
109
0
        .snd = { .ptr = (char *)slice.ptr + mid * sizeof(element_type), \
110
0
                 .len = slice.len - mid } })
111
112
// Conversion of slice to an array, rewritten (by Eurydice) to name the
113
// destination array, since arrays are not values in C.
114
// N.B.: see note in karamel/lib/Inlining.ml if you change this.
115
#define Eurydice_slice_to_array2(dst, src, _, t_arr)                        \
116
0
    Eurydice_slice_to_array3(&(dst)->tag, (char *)&(dst)->val.case_Ok, src, \
117
0
                             sizeof(t_arr))
118
119
static inline void
120
Eurydice_slice_to_array3(uint8_t *dst_tag, char *dst_ok,
121
                         Eurydice_slice src, size_t sz)
122
0
{
123
0
    *dst_tag = 0;
124
0
    memcpy(dst_ok, src.ptr, sz);
125
0
}
Unexecuted instantiation: kyber.c:Eurydice_slice_to_array3
Unexecuted instantiation: libcrux_mlkem768_portable.c:Eurydice_slice_to_array3
Unexecuted instantiation: libcrux_mlkem_portable.c:Eurydice_slice_to_array3
Unexecuted instantiation: libcrux_core.c:Eurydice_slice_to_array3
126
127
// CORE STUFF (conversions, endianness, ...)
128
129
static inline void
130
core_num__u32_8__to_be_bytes(uint32_t src, uint8_t dst[4])
131
0
{
132
0
    // TODO: why not store32_be?
133
0
    uint32_t x = htobe32(src);
134
0
    memcpy(dst, &x, 4);
135
0
}
Unexecuted instantiation: kyber.c:core_num__u32_8__to_be_bytes
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u32_8__to_be_bytes
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u32_8__to_be_bytes
Unexecuted instantiation: libcrux_core.c:core_num__u32_8__to_be_bytes
136
137
static inline uint32_t
138
core_num__u32_8__from_le_bytes(uint8_t buf[4])
139
0
{
140
0
    return load32_le(buf);
141
0
}
Unexecuted instantiation: kyber.c:core_num__u32_8__from_le_bytes
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u32_8__from_le_bytes
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u32_8__from_le_bytes
Unexecuted instantiation: libcrux_core.c:core_num__u32_8__from_le_bytes
142
143
static inline void
144
core_num__u64_9__to_le_bytes(uint64_t v, uint8_t buf[8])
145
0
{
146
0
    store64_le(buf, v);
147
0
}
Unexecuted instantiation: kyber.c:core_num__u64_9__to_le_bytes
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u64_9__to_le_bytes
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u64_9__to_le_bytes
Unexecuted instantiation: libcrux_core.c:core_num__u64_9__to_le_bytes
148
static inline uint64_t
149
core_num__u64_9__from_le_bytes(uint8_t buf[8])
150
0
{
151
0
    return load64_le(buf);
152
0
}
Unexecuted instantiation: kyber.c:core_num__u64_9__from_le_bytes
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u64_9__from_le_bytes
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u64_9__from_le_bytes
Unexecuted instantiation: libcrux_core.c:core_num__u64_9__from_le_bytes
153
154
static inline int64_t
155
core_convert_num___core__convert__From_i32__for_i64__59__from(int32_t x)
156
0
{
157
0
    return x;
158
0
}
Unexecuted instantiation: kyber.c:core_convert_num___core__convert__From_i32__for_i64__59__from
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_convert_num___core__convert__From_i32__for_i64__59__from
Unexecuted instantiation: libcrux_mlkem_portable.c:core_convert_num___core__convert__From_i32__for_i64__59__from
Unexecuted instantiation: libcrux_core.c:core_convert_num___core__convert__From_i32__for_i64__59__from
159
160
static inline uint64_t
161
core_convert_num___core__convert__From_u8__for_u64__66__from(uint8_t x)
162
0
{
163
0
    return x;
164
0
}
Unexecuted instantiation: kyber.c:core_convert_num___core__convert__From_u8__for_u64__66__from
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_convert_num___core__convert__From_u8__for_u64__66__from
Unexecuted instantiation: libcrux_mlkem_portable.c:core_convert_num___core__convert__From_u8__for_u64__66__from
Unexecuted instantiation: libcrux_core.c:core_convert_num___core__convert__From_u8__for_u64__66__from
165
166
static inline uint64_t
167
core_convert_num___core__convert__From_u16__for_u64__70__from(uint16_t x)
168
0
{
169
0
    return x;
170
0
}
Unexecuted instantiation: kyber.c:core_convert_num___core__convert__From_u16__for_u64__70__from
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_convert_num___core__convert__From_u16__for_u64__70__from
Unexecuted instantiation: libcrux_mlkem_portable.c:core_convert_num___core__convert__From_u16__for_u64__70__from
Unexecuted instantiation: libcrux_core.c:core_convert_num___core__convert__From_u16__for_u64__70__from
171
172
static inline size_t
173
core_convert_num___core__convert__From_u16__for_usize__96__from(uint16_t x)
174
0
{
175
0
    return x;
176
0
}
Unexecuted instantiation: kyber.c:core_convert_num___core__convert__From_u16__for_usize__96__from
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_convert_num___core__convert__From_u16__for_usize__96__from
Unexecuted instantiation: libcrux_mlkem_portable.c:core_convert_num___core__convert__From_u16__for_usize__96__from
Unexecuted instantiation: libcrux_core.c:core_convert_num___core__convert__From_u16__for_usize__96__from
177
178
static inline uint32_t
179
core_num__u8_6__count_ones(uint8_t x0)
180
0
{
181
0
#ifdef _MSC_VER
182
0
    return __popcnt(x0);
183
0
#else
184
0
    return __builtin_popcount(x0);
185
0
#endif
186
0
}
Unexecuted instantiation: kyber.c:core_num__u8_6__count_ones
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u8_6__count_ones
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u8_6__count_ones
Unexecuted instantiation: libcrux_core.c:core_num__u8_6__count_ones
187
188
// unsigned overflow wraparound semantics in C
189
static inline uint16_t
190
core_num__u16_7__wrapping_add(uint16_t x, uint16_t y)
191
0
{
192
0
    return x + y;
193
0
}
Unexecuted instantiation: kyber.c:core_num__u16_7__wrapping_add
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u16_7__wrapping_add
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u16_7__wrapping_add
Unexecuted instantiation: libcrux_core.c:core_num__u16_7__wrapping_add
194
static inline uint8_t
195
core_num__u8_6__wrapping_sub(uint8_t x, uint8_t y)
196
0
{
197
0
    return x - y;
198
0
}
Unexecuted instantiation: kyber.c:core_num__u8_6__wrapping_sub
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num__u8_6__wrapping_sub
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num__u8_6__wrapping_sub
Unexecuted instantiation: libcrux_core.c:core_num__u8_6__wrapping_sub
199
200
static inline void
201
core_ops_arith__i32_319__add_assign(int32_t *x0,
202
                                    int32_t *x1)
203
0
{
204
0
    *x0 = *x0 + *x1;
205
0
}
Unexecuted instantiation: kyber.c:core_ops_arith__i32_319__add_assign
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_ops_arith__i32_319__add_assign
Unexecuted instantiation: libcrux_mlkem_portable.c:core_ops_arith__i32_319__add_assign
Unexecuted instantiation: libcrux_core.c:core_ops_arith__i32_319__add_assign
206
207
static inline uint8_t
208
Eurydice_bitand_pv_u8(uint8_t *p, uint8_t v)
209
0
{
210
0
    return (*p) & v;
211
0
}
Unexecuted instantiation: kyber.c:Eurydice_bitand_pv_u8
Unexecuted instantiation: libcrux_mlkem768_portable.c:Eurydice_bitand_pv_u8
Unexecuted instantiation: libcrux_mlkem_portable.c:Eurydice_bitand_pv_u8
Unexecuted instantiation: libcrux_core.c:Eurydice_bitand_pv_u8
212
static inline uint8_t
213
Eurydice_shr_pv_u8(uint8_t *p, int32_t v)
214
0
{
215
0
    return (*p) >> v;
216
0
}
Unexecuted instantiation: kyber.c:Eurydice_shr_pv_u8
Unexecuted instantiation: libcrux_mlkem768_portable.c:Eurydice_shr_pv_u8
Unexecuted instantiation: libcrux_mlkem_portable.c:Eurydice_shr_pv_u8
Unexecuted instantiation: libcrux_core.c:Eurydice_shr_pv_u8
217
218
#define core_num_nonzero_private_NonZeroUsizeInner size_t
219
static inline core_num_nonzero_private_NonZeroUsizeInner
220
core_num_nonzero_private___core__clone__Clone_for_core__num__nonzero__private__NonZeroUsizeInner__26__clone(
221
    core_num_nonzero_private_NonZeroUsizeInner *x0)
222
0
{
223
0
    return *x0;
224
0
}
Unexecuted instantiation: kyber.c:core_num_nonzero_private___core__clone__Clone_for_core__num__nonzero__private__NonZeroUsizeInner__26__clone
Unexecuted instantiation: libcrux_mlkem768_portable.c:core_num_nonzero_private___core__clone__Clone_for_core__num__nonzero__private__NonZeroUsizeInner__26__clone
Unexecuted instantiation: libcrux_mlkem_portable.c:core_num_nonzero_private___core__clone__Clone_for_core__num__nonzero__private__NonZeroUsizeInner__26__clone
Unexecuted instantiation: libcrux_core.c:core_num_nonzero_private___core__clone__Clone_for_core__num__nonzero__private__NonZeroUsizeInner__26__clone
225
226
// ITERATORS
227
#define Eurydice_range_iter_next(iter_ptr, t, ret_t)    \
228
0
    (((iter_ptr)->start == (iter_ptr)->end)             \
229
0
         ? (CLITERAL(ret_t){ .tag = core_option_None }) \
230
0
         : (CLITERAL(ret_t){ .tag = core_option_Some,   \
231
0
                             .f0 = (iter_ptr)->start++ }))
232
233
// Old name (TODO: remove once everyone has upgraded to the latest Charon)
234
#define core_iter_range___core__iter__traits__iterator__Iterator_for_core__ops__range__Range_A___3__next \
235
    Eurydice_range_iter_next
236
237
#define core_iter_range___core__iter__traits__iterator__Iterator_for_core__ops__range__Range_A___6__next \
238
0
    Eurydice_range_iter_next
239
240
// See note in karamel/lib/Inlining.ml if you change this
241
0
#define Eurydice_into_iter(x, t, _ret_t) (x)
242
#define core_iter_traits_collect___core__iter__traits__collect__IntoIterator_for_I___into_iter \
243
    Eurydice_into_iter
244
// This name changed on 20240627
245
#define core_iter_traits_collect___core__iter__traits__collect__IntoIterator_for_I__1__into_iter \
246
0
    Eurydice_into_iter
247
248
typedef struct {
249
    Eurydice_slice slice;
250
    size_t chunk_size;
251
} Eurydice_chunks;
252
253
// Can't use macros Eurydice_slice_subslice_{to,from} because they require a
254
// type, and this static inline function cannot receive a type as an argument.
255
// Instead, we receive the element size and use it to peform manual offset
256
// computations rather than going through the macros.
257
static inline Eurydice_slice
258
chunk_next(Eurydice_chunks *chunks,
259
           size_t element_size)
260
0
{
261
0
    size_t chunk_size = chunks->slice.len >= chunks->chunk_size
262
0
                            ? chunks->chunk_size
263
0
                            : chunks->slice.len;
264
0
    Eurydice_slice curr_chunk;
265
0
    curr_chunk.ptr = chunks->slice.ptr;
266
0
    curr_chunk.len = chunk_size;
267
0
    chunks->slice.ptr = (char *)(chunks->slice.ptr) + chunk_size * element_size;
268
0
    chunks->slice.len = chunks->slice.len - chunk_size;
269
0
    return curr_chunk;
270
0
}
Unexecuted instantiation: kyber.c:chunk_next
Unexecuted instantiation: libcrux_mlkem768_portable.c:chunk_next
Unexecuted instantiation: libcrux_mlkem_portable.c:chunk_next
Unexecuted instantiation: libcrux_core.c:chunk_next
271
272
#define core_slice___Slice_T___chunks(slice_, sz_, t, _ret_t) \
273
    ((Eurydice_chunks){ .slice = slice_, .chunk_size = sz_ })
274
#define core_slice___Slice_T___chunks_exact(slice_, sz_, t, _ret_t)             \
275
    ((Eurydice_chunks){                                                         \
276
        .slice = { .ptr = slice_.ptr, .len = slice_.len - (slice_.len % sz_) }, \
277
        .chunk_size = sz_ })
278
#define core_slice_iter_Chunks Eurydice_chunks
279
#define core_slice_iter_ChunksExact Eurydice_chunks
280
#define Eurydice_chunks_next(iter, t, ret_t)                         \
281
    (((iter)->slice.len == 0) ? ((ret_t){ .tag = core_option_None }) \
282
                              : ((ret_t){ .tag = core_option_Some,   \
283
                                          .f0 = chunk_next(iter, sizeof(t)) }))
284
#define core_slice_iter___core__iter__traits__iterator__Iterator_for_core__slice__iter__Chunks__a__T___70__next \
285
    Eurydice_chunks_next
286
// This name changed on 20240627
287
#define core_slice_iter___core__iter__traits__iterator__Iterator_for_core__slice__iter__Chunks__a__T___71__next \
288
    Eurydice_chunks_next
289
#define core_slice_iter__core__slice__iter__ChunksExact__a__T__89__next( \
290
    iter, t, _ret_t)                                                     \
291
    core_slice_iter__core__slice__iter__Chunks__a__T__70__next(iter, t)
292
293
typedef struct {
294
    Eurydice_slice s;
295
    size_t index;
296
} Eurydice_slice_iterator;
297
298
#define core_slice___Slice_T___iter(x, t, _ret_t) \
299
    ((Eurydice_slice_iterator){ .s = x, .index = 0 })
300
#define core_slice_iter_Iter Eurydice_slice_iterator
301
#define core_slice_iter__core__slice__iter__Iter__a__T__181__next(iter, t, \
302
                                                                  ret_t)   \
303
    (((iter)->index == (iter)->s.len)                                      \
304
         ? (CLITERAL(ret_t){ .tag = core_option_None })                    \
305
         : (CLITERAL(ret_t){                                               \
306
               .tag = core_option_Some,                                    \
307
               .f0 = ((iter)->index++,                                     \
308
                      &((t *)((iter)->s.ptr))[(iter)->index - 1]) }))
309
310
// STRINGS
311
312
typedef const char *Prims_string;
313
314
// MISC (UNTESTED)
315
316
typedef void *core_fmt_Formatter;
317
typedef void *core_fmt_Arguments;
318
typedef void *core_fmt_rt_Argument;
319
#define core_fmt_rt__core__fmt__rt__Argument__a__1__new_display(x1, x2, x3, \
320
                                                                x4)         \
321
    NULL
322
323
// VECTORS (ANCIENT, POSSIBLY UNTESTED)
324
325
/* For now these are passed by value -- three words. We could conceivably change
326
 * the representation to heap-allocate this struct and only pass around the
327
 * pointer (one word). */
328
typedef struct {
329
    void *ptr;
330
    size_t len;        /* the number of elements */
331
    size_t alloc_size; /* the size of the allocation, in number of BYTES */
332
} Eurydice_vec_s, *Eurydice_vec;
333
334
/* Here, we set everything to zero rather than use a non-standard GCC
335
 * statement-expression -- this suitably initializes ptr to NULL and len and
336
 * size to 0. */
337
#define EURYDICE_VEC_NEW(_) calloc(1, sizeof(Eurydice_vec_s))
338
#define EURYDICE_VEC_PUSH(v, x, t)                                              \
339
    do {                                                                        \
340
        /* Grow the vector if capacity has been reached. */                     \
341
        if (v->len == v->alloc_size / sizeof(t)) {                              \
342
            /* Assuming that this does not exceed SIZE_MAX, because code proven \
343
             * correct by Aeneas. Would this even happen in practice? */        \
344
            size_t new_size;                                                    \
345
            if (v->alloc_size == 0)                                             \
346
                new_size = 8 * sizeof(t);                                       \
347
            else if (v->alloc_size <= SIZE_MAX / 2)                             \
348
                /* TODO: discuss growth policy */                               \
349
                new_size = 2 * v->alloc_size;                                   \
350
            else                                                                \
351
                new_size = (SIZE_MAX / sizeof(t)) * sizeof(t);                  \
352
            v->ptr = realloc(v->ptr, new_size);                                 \
353
            v->alloc_size = new_size;                                           \
354
        }                                                                       \
355
        ((t *)v->ptr)[v->len] = x;                                              \
356
        v->len++;                                                               \
357
    } while (0)
358
359
#define EURYDICE_VEC_DROP(v, t) \
360
    do {                        \
361
        free(v->ptr);           \
362
        free(v);                \
363
    } while (0)
364
365
#define EURYDICE_VEC_INDEX(v, i, t) &((t *)v->ptr)[i]
366
#define EURYDICE_VEC_LEN(v, t) (v)->len
367
368
/* TODO: remove GCC-isms */
369
#define EURYDICE_BOX_NEW(x, t)    \
370
    ({                            \
371
        t *p = malloc(sizeof(t)); \
372
        *p = x;                   \
373
        p;                        \
374
    })
375
376
#define EURYDICE_REPLACE(ptr, new_v, t) \
377
    ({                                  \
378
        t old_v = *ptr;                 \
379
        *ptr = new_v;                   \
380
        old_v;                          \
381
    })
382
383
#if defined(__cplusplus)
384
}
385
#endif