• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 7262987147

19 Dec 2023 02:10PM UTC coverage: 88.225% (-0.4%) from 88.616%
7262987147

push

github

fckxorg
test: add tests for debugging extensions

This patch adds tests for LuaJIT debugging
extensions for lldb and gdb.

5336 of 5969 branches covered (0.0%)

Branch coverage included in aggregate %.

20475 of 23287 relevant lines covered (87.92%)

1285545.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.83
/src/lj_cparse.c
1
/*
2
** C declaration parser.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
*/
5

6
#include "lj_obj.h"
7

8
#if LJ_HASFFI
9

10
#include "lj_gc.h"
11
#include "lj_err.h"
12
#include "lj_buf.h"
13
#include "lj_ctype.h"
14
#include "lj_cparse.h"
15
#include "lj_frame.h"
16
#include "lj_vm.h"
17
#include "lj_char.h"
18
#include "lj_strscan.h"
19
#include "lj_strfmt.h"
20

21
/*
22
** Important note: this is NOT a validating C parser! This is a minimal
23
** C declaration parser, solely for use by the LuaJIT FFI.
24
**
25
** It ought to return correct results for properly formed C declarations,
26
** but it may accept some invalid declarations, too (and return nonsense).
27
** Also, it shows rather generic error messages to avoid unnecessary bloat.
28
** If in doubt, please check the input against your favorite C compiler.
29
*/
30

31
#ifdef LUA_USE_ASSERT
32
#define lj_assertCP(c, ...)        (lj_assertG_(G(cp->L), (c), __VA_ARGS__))
33
#else
34
#define lj_assertCP(c, ...)        ((void)cp)
35
#endif
36

37
/* -- Miscellaneous ------------------------------------------------------- */
38

39
/* Match string against a C literal. */
40
#define cp_str_is(str, k) \
41
  ((str)->len == sizeof(k)-1 && !memcmp(strdata(str), k, sizeof(k)-1))
42

43
/* Check string against a linear list of matches. */
44
int lj_cparse_case(GCstr *str, const char *match)
269✔
45
{
46
  MSize len;
269✔
47
  int n;
269✔
48
  for  (n = 0; (len = (MSize)*match++); n++, match += len) {
960✔
49
    if (str->len == len && !memcmp(match, strdata(str), len))
847✔
50
      return n;
156✔
51
  }
52
  return -1;
53
}
54

55
/* -- C lexer ------------------------------------------------------------- */
56

57
/* C lexer token names. */
58
static const char *const ctoknames[] = {
59
#define CTOKSTR(name, str)        str,
60
CTOKDEF(CTOKSTR)
61
#undef CTOKSTR
62
  NULL
63
};
64

65
/* Forward declaration. */
66
LJ_NORET static void cp_err(CPState *cp, ErrMsg em);
67

68
static const char *cp_tok2str(CPState *cp, CPToken tok)
69
{
70
  lj_assertCP(tok < CTOK_FIRSTDECL, "bad CPToken %d", tok);
71
  if (tok > CTOK_OFS)
72
    return ctoknames[tok-CTOK_OFS-1];
73
  else if (!lj_char_iscntrl(tok))
74
    return lj_strfmt_pushf(cp->L, "%c", tok);
75
  else
76
    return lj_strfmt_pushf(cp->L, "char(%d)", tok);
77
}
78

79
/* End-of-line? */
80
static LJ_AINLINE int cp_iseol(CPChar c)
320✔
81
{
82
  return (c == '\n' || c == '\r');
320✔
83
}
84

85
/* Peek next raw character. */
86
static LJ_AINLINE CPChar cp_rawpeek(CPState *cp)
195✔
87
{
88
  return (CPChar)(uint8_t)(*cp->p);
195✔
89
}
90

91
static LJ_NOINLINE CPChar cp_get_bs(CPState *cp);
92

93
/* Get next character. */
94
static LJ_AINLINE CPChar cp_get(CPState *cp)
3,980,082✔
95
{
96
  cp->c = (CPChar)(uint8_t)(*cp->p++);
3,980,082✔
97
  if (LJ_LIKELY(cp->c != '\\')) return cp->c;
3,980,082✔
98
  return cp_get_bs(cp);
×
99
}
100

101
/* Transparently skip backslash-escaped line breaks. */
102
static LJ_NOINLINE CPChar cp_get_bs(CPState *cp)
×
103
{
104
  CPChar c2, c = cp_rawpeek(cp);
×
105
  if (!cp_iseol(c)) return cp->c;
×
106
  cp->p++;
×
107
  c2 = cp_rawpeek(cp);
×
108
  if (cp_iseol(c2) && c2 != c) cp->p++;
×
109
  cp->linenumber++;
×
110
  return cp_get(cp);
×
111
}
112

113
/* Save character in buffer. */
114
static LJ_AINLINE void cp_save(CPState *cp, CPChar c)
3,535,132✔
115
{
116
  lj_buf_putb(&cp->sb, c);
7,070,264✔
117
}
×
118

119
/* Skip line break. Handles "\n", "\r", "\r\n" or "\n\r". */
120
static void cp_newline(CPState *cp)
195✔
121
{
122
  CPChar c = cp_rawpeek(cp);
195✔
123
  if (cp_iseol(c) && c != cp->c) cp->p++;
13✔
124
  cp->linenumber++;
195✔
125
}
195✔
126

127
LJ_NORET static void cp_errmsg(CPState *cp, CPToken tok, ErrMsg em, ...)
×
128
{
129
  const char *msg, *tokstr;
×
130
  lua_State *L;
×
131
  va_list argp;
×
132
  if (tok == 0) {
×
133
    tokstr = NULL;
134
  } else if (tok == CTOK_IDENT || tok == CTOK_INTEGER || tok == CTOK_STRING ||
×
135
             tok >= CTOK_FIRSTDECL) {
×
136
    if (sbufP(&cp->sb) == sbufB(&cp->sb)) cp_save(cp, '$');
×
137
    cp_save(cp, '\0');
×
138
    tokstr = sbufB(&cp->sb);
×
139
  } else {
140
    tokstr = cp_tok2str(cp, tok);
×
141
  }
142
  L = cp->L;
×
143
  va_start(argp, em);
×
144
  msg = lj_strfmt_pushvf(L, err2msg(em), argp);
×
145
  va_end(argp);
×
146
  if (tokstr)
×
147
    msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tokstr);
×
148
  if (cp->linenumber > 1)
×
149
    msg = lj_strfmt_pushf(L, "%s at line %d", msg, cp->linenumber);
×
150
  lj_err_callermsg(L, msg);
×
151
}
152

153
LJ_NORET LJ_NOINLINE static void cp_err_token(CPState *cp, CPToken tok)
×
154
{
155
  cp_errmsg(cp, cp->tok, LJ_ERR_XTOKEN, cp_tok2str(cp, tok));
×
156
}
157

158
LJ_NORET LJ_NOINLINE static void cp_err_badidx(CPState *cp, CType *ct)
×
159
{
160
  GCstr *s = lj_ctype_repr(cp->cts->L, ctype_typeid(cp->cts, ct), NULL);
×
161
  cp_errmsg(cp, 0, LJ_ERR_FFI_BADIDX, strdata(s));
×
162
}
163

164
LJ_NORET LJ_NOINLINE static void cp_err(CPState *cp, ErrMsg em)
×
165
{
166
  cp_errmsg(cp, 0, em);
×
167
}
168

169
/* -- Main lexical scanner ------------------------------------------------ */
170

171
/* Parse number literal. Only handles int32_t/uint32_t right now. */
172
static CPToken cp_number(CPState *cp)
119✔
173
{
174
  StrScanFmt fmt;
147✔
175
  TValue o;
147✔
176
  do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp)));
147✔
177
  cp_save(cp, '\0');
119✔
178
  fmt = lj_strscan_scan((const uint8_t *)sbufB(&cp->sb), sbuflen(&cp->sb)-1,
119✔
179
                        &o, STRSCAN_OPT_C);
180
  if (fmt == STRSCAN_INT) cp->val.id = CTID_INT32;
119✔
181
  else if (fmt == STRSCAN_U32) cp->val.id = CTID_UINT32;
×
182
  else if (!(cp->mode & CPARSE_MODE_SKIP))
×
183
    cp_errmsg(cp, CTOK_INTEGER, LJ_ERR_XNUMBER);
×
184
  cp->val.u32 = (uint32_t)o.i;
119✔
185
  return CTOK_INTEGER;
119✔
186
}
187

188
/* Parse identifier or keyword. */
189
static CPToken cp_ident(CPState *cp)
442,461✔
190
{
191
  do { cp_save(cp, cp->c); } while (lj_char_isident(cp_get(cp)));
3,976,561✔
192
  cp->str = lj_buf_str(cp->L, &cp->sb);
442,461✔
193
  cp->val.id = lj_ctype_getname(cp->cts, &cp->ct, cp->str, cp->tmask);
442,461✔
194
  if (ctype_type(cp->ct->info) == CT_KW)
442,461✔
195
    return ctype_cid(cp->ct->info);
1,133✔
196
  return CTOK_IDENT;
197
}
198

199
/* Parse parameter. */
200
static CPToken cp_param(CPState *cp)
2✔
201
{
202
  CPChar c = cp_get(cp);
2✔
203
  TValue *o = cp->param;
2✔
204
  if (lj_char_isident(c) || c == '$')  /* Reserve $xyz for future extensions. */
2✔
205
    cp_errmsg(cp, c, LJ_ERR_XSYNTAX);
×
206
  if (!o || o >= cp->L->top)
2✔
207
    cp_err(cp, LJ_ERR_FFI_NUMPARAM);
×
208
  cp->param = o+1;
2✔
209
  if (tvisstr(o)) {
2✔
210
    cp->str = strV(o);
×
211
    cp->val.id = 0;
×
212
    cp->ct = &cp->cts->tab[0];
×
213
    return CTOK_IDENT;
×
214
  } else if (tvisnumber(o)) {
2✔
215
    cp->val.i32 = numberVint(o);
×
216
    cp->val.id = CTID_INT32;
×
217
    return CTOK_INTEGER;
×
218
  } else {
219
    GCcdata *cd;
2✔
220
    if (!tviscdata(o))
2✔
221
      lj_err_argtype(cp->L, (int)(o-cp->L->base)+1, "type parameter");
×
222
    cd = cdataV(o);
2✔
223
    if (cd->ctypeid == CTID_CTYPEID)
2✔
224
      cp->val.id = *(CTypeID *)cdataptr(cd);
2✔
225
    else
226
      cp->val.id = cd->ctypeid;
×
227
    return '$';
2✔
228
  }
229
}
230

231
/* Parse string or character constant. */
232
static CPToken cp_string(CPState *cp)
3✔
233
{
234
  CPChar delim = cp->c;
3✔
235
  cp_get(cp);
3✔
236
  while (cp->c != delim) {
20✔
237
    CPChar c = cp->c;
17✔
238
    if (c == '\0') cp_errmsg(cp, CTOK_EOF, LJ_ERR_XSTR);
17✔
239
    if (c == '\\') {
17✔
240
      c = cp_get(cp);
×
241
      switch (c) {
×
242
      case '\0': cp_errmsg(cp, CTOK_EOF, LJ_ERR_XSTR); break;
×
243
      case 'a': c = '\a'; break;
244
      case 'b': c = '\b'; break;
×
245
      case 'f': c = '\f'; break;
×
246
      case 'n': c = '\n'; break;
×
247
      case 'r': c = '\r'; break;
×
248
      case 't': c = '\t'; break;
×
249
      case 'v': c = '\v'; break;
×
250
      case 'e': c = 27; break;
×
251
      case 'x':
252
        c = 0;
253
        while (lj_char_isxdigit(cp_get(cp)))
×
254
          c = (c<<4) + (lj_char_isdigit(cp->c) ? cp->c-'0' : (cp->c&15)+9);
×
255
        cp_save(cp, (c & 0xff));
×
256
        continue;
×
257
      default:
×
258
        if (lj_char_isdigit(c)) {
×
259
          c -= '0';
×
260
          if (lj_char_isdigit(cp_get(cp))) {
×
261
            c = c*8 + (cp->c - '0');
×
262
            if (lj_char_isdigit(cp_get(cp))) {
×
263
              c = c*8 + (cp->c - '0');
×
264
              cp_get(cp);
×
265
            }
266
          }
267
          cp_save(cp, (c & 0xff));
×
268
          continue;
×
269
        }
270
        break;
271
      }
272
    }
17✔
273
    cp_save(cp, c);
17✔
274
    cp_get(cp);
37✔
275
  }
276
  cp_get(cp);
3✔
277
  if (delim == '"') {
3✔
278
    cp->str = lj_buf_str(cp->L, &cp->sb);
3✔
279
    return CTOK_STRING;
3✔
280
  } else {
281
    if (sbuflen(&cp->sb) != 1) cp_err_token(cp, '\'');
×
282
    cp->val.i32 = (int32_t)(char)*sbufB(&cp->sb);
×
283
    cp->val.id = CTID_INT32;
×
284
    return CTOK_INTEGER;
×
285
  }
286
}
287

288
/* Skip C comment. */
289
static void cp_comment_c(CPState *cp)
4✔
290
{
291
  do {
129✔
292
    if (cp_get(cp) == '*') {
129✔
293
      do {
4✔
294
        if (cp_get(cp) == '/') { cp_get(cp); return; }
4✔
295
      } while (cp->c == '*');
×
296
    }
297
    if (cp_iseol(cp->c)) cp_newline(cp);
125✔
298
  } while (cp->c != '\0');
125✔
299
}
300

301
/* Skip C++ comment. */
302
static void cp_comment_cpp(CPState *cp)
×
303
{
304
  while (!cp_iseol(cp_get(cp)) && cp->c != '\0')
×
305
    ;
×
306
}
×
307

308
/* Lexical scanner for C. Only a minimal subset is implemented. */
309
static CPToken cp_next_(CPState *cp)
886,056✔
310
{
311
  lj_buf_reset(&cp->sb);
886,056✔
312
  for (;;) {
887,509✔
313
    if (lj_char_isident(cp->c))
887,509✔
314
      return lj_char_isdigit(cp->c) ? cp_number(cp) : cp_ident(cp);
442,580✔
315
    switch (cp->c) {
444,929✔
316
    case '\n': case '\r': cp_newline(cp);  /* fallthrough. */
195✔
317
    case ' ': case '\t': case '\v': case '\f': cp_get(cp); break;
888,958✔
318
    case '"': case '\'': return cp_string(cp);
3✔
319
    case '/':
320
      if (cp_get(cp) == '*') cp_comment_c(cp);
4✔
321
      else if (cp->c == '/') cp_comment_cpp(cp);
×
322
      else return '/';
323
      break;
324
    case '|':
325
      if (cp_get(cp) != '|') return '|';
×
326
      cp_get(cp); return CTOK_OROR;
×
327
    case '&':
328
      if (cp_get(cp) != '&') return '&';
×
329
      cp_get(cp); return CTOK_ANDAND;
×
330
    case '=':
331
      if (cp_get(cp) != '=') return '=';
1✔
332
      cp_get(cp); return CTOK_EQ;
×
333
    case '!':
334
      if (cp_get(cp) != '=') return '!';
×
335
      cp_get(cp); return CTOK_NE;
×
336
    case '<':
337
      if (cp_get(cp) == '=') { cp_get(cp); return CTOK_LE; }
×
338
      else if (cp->c == '<') { cp_get(cp); return CTOK_SHL; }
×
339
      return '<';
340
    case '>':
341
      if (cp_get(cp) == '=') { cp_get(cp); return CTOK_GE; }
×
342
      else if (cp->c == '>') { cp_get(cp); return CTOK_SHR; }
×
343
      return '>';
344
    case '-':
345
      if (cp_get(cp) != '>') return '-';
1✔
346
      cp_get(cp); return CTOK_DEREF;
×
347
    case '$':
2✔
348
      return cp_param(cp);
2✔
349
    case '\0': return CTOK_EOF;
350
    default: { CPToken c = cp->c; cp_get(cp); return c; }
1,757✔
351
    }
352
  }
353
}
354

355
static LJ_NOINLINE CPToken cp_next(CPState *cp)
886,056✔
356
{
357
  return (cp->tok = cp_next_(cp));
886,056✔
358
}
359

360
/* -- C parser ------------------------------------------------------------ */
361

362
/* Namespaces for resolving identifiers. */
363
#define CPNS_DEFAULT \
364
  ((1u<<CT_KW)|(1u<<CT_TYPEDEF)|(1u<<CT_FUNC)|(1u<<CT_EXTERN)|(1u<<CT_CONSTVAL))
365
#define CPNS_STRUCT        ((1u<<CT_KW)|(1u<<CT_STRUCT)|(1u<<CT_ENUM))
366

367
typedef CTypeID CPDeclIdx;        /* Index into declaration stack. */
368
typedef uint32_t CPscl;                /* Storage class flags. */
369

370
/* Type declaration context. */
371
typedef struct CPDecl {
372
  CPDeclIdx top;        /* Top of declaration stack. */
373
  CPDeclIdx pos;        /* Insertion position in declaration chain. */
374
  CPDeclIdx specpos;        /* Saved position for declaration specifier. */
375
  uint32_t mode;        /* Declarator mode. */
376
  CPState *cp;                /* C parser state. */
377
  GCstr *name;                /* Name of declared identifier (if direct). */
378
  GCstr *redir;                /* Redirected symbol name. */
379
  CTypeID nameid;        /* Existing typedef for declared identifier. */
380
  CTInfo attr;                /* Attributes. */
381
  CTInfo fattr;                /* Function attributes. */
382
  CTInfo specattr;        /* Saved attributes. */
383
  CTInfo specfattr;        /* Saved function attributes. */
384
  CTSize bits;                /* Field size in bits (if any). */
385
  CType stack[CPARSE_MAX_DECLSTACK];  /* Type declaration stack. */
386
} CPDecl;
387

388
/* Forward declarations. */
389
static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl);
390
static void cp_declarator(CPState *cp, CPDecl *decl);
391
static CTypeID cp_decl_abstract(CPState *cp);
392

393
/* Initialize C parser state. Caller must set up: L, p, srcname, mode. */
394
static void cp_init(CPState *cp)
441,712✔
395
{
396
  cp->linenumber = 1;
441,712✔
397
  cp->depth = 0;
441,712✔
398
  cp->curpack = 0;
441,712✔
399
  cp->packstack[0] = 255;
441,712✔
400
  lj_buf_init(cp->L, &cp->sb);
441,712✔
401
  lj_assertCP(cp->p != NULL, "uninitialized cp->p");
441,712✔
402
  cp_get(cp);  /* Read-ahead first char. */
441,712✔
403
  cp->tok = 0;
441,712✔
404
  cp->tmask = CPNS_DEFAULT;
441,712✔
405
  cp_next(cp);  /* Read-ahead first token. */
441,712✔
406
}
441,712✔
407

408
/* Cleanup C parser state. */
409
static void cp_cleanup(CPState *cp)
441,712✔
410
{
411
  global_State *g = G(cp->L);
441,712✔
412
  lj_buf_free(g, &cp->sb);
441,712✔
413
}
441,712✔
414

415
/* Check and consume optional token. */
416
static int cp_opt(CPState *cp, CPToken tok)
2,654,466✔
417
{
418
  if (cp->tok == tok) { cp_next(cp); return 1; }
1,111✔
419
  return 0;
420
}
421

422
/* Check and consume token. */
423
static void cp_check(CPState *cp, CPToken tok)
588✔
424
{
425
  if (cp->tok != tok) cp_err_token(cp, tok);
588✔
426
  cp_next(cp);
588✔
427
}
588✔
428

429
/* Check if the next token may start a type declaration. */
430
static int cp_istypedecl(CPState *cp)
6✔
431
{
432
  if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECL) return 1;
6✔
433
  if (cp->tok == CTOK_IDENT && ctype_istypedef(cp->ct->info)) return 1;
5✔
434
  if (cp->tok == '$') return 1;
5✔
435
  return 0;
436
}
437

438
/* -- Constant expression evaluator --------------------------------------- */
439

440
/* Forward declarations. */
441
static void cp_expr_unary(CPState *cp, CPValue *k);
442
static void cp_expr_sub(CPState *cp, CPValue *k, int pri);
443

444
/* Please note that type handling is very weak here. Most ops simply
445
** assume integer operands. Accessors are only needed to compute types and
446
** return synthetic values. The only purpose of the expression evaluator
447
** is to compute the values of constant expressions one would typically
448
** find in C header files. And again: this is NOT a validating C parser!
449
*/
450

451
/* Parse comma separated expression and return last result. */
452
static void cp_expr_comma(CPState *cp, CPValue *k)
×
453
{
454
  do { cp_expr_sub(cp, k, 0); } while (cp_opt(cp, ','));
×
455
}
×
456

457
/* Parse sizeof/alignof operator. */
458
static void cp_expr_sizeof(CPState *cp, CPValue *k, int wantsz)
×
459
{
460
  CTSize sz;
×
461
  CTInfo info;
×
462
  if (cp_opt(cp, '(')) {
×
463
    if (cp_istypedecl(cp))
×
464
      k->id = cp_decl_abstract(cp);
×
465
    else
466
      cp_expr_comma(cp, k);
×
467
    cp_check(cp, ')');
×
468
  } else {
469
    cp_expr_unary(cp, k);
×
470
  }
471
  info = lj_ctype_info(cp->cts, k->id, &sz);
×
472
  if (wantsz) {
×
473
    if (sz != CTSIZE_INVALID)
×
474
      k->u32 = sz;
×
475
    else if (k->id != CTID_A_CCHAR)  /* Special case for sizeof("string"). */
×
476
      cp_err(cp, LJ_ERR_FFI_INVSIZE);
×
477
  } else {
478
    k->u32 = 1u << ctype_align(info);
×
479
  }
480
  k->id = CTID_UINT32;  /* Really size_t. */
×
481
}
×
482

483
/* Parse prefix operators. */
484
static void cp_expr_prefix(CPState *cp, CPValue *k)
120✔
485
{
486
  if (cp->tok == CTOK_INTEGER) {
120✔
487
    *k = cp->val; cp_next(cp);
119✔
488
  } else if (cp_opt(cp, '+')) {
1✔
489
    cp_expr_unary(cp, k);  /* Nothing to do (well, integer promotion). */
×
490
  } else if (cp_opt(cp, '-')) {
1✔
491
    cp_expr_unary(cp, k); k->i32 = -k->i32;
1✔
492
  } else if (cp_opt(cp, '~')) {
×
493
    cp_expr_unary(cp, k); k->i32 = ~k->i32;
×
494
  } else if (cp_opt(cp, '!')) {
×
495
    cp_expr_unary(cp, k); k->i32 = !k->i32; k->id = CTID_INT32;
×
496
  } else if (cp_opt(cp, '(')) {
×
497
    if (cp_istypedecl(cp)) {  /* Cast operator. */
×
498
      CTypeID id = cp_decl_abstract(cp);
×
499
      cp_check(cp, ')');
×
500
      cp_expr_unary(cp, k);
×
501
      k->id = id;  /* No conversion performed. */
×
502
    } else {  /* Sub-expression. */
503
      cp_expr_comma(cp, k);
×
504
      cp_check(cp, ')');
×
505
    }
506
  } else if (cp_opt(cp, '*')) {  /* Indirection. */
×
507
    CType *ct;
×
508
    cp_expr_unary(cp, k);
×
509
    ct = lj_ctype_rawref(cp->cts, k->id);
×
510
    if (!ctype_ispointer(ct->info))
×
511
      cp_err_badidx(cp, ct);
×
512
    k->u32 = 0; k->id = ctype_cid(ct->info);
×
513
  } else if (cp_opt(cp, '&')) {  /* Address operator. */
×
514
    cp_expr_unary(cp, k);
×
515
    k->id = lj_ctype_intern(cp->cts, CTINFO(CT_PTR, CTALIGN_PTR+k->id),
×
516
                            CTSIZE_PTR);
517
  } else if (cp_opt(cp, CTOK_SIZEOF)) {
×
518
    cp_expr_sizeof(cp, k, 1);
×
519
  } else if (cp_opt(cp, CTOK_ALIGNOF)) {
×
520
    cp_expr_sizeof(cp, k, 0);
×
521
  } else if (cp->tok == CTOK_IDENT) {
×
522
    if (ctype_type(cp->ct->info) == CT_CONSTVAL) {
×
523
      k->u32 = cp->ct->size; k->id = ctype_cid(cp->ct->info);
×
524
    } else if (ctype_type(cp->ct->info) == CT_EXTERN) {
×
525
      k->u32 = cp->val.id; k->id = ctype_cid(cp->ct->info);
×
526
    } else if (ctype_type(cp->ct->info) == CT_FUNC) {
×
527
      k->u32 = cp->val.id; k->id = cp->val.id;
×
528
    } else {
529
      goto err_expr;
×
530
    }
531
    cp_next(cp);
×
532
  } else if (cp->tok == CTOK_STRING) {
×
533
    CTSize sz = cp->str->len;
×
534
    while (cp_next(cp) == CTOK_STRING)
×
535
      sz += cp->str->len;
×
536
    k->u32 = sz + 1;
×
537
    k->id = CTID_A_CCHAR;
×
538
  } else {
539
  err_expr:
×
540
    cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL);
×
541
  }
542
}
120✔
543

544
/* Parse postfix operators. */
545
static void cp_expr_postfix(CPState *cp, CPValue *k)
546
{
547
  for (;;) {
548
    CType *ct;
549
    if (cp_opt(cp, '[')) {  /* Array/pointer index. */
550
      CPValue k2;
551
      cp_expr_comma(cp, &k2);
552
      ct = lj_ctype_rawref(cp->cts, k->id);
553
      if (!ctype_ispointer(ct->info)) {
554
        ct = lj_ctype_rawref(cp->cts, k2.id);
555
        if (!ctype_ispointer(ct->info))
556
          cp_err_badidx(cp, ct);
557
      }
558
      cp_check(cp, ']');
559
      k->u32 = 0;
560
    } else if (cp->tok == '.' || cp->tok == CTOK_DEREF) {  /* Struct deref. */
561
      CTSize ofs;
562
      CType *fct;
563
      ct = lj_ctype_rawref(cp->cts, k->id);
564
      if (cp->tok == CTOK_DEREF) {
565
        if (!ctype_ispointer(ct->info))
566
          cp_err_badidx(cp, ct);
567
        ct = lj_ctype_rawref(cp->cts, ctype_cid(ct->info));
568
      }
569
      cp_next(cp);
570
      if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT);
571
      if (!ctype_isstruct(ct->info) || ct->size == CTSIZE_INVALID ||
572
          !(fct = lj_ctype_getfield(cp->cts, ct, cp->str, &ofs)) ||
573
          ctype_isbitfield(fct->info)) {
574
        GCstr *s = lj_ctype_repr(cp->cts->L, ctype_typeid(cp->cts, ct), NULL);
575
        cp_errmsg(cp, 0, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(cp->str));
576
      }
577
      ct = fct;
578
      k->u32 = ctype_isconstval(ct->info) ? ct->size : 0;
579
      cp_next(cp);
580
    } else {
581
      return;
582
    }
583
    k->id = ctype_cid(ct->info);
584
  }
585
}
586

587
/* Parse infix operators. */
588
static void cp_expr_infix(CPState *cp, CPValue *k, int pri)
589
{
590
  CPValue k2;
591
  k2.u32 = 0; k2.id = 0;  /* Silence the compiler. */
592
  for (;;) {
593
    switch (pri) {
594
    case 0:
595
      if (cp_opt(cp, '?')) {
596
        CPValue k3;
597
        cp_expr_comma(cp, &k2);  /* Right-associative. */
598
        cp_check(cp, ':');
599
        cp_expr_sub(cp, &k3, 0);
600
        k->u32 = k->u32 ? k2.u32 : k3.u32;
601
        k->id = k2.id > k3.id ? k2.id : k3.id;
602
        continue;
603
      }
604
      /* fallthrough */
605
    case 1:
606
      if (cp_opt(cp, CTOK_OROR)) {
607
        cp_expr_sub(cp, &k2, 2); k->i32 = k->u32 || k2.u32; k->id = CTID_INT32;
608
        continue;
609
      }
610
      /* fallthrough */
611
    case 2:
612
      if (cp_opt(cp, CTOK_ANDAND)) {
613
        cp_expr_sub(cp, &k2, 3); k->i32 = k->u32 && k2.u32; k->id = CTID_INT32;
614
        continue;
615
      }
616
      /* fallthrough */
617
    case 3:
618
      if (cp_opt(cp, '|')) {
619
        cp_expr_sub(cp, &k2, 4); k->u32 = k->u32 | k2.u32; goto arith_result;
620
      }
621
      /* fallthrough */
622
    case 4:
623
      if (cp_opt(cp, '^')) {
624
        cp_expr_sub(cp, &k2, 5); k->u32 = k->u32 ^ k2.u32; goto arith_result;
625
      }
626
      /* fallthrough */
627
    case 5:
628
      if (cp_opt(cp, '&')) {
629
        cp_expr_sub(cp, &k2, 6); k->u32 = k->u32 & k2.u32; goto arith_result;
630
      }
631
      /* fallthrough */
632
    case 6:
633
      if (cp_opt(cp, CTOK_EQ)) {
634
        cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 == k2.u32; k->id = CTID_INT32;
635
        continue;
636
      } else if (cp_opt(cp, CTOK_NE)) {
637
        cp_expr_sub(cp, &k2, 7); k->i32 = k->u32 != k2.u32; k->id = CTID_INT32;
638
        continue;
639
      }
640
      /* fallthrough */
641
    case 7:
642
      if (cp_opt(cp, '<')) {
643
        cp_expr_sub(cp, &k2, 8);
644
        if (k->id == CTID_INT32 && k2.id == CTID_INT32)
645
          k->i32 = k->i32 < k2.i32;
646
        else
647
          k->i32 = k->u32 < k2.u32;
648
        k->id = CTID_INT32;
649
        continue;
650
      } else if (cp_opt(cp, '>')) {
651
        cp_expr_sub(cp, &k2, 8);
652
        if (k->id == CTID_INT32 && k2.id == CTID_INT32)
653
          k->i32 = k->i32 > k2.i32;
654
        else
655
          k->i32 = k->u32 > k2.u32;
656
        k->id = CTID_INT32;
657
        continue;
658
      } else if (cp_opt(cp, CTOK_LE)) {
659
        cp_expr_sub(cp, &k2, 8);
660
        if (k->id == CTID_INT32 && k2.id == CTID_INT32)
661
          k->i32 = k->i32 <= k2.i32;
662
        else
663
          k->i32 = k->u32 <= k2.u32;
664
        k->id = CTID_INT32;
665
        continue;
666
      } else if (cp_opt(cp, CTOK_GE)) {
667
        cp_expr_sub(cp, &k2, 8);
668
        if (k->id == CTID_INT32 && k2.id == CTID_INT32)
669
          k->i32 = k->i32 >= k2.i32;
670
        else
671
          k->i32 = k->u32 >= k2.u32;
672
        k->id = CTID_INT32;
673
        continue;
674
      }
675
      /* fallthrough */
676
    case 8:
677
      if (cp_opt(cp, CTOK_SHL)) {
678
        cp_expr_sub(cp, &k2, 9); k->u32 = k->u32 << k2.u32;
679
        continue;
680
      } else if (cp_opt(cp, CTOK_SHR)) {
681
        cp_expr_sub(cp, &k2, 9);
682
        if (k->id == CTID_INT32)
683
          k->i32 = k->i32 >> k2.i32;
684
        else
685
          k->u32 = k->u32 >> k2.u32;
686
        continue;
687
      }
688
      /* fallthrough */
689
    case 9:
690
      if (cp_opt(cp, '+')) {
691
        cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 + k2.u32;
692
      arith_result:
693
        if (k2.id > k->id) k->id = k2.id;  /* Trivial promotion to unsigned. */
694
        continue;
695
      } else if (cp_opt(cp, '-')) {
696
        cp_expr_sub(cp, &k2, 10); k->u32 = k->u32 - k2.u32; goto arith_result;
697
      }
698
      /* fallthrough */
699
    case 10:
700
      if (cp_opt(cp, '*')) {
701
        cp_expr_unary(cp, &k2); k->u32 = k->u32 * k2.u32; goto arith_result;
702
      } else if (cp_opt(cp, '/')) {
703
        cp_expr_unary(cp, &k2);
704
        if (k2.id > k->id) k->id = k2.id;  /* Trivial promotion to unsigned. */
705
        if (k2.u32 == 0 ||
706
            (k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1))
707
          cp_err(cp, LJ_ERR_BADVAL);
708
        if (k->id == CTID_INT32)
709
          k->i32 = k->i32 / k2.i32;
710
        else
711
          k->u32 = k->u32 / k2.u32;
712
        continue;
713
      } else if (cp_opt(cp, '%')) {
714
        cp_expr_unary(cp, &k2);
715
        if (k2.id > k->id) k->id = k2.id;  /* Trivial promotion to unsigned. */
716
        if (k2.u32 == 0 ||
717
            (k->id == CTID_INT32 && k->u32 == 0x80000000u && k2.i32 == -1))
718
          cp_err(cp, LJ_ERR_BADVAL);
719
        if (k->id == CTID_INT32)
720
          k->i32 = k->i32 % k2.i32;
721
        else
722
          k->u32 = k->u32 % k2.u32;
723
        continue;
724
      }
725
    default:
726
      return;
727
    }
728
  }
729
}
730

731
/* Parse and evaluate unary expression. */
732
static void cp_expr_unary(CPState *cp, CPValue *k)
120✔
733
{
734
  if (++cp->depth > CPARSE_MAX_DECLDEPTH) cp_err(cp, LJ_ERR_XLEVELS);
120✔
735
  cp_expr_prefix(cp, k);
120✔
736
  cp_expr_postfix(cp, k);
120✔
737
  cp->depth--;
120✔
738
}
120✔
739

740
/* Parse and evaluate sub-expression. */
741
static void cp_expr_sub(CPState *cp, CPValue *k, int pri)
119✔
742
{
743
  cp_expr_unary(cp, k);
×
744
  cp_expr_infix(cp, k, pri);
119✔
745
}
746

747
/* Parse constant integer expression. */
748
static void cp_expr_kint(CPState *cp, CPValue *k)
119✔
749
{
750
  CType *ct;
119✔
751
  cp_expr_sub(cp, k, 0);
119✔
752
  ct = ctype_raw(cp->cts, k->id);
119✔
753
  if (!ctype_isinteger(ct->info)) cp_err(cp, LJ_ERR_BADVAL);
119✔
754
}
119✔
755

756
/* Parse (non-negative) size expression. */
757
static CTSize cp_expr_ksize(CPState *cp)
118✔
758
{
759
  CPValue k;
118✔
760
  cp_expr_kint(cp, &k);
118✔
761
  if (k.u32 >= 0x80000000u) cp_err(cp, LJ_ERR_FFI_INVSIZE);
118✔
762
  return k.u32;
118✔
763
}
764

765
/* -- Type declaration stack management ----------------------------------- */
766

767
/* Add declaration element behind the insertion position. */
768
static CPDeclIdx cp_add(CPDecl *decl, CTInfo info, CTSize size)
442,769✔
769
{
770
  CPDeclIdx top = decl->top;
442,769✔
771
  if (top >= CPARSE_MAX_DECLSTACK) cp_err(decl->cp, LJ_ERR_XLEVELS);
291✔
772
  decl->stack[top].info = info;
442,769✔
773
  decl->stack[top].size = size;
442,769✔
774
  decl->stack[top].sib = 0;
442,769✔
775
  setgcrefnull(decl->stack[top].name);
442,769✔
776
  decl->stack[top].next = decl->stack[decl->pos].next;
442,769✔
777
  decl->stack[decl->pos].next = (CTypeID1)top;
442,769✔
778
  decl->top = top+1;
442,769✔
779
  return top;
442,769✔
780
}
781

782
/* Push declaration element before the insertion position. */
783
static CPDeclIdx cp_push(CPDecl *decl, CTInfo info, CTSize size)
442,446✔
784
{
785
  return (decl->pos = cp_add(decl, info, size));
442,446✔
786
}
787

788
/* Push or merge attributes. */
789
static void cp_push_attributes(CPDecl *decl)
442,079✔
790
{
791
  CType *ct = &decl->stack[decl->pos];
442,079✔
792
  if (ctype_isfunc(ct->info)) {  /* Ok to modify in-place. */
442,079✔
793
#if LJ_TARGET_X86
794
    if ((decl->fattr & CTFP_CCONV))
795
      ct->info = (ct->info & (CTMASK_NUM|CTF_VARARG|CTMASK_CID)) +
796
                 (decl->fattr & ~CTMASK_CID);
797
#endif
798
  } else {
799
    if ((decl->attr & CTFP_ALIGNED) && !(decl->mode & CPARSE_MODE_FIELD))
442,079✔
800
      cp_push(decl, CTINFO(CT_ATTRIB, CTATTRIB(CTA_ALIGN)),
×
801
              ctype_align(decl->attr));
×
802
  }
803
}
442,079✔
804

805
/* Push unrolled type to declaration stack and merge qualifiers. */
806
static void cp_push_type(CPDecl *decl, CTypeID id)
441,077✔
807
{
808
  CType *ct = ctype_get(decl->cp->cts, id);
441,077✔
809
  CTInfo info = ct->info;
441,077✔
810
  CTSize size = ct->size;
441,077✔
811
  switch (ctype_type(info)) {
441,077✔
812
  case CT_STRUCT: case CT_ENUM:
250✔
813
    cp_push(decl, CTINFO(CT_TYPEDEF, id), 0);  /* Don't copy unique types. */
250✔
814
    if ((decl->attr & CTF_QUAL)) {  /* Push unmerged qualifiers. */
250✔
815
      cp_push(decl, CTINFO(CT_ATTRIB, CTATTRIB(CTA_QUAL)),
1✔
816
              (decl->attr & CTF_QUAL));
817
      decl->attr &= ~CTF_QUAL;
1✔
818
    }
819
    break;
820
  case CT_ATTRIB:
×
821
    if (ctype_isxattrib(info, CTA_QUAL))
×
822
      decl->attr &= ~size;  /* Remove redundant qualifiers. */
×
823
    cp_push_type(decl, ctype_cid(info));  /* Unroll. */
×
824
    cp_push(decl, info & ~CTMASK_CID, size);  /* Copy type. */
×
825
    break;
×
826
  case CT_ARRAY:
20✔
827
    if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) {
20✔
828
      info |= (decl->attr & CTF_QUAL);
15✔
829
      decl->attr &= ~CTF_QUAL;
15✔
830
    }
831
    cp_push_type(decl, ctype_cid(info));  /* Unroll. */
20✔
832
    cp_push(decl, info & ~CTMASK_CID, size);  /* Copy type. */
20✔
833
    decl->stack[decl->pos].sib = 1;  /* Mark as already checked and sized. */
20✔
834
    /* Note: this is not copied to the ct->sib in the C type table. */
835
    break;
20✔
836
  case CT_FUNC:
837
    /* Copy type, link parameters (shared). */
838
    decl->stack[cp_push(decl, info, size)].sib = ct->sib;
×
839
    break;
×
840
  default:
440,807✔
841
    /* Copy type, merge common qualifiers. */
842
    cp_push(decl, info|(decl->attr & CTF_QUAL), size);
440,807✔
843
    decl->attr &= ~CTF_QUAL;
440,807✔
844
    break;
440,807✔
845
  }
846
}
441,077✔
847

848
/* Consume the declaration element chain and intern the C type. */
849
static CTypeID cp_decl_intern(CPState *cp, CPDecl *decl)
442,074✔
850
{
851
  CTypeID id = 0;
442,074✔
852
  CPDeclIdx idx = 0;
442,074✔
853
  CTSize csize = CTSIZE_INVALID;
442,074✔
854
  CTSize cinfo = 0;
442,074✔
855
  do {
442,875✔
856
    CType *ct = &decl->stack[idx];
442,875✔
857
    CTInfo info = ct->info;
442,875✔
858
    CTInfo size = ct->size;
442,875✔
859
    /* The cid is already part of info for copies of pointers/functions. */
860
    idx = ct->next;
442,875✔
861
    if (ctype_istypedef(info)) {
442,875✔
862
      lj_assertCP(id == 0, "typedef not at toplevel");
248✔
863
      id = ctype_cid(info);
248✔
864
      /* Always refetch info/size, since struct/enum may have been completed. */
865
      cinfo = ctype_get(cp->cts, id)->info;
248✔
866
      csize = ctype_get(cp->cts, id)->size;
248✔
867
      lj_assertCP(ctype_isstruct(cinfo) || ctype_isenum(cinfo),
248✔
868
                  "typedef of bad type");
869
    } else if (ctype_isfunc(info)) {  /* Intern function. */
442,627✔
870
      CType *fct;
32✔
871
      CTypeID fid;
32✔
872
      CTypeID sib;
32✔
873
      if (id) {
32✔
874
        CType *refct = ctype_raw(cp->cts, id);
32✔
875
        /* Reject function or refarray return types. */
876
        if (ctype_isfunc(refct->info) || ctype_isrefarray(refct->info))
32✔
877
          cp_err(cp, LJ_ERR_FFI_INVTYPE);
×
878
      }
879
      /* No intervening attributes allowed, skip forward. */
880
      while (idx) {
32✔
881
        CType *ctn = &decl->stack[idx];
2✔
882
        if (!ctype_isattrib(ctn->info)) break;
2✔
883
        idx = ctn->next;  /* Skip attribute. */
×
884
      }
885
      sib = ct->sib;  /* Next line may reallocate the C type table. */
32✔
886
      fid = lj_ctype_new(cp->cts, &fct);
32✔
887
      csize = CTSIZE_INVALID;
32✔
888
      fct->info = cinfo = info + id;
32✔
889
      fct->size = size;
32✔
890
      fct->sib = sib;
32✔
891
      id = fid;
32✔
892
    } else if (ctype_isattrib(info)) {
442,595✔
893
      if (ctype_isxattrib(info, CTA_QUAL))
1✔
894
        cinfo |= size;
1✔
895
      else if (ctype_isxattrib(info, CTA_ALIGN))
×
896
        CTF_INSERT(cinfo, ALIGN, size);
×
897
      id = lj_ctype_intern(cp->cts, info+id, size);
1✔
898
      /* Inherit csize/cinfo from original type. */
899
    } else {
900
      if (ctype_isnum(info)) {  /* Handle mode/vector-size attributes. */
442,594✔
901
        lj_assertCP(id == 0, "number not at toplevel");
441,648✔
902
        if (!(info & CTF_BOOL)) {
441,648✔
903
          CTSize msize = ctype_msizeP(decl->attr);
441,637✔
904
          CTSize vsize = ctype_vsizeP(decl->attr);
441,637✔
905
          if (msize && (!(info & CTF_FP) || (msize == 4 || msize == 8))) {
441,637✔
906
            CTSize malign = lj_fls(msize);
×
907
            if (malign > 4) malign = 4;  /* Limit alignment. */
×
908
            CTF_INSERT(info, ALIGN, malign);
×
909
            size = msize;  /* Override size via mode. */
×
910
          }
911
          if (vsize) {  /* Vector size set? */
441,637✔
912
            CTSize esize = lj_fls(size);
×
913
            if (vsize >= esize) {
×
914
              /* Intern the element type first. */
915
              id = lj_ctype_intern(cp->cts, info, size);
×
916
              /* Then create a vector (array) with vsize alignment. */
917
              size = (1u << vsize);
×
918
              if (vsize > 4) vsize = 4;  /* Limit alignment. */
×
919
              if (ctype_align(info) > vsize) vsize = ctype_align(info);
×
920
              info = CTINFO(CT_ARRAY, (info & CTF_QUAL) + CTF_VECTOR +
×
921
                                      CTALIGN(vsize));
922
            }
923
          }
924
        }
925
      } else if (ctype_isptr(info)) {
946✔
926
        /* Reject pointer/ref to ref. */
927
        if (id && ctype_isref(ctype_raw(cp->cts, id)->info))
912✔
928
          cp_err(cp, LJ_ERR_FFI_INVTYPE);
×
929
        if (ctype_isref(info)) {
456✔
930
          info &= ~CTF_VOLATILE;  /* Refs are always const, never volatile. */
×
931
          /* No intervening attributes allowed, skip forward. */
932
          while (idx) {
×
933
            CType *ctn = &decl->stack[idx];
×
934
            if (!ctype_isattrib(ctn->info)) break;
×
935
            idx = ctn->next;  /* Skip attribute. */
×
936
          }
937
        }
938
      } else if (ctype_isarray(info)) {  /* Check for valid array size etc. */
490✔
939
        if (ct->sib == 0) {  /* Only check/size arrays not copied by unroll. */
312✔
940
          if (ctype_isref(cinfo))  /* Reject arrays of refs. */
291✔
941
            cp_err(cp, LJ_ERR_FFI_INVTYPE);
×
942
          /* Reject VLS or unknown-sized types. */
943
          if (ctype_isvltype(cinfo) || csize == CTSIZE_INVALID)
291✔
944
            cp_err(cp, LJ_ERR_FFI_INVSIZE);
×
945
          /* a[] and a[?] keep their invalid size. */
946
          if (size != CTSIZE_INVALID) {
291✔
947
            uint64_t xsz = (uint64_t)size * csize;
118✔
948
            if (xsz >= 0x80000000u) cp_err(cp, LJ_ERR_FFI_INVSIZE);
118✔
949
            size = (CTSize)xsz;
118✔
950
          }
951
        }
952
        if ((cinfo & CTF_ALIGN) > (info & CTF_ALIGN))  /* Find max. align. */
312✔
953
          info = (info & ~CTF_ALIGN) | (cinfo & CTF_ALIGN);
63✔
954
        info |= (cinfo & CTF_QUAL);  /* Inherit qual. */
312✔
955
      } else {
956
        lj_assertCP(ctype_isvoid(info), "bad ctype %08x", info);
442,594✔
957
      }
958
      csize = size;
442,594✔
959
      cinfo = info+id;
442,594✔
960
      id = lj_ctype_intern(cp->cts, info+id, size);
442,594✔
961
    }
962
  } while (idx);
442,875✔
963
  return id;
442,074✔
964
}
965

966
/* -- C declaration parser ------------------------------------------------ */
967

968
/* Reset declaration state to declaration specifier. */
969
static void cp_decl_reset(CPDecl *decl)
107✔
970
{
971
  decl->pos = decl->specpos;
107✔
972
  decl->top = decl->specpos+1;
107✔
973
  decl->stack[decl->specpos].next = 0;
107✔
974
  decl->attr = decl->specattr;
107✔
975
  decl->fattr = decl->specfattr;
107✔
976
  decl->name = NULL;
107✔
977
  decl->redir = NULL;
107✔
978
}
107✔
979

980
/* Parse constant initializer. */
981
/* NYI: FP constants and strings as initializers. */
982
static CTypeID cp_decl_constinit(CPState *cp, CType **ctp, CTypeID ctypeid)
×
983
{
984
  CType *ctt = ctype_get(cp->cts, ctypeid);
×
985
  CTInfo info;
×
986
  CTSize size;
×
987
  CPValue k;
×
988
  CTypeID constid;
×
989
  while (ctype_isattrib(ctt->info)) {  /* Skip attributes. */
×
990
    ctypeid = ctype_cid(ctt->info);  /* Update ID, too. */
×
991
    ctt = ctype_get(cp->cts, ctypeid);
×
992
  }
993
  info = ctt->info;
×
994
  size = ctt->size;
×
995
  if (!ctype_isinteger(info) || !(info & CTF_CONST) || size > 4)
×
996
    cp_err(cp, LJ_ERR_FFI_INVTYPE);
×
997
  cp_check(cp, '=');
×
998
  cp_expr_sub(cp, &k, 0);
×
999
  constid = lj_ctype_new(cp->cts, ctp);
×
1000
  (*ctp)->info = CTINFO(CT_CONSTVAL, CTF_CONST|ctypeid);
×
1001
  k.u32 <<= 8*(4-size);
×
1002
  if ((info & CTF_UNSIGNED))
×
1003
    k.u32 >>= 8*(4-size);
×
1004
  else
1005
    k.u32 = (uint32_t)((int32_t)k.u32 >> 8*(4-size));
×
1006
  (*ctp)->size = k.u32;
×
1007
  return constid;
×
1008
}
1009

1010
/* Parse size in parentheses as part of attribute. */
1011
static CTSize cp_decl_sizeattr(CPState *cp)
×
1012
{
1013
  CTSize sz;
×
1014
  uint32_t oldtmask = cp->tmask;
×
1015
  cp->tmask = CPNS_DEFAULT;  /* Required for expression evaluator. */
×
1016
  cp_check(cp, '(');
×
1017
  sz = cp_expr_ksize(cp);
×
1018
  cp->tmask = oldtmask;
×
1019
  cp_check(cp, ')');
×
1020
  return sz;
×
1021
}
1022

1023
/* Parse alignment attribute. */
1024
static void cp_decl_align(CPState *cp, CPDecl *decl)
1025
{
1026
  CTSize al = 4;  /* Unspecified alignment is 16 bytes. */
1027
  if (cp->tok == '(') {
1028
    al = cp_decl_sizeattr(cp);
1029
    al = al ? lj_fls(al) : 0;
1030
  }
1031
  CTF_INSERT(decl->attr, ALIGN, al);
1032
  decl->attr |= CTFP_ALIGNED;
1033
}
1034

1035
/* Parse GCC asm("name") redirect. */
1036
static void cp_decl_asm(CPState *cp, CPDecl *decl)
1037
{
1038
  UNUSED(decl);
1039
  cp_next(cp);
1040
  cp_check(cp, '(');
1041
  if (cp->tok == CTOK_STRING) {
1042
    GCstr *str = cp->str;
1043
    while (cp_next(cp) == CTOK_STRING) {
1044
      lj_strfmt_pushf(cp->L, "%s%s", strdata(str), strdata(cp->str));
1045
      cp->L->top--;
1046
      str = strV(cp->L->top);
1047
    }
1048
    decl->redir = str;
1049
  }
1050
  cp_check(cp, ')');
1051
}
1052

1053
/* Parse GCC __attribute__((mode(...))). */
1054
static void cp_decl_mode(CPState *cp, CPDecl *decl)
1055
{
1056
  cp_check(cp, '(');
1057
  if (cp->tok == CTOK_IDENT) {
1058
    const char *s = strdata(cp->str);
1059
    CTSize sz = 0, vlen = 0;
1060
    if (s[0] == '_' && s[1] == '_') s += 2;
1061
    if (*s == 'V') {
1062
      s++;
1063
      vlen = *s++ - '0';
1064
      if (*s >= '0' && *s <= '9')
1065
        vlen = vlen*10 + (*s++ - '0');
1066
    }
1067
    switch (*s++) {
1068
    case 'Q': sz = 1; break;
1069
    case 'H': sz = 2; break;
1070
    case 'S': sz = 4; break;
1071
    case 'D': sz = 8; break;
1072
    case 'T': sz = 16; break;
1073
    case 'O': sz = 32; break;
1074
    default: goto bad_size;
1075
    }
1076
    if (*s == 'I' || *s == 'F') {
1077
      CTF_INSERT(decl->attr, MSIZEP, sz);
1078
      if (vlen) CTF_INSERT(decl->attr, VSIZEP, lj_fls(vlen*sz));
1079
    }
1080
  bad_size:
1081
    cp_next(cp);
1082
  }
1083
  cp_check(cp, ')');
1084
}
1085

1086
/* Parse GCC __attribute__((...)). */
1087
static void cp_decl_gccattribute(CPState *cp, CPDecl *decl)
×
1088
{
1089
  cp_next(cp);
×
1090
  cp_check(cp, '(');
×
1091
  cp_check(cp, '(');
×
1092
  while (cp->tok != ')') {
×
1093
    if (cp->tok == CTOK_IDENT) {
×
1094
      GCstr *attrstr = cp->str;
×
1095
#if LUAJIT_SMART_STRINGS
1096
      /*
1097
       * Sadly, several option __name__-s exceed 12 bytes hence they
1098
       * could've been interned using the full hash.  Strip "__" to stay
1099
       * within limits.
1100
       */
1101
      const char *c = strdata(cp->str);
×
1102
      if (attrstr->len > 12 && c[0]=='_' && c[1]=='_' && c[2] != '_' &&
×
1103
          c[attrstr->len-2]=='_' && c[attrstr->len-1]=='_')
×
1104
        attrstr = lj_str_new(cp->L, c+2, attrstr->len-4);
×
1105
#endif
1106
      cp_next(cp);
×
1107
      switch (lj_cparse_case(attrstr,
×
1108
                "\007aligned" "\013__aligned__"
1109
                "\006packed" "\012__packed__"
1110
                "\004mode" "\010__mode__"
1111
                "\013vector_size" "\017__vector_size__"
1112
#if LJ_TARGET_X86
1113
                "\007regparm" "\013__regparm__"
1114
                "\005cdecl"  "\011__cdecl__"
1115
                "\010thiscall" "\014__thiscall__"
1116
                "\010fastcall" "\014__fastcall__"
1117
                "\007stdcall" "\013__stdcall__"
1118
                "\012sseregparm" "\016__sseregparm__"
1119
#endif
1120
              )) {
1121
      case 0: case 1: /* aligned */
×
1122
        cp_decl_align(cp, decl);
×
1123
        break;
×
1124
      case 2: case 3: /* packed */
×
1125
        decl->attr |= CTFP_PACKED;
×
1126
        break;
×
1127
      case 4: case 5: /* mode */
×
1128
        cp_decl_mode(cp, decl);
×
1129
        break;
×
1130
      case 6: case 7: /* vector_size */
×
1131
        {
1132
          CTSize vsize = cp_decl_sizeattr(cp);
×
1133
          if (vsize) CTF_INSERT(decl->attr, VSIZEP, lj_fls(vsize));
×
1134
        }
1135
        break;
1136
#if LJ_TARGET_X86
1137
      case 8: case 9: /* regparm */
1138
        CTF_INSERT(decl->fattr, REGPARM, cp_decl_sizeattr(cp));
1139
        decl->fattr |= CTFP_CCONV;
1140
        break;
1141
      case 10: case 11: /* cdecl */
1142
        CTF_INSERT(decl->fattr, CCONV, CTCC_CDECL);
1143
        decl->fattr |= CTFP_CCONV;
1144
        break;
1145
      case 12: case 13: /* thiscall */
1146
        CTF_INSERT(decl->fattr, CCONV, CTCC_THISCALL);
1147
        decl->fattr |= CTFP_CCONV;
1148
        break;
1149
      case 14: case 15: /* fastcall */
1150
        CTF_INSERT(decl->fattr, CCONV, CTCC_FASTCALL);
1151
        decl->fattr |= CTFP_CCONV;
1152
        break;
1153
      case 16: case 17: /* stdcall */
1154
        CTF_INSERT(decl->fattr, CCONV, CTCC_STDCALL);
1155
        decl->fattr |= CTFP_CCONV;
1156
        break;
1157
      case 18: case 19: /* sseregparm */
1158
        decl->fattr |= CTF_SSEREGPARM;
1159
        decl->fattr |= CTFP_CCONV;
1160
        break;
1161
#endif
1162
      default:  /* Skip all other attributes. */
×
1163
        goto skip_attr;
×
1164
      }
1165
    } else if (cp->tok >= CTOK_FIRSTDECL) {  /* For __attribute((const)) etc. */
×
1166
      cp_next(cp);
×
1167
    skip_attr:
×
1168
      if (cp_opt(cp, '(')) {
×
1169
        while (cp->tok != ')' && cp->tok != CTOK_EOF) cp_next(cp);
×
1170
        cp_check(cp, ')');
×
1171
      }
1172
    } else {
1173
      break;
1174
    }
1175
    if (!cp_opt(cp, ',')) break;
×
1176
  }
1177
  cp_check(cp, ')');
×
1178
  cp_check(cp, ')');
×
1179
}
×
1180

1181
/* Parse MSVC __declspec(...). */
1182
static void cp_decl_msvcattribute(CPState *cp, CPDecl *decl)
×
1183
{
1184
  cp_next(cp);
×
1185
  cp_check(cp, '(');
×
1186
  while (cp->tok == CTOK_IDENT) {
×
1187
    GCstr *attrstr = cp->str;
×
1188
    cp_next(cp);
×
1189
    if (cp_str_is(attrstr, "align")) {
×
1190
      cp_decl_align(cp, decl);
×
1191
    } else {  /* Ignore all other attributes. */
1192
      if (cp_opt(cp, '(')) {
×
1193
        while (cp->tok != ')' && cp->tok != CTOK_EOF) cp_next(cp);
×
1194
        cp_check(cp, ')');
×
1195
      }
1196
    }
1197
  }
1198
  cp_check(cp, ')');
×
1199
}
×
1200

1201
/* Parse declaration attributes (and common qualifiers). */
1202
static void cp_decl_attributes(CPState *cp, CPDecl *decl)
1,326,943✔
1203
{
1204
  for (;;) {
1,327,031✔
1205
    switch (cp->tok) {
1,327,031✔
1206
    case CTOK_CONST: decl->attr |= CTF_CONST; break;
84✔
1207
    case CTOK_VOLATILE: decl->attr |= CTF_VOLATILE; break;
1✔
1208
    case CTOK_RESTRICT: break;  /* Ignore. */
1209
    case CTOK_EXTENSION: break;  /* Ignore. */
1210
    case CTOK_ATTRIBUTE: cp_decl_gccattribute(cp, decl); continue;
×
1211
    case CTOK_ASM: cp_decl_asm(cp, decl); continue;
3✔
1212
    case CTOK_DECLSPEC: cp_decl_msvcattribute(cp, decl); continue;
×
1213
    case CTOK_CCDECL:
1214
#if LJ_TARGET_X86
1215
      CTF_INSERT(decl->fattr, CCONV, cp->ct->size);
1216
      decl->fattr |= CTFP_CCONV;
1217
#endif
1218
      break;
1219
    case CTOK_PTRSZ:
×
1220
#if LJ_64
1221
      CTF_INSERT(decl->attr, MSIZEP, cp->ct->size);
×
1222
#endif
1223
      break;
×
1224
    default: return;
1,326,943✔
1225
    }
1226
    cp_next(cp);
85✔
1227
  }
1228
}
1229

1230
/* Parse struct/union/enum name. */
1231
static CTypeID cp_struct_name(CPState *cp, CPDecl *sdecl, CTInfo info)
79✔
1232
{
1233
  CTypeID sid;
79✔
1234
  CType *ct;
79✔
1235
  cp->tmask = CPNS_STRUCT;
79✔
1236
  cp_next(cp);
79✔
1237
  cp_decl_attributes(cp, sdecl);
79✔
1238
  cp->tmask = CPNS_DEFAULT;
79✔
1239
  if (cp->tok != '{') {
79✔
1240
    if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT);
27✔
1241
    if (cp->val.id) {  /* Name of existing struct/union/enum. */
27✔
1242
      sid = cp->val.id;
15✔
1243
      ct = cp->ct;
15✔
1244
      if ((ct->info ^ info) & (CTMASK_NUM|CTF_UNION))  /* Wrong type. */
15✔
1245
        cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(gco2str(gcref(ct->name))));
×
1246
    } else {  /* Create named, incomplete struct/union/enum. */
1247
      if ((cp->mode & CPARSE_MODE_NOIMPLICIT))
12✔
1248
        cp_errmsg(cp, 0, LJ_ERR_FFI_BADTAG, strdata(cp->str));
×
1249
      sid = lj_ctype_new(cp->cts, &ct);
12✔
1250
      ct->info = info;
12✔
1251
      ct->size = CTSIZE_INVALID;
12✔
1252
      ctype_setname(ct, cp->str);
12✔
1253
      lj_ctype_addname(cp->cts, ct, sid);
12✔
1254
    }
1255
    cp_next(cp);
27✔
1256
  } else {  /* Create anonymous, incomplete struct/union/enum. */
1257
    sid = lj_ctype_new(cp->cts, &ct);
52✔
1258
    ct->info = info;
52✔
1259
    ct->size = CTSIZE_INVALID;
52✔
1260
  }
1261
  if (cp->tok == '{') {
79✔
1262
    if (ct->size != CTSIZE_INVALID || ct->sib)
57✔
1263
      cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(gco2str(gcref(ct->name))));
×
1264
    ct->sib = 1;  /* Indicate the type is currently being defined. */
57✔
1265
  }
1266
  return sid;
79✔
1267
}
1268

1269
/* Determine field alignment. */
1270
static CTSize cp_field_align(CPState *cp, CType *ct, CTInfo info)
246✔
1271
{
1272
  CTSize align = ctype_align(info);
246✔
1273
  UNUSED(cp); UNUSED(ct);
246✔
1274
#if (LJ_TARGET_X86 && !LJ_ABI_WIN) || (LJ_TARGET_ARM && __APPLE__)
1275
  /* The SYSV i386 and iOS ABIs limit alignment of non-vector fields to 2^2. */
1276
  if (align > 2 && !(info & CTFP_ALIGNED)) {
1277
    if (ctype_isarray(info) && !(info & CTF_VECTOR)) {
1278
      do {
1279
        ct = ctype_rawchild(cp->cts, ct);
1280
        info = ct->info;
1281
      } while (ctype_isarray(info) && !(info & CTF_VECTOR));
1282
    }
1283
    if (ctype_isnum(info) || ctype_isenum(info))
1284
      align = 2;
1285
  }
1286
#endif
1287
  return align;
246✔
1288
}
1289

1290
/* Layout struct/union fields. */
1291
static void cp_struct_layout(CPState *cp, CTypeID sid, CTInfo sattr)
55✔
1292
{
1293
  CTSize bofs = 0, bmaxofs = 0;  /* Bit offset and max. bit offset. */
55✔
1294
  CTSize maxalign = ctype_align(sattr);
55✔
1295
  CType *sct = ctype_get(cp->cts, sid);
55✔
1296
  CTInfo sinfo = sct->info;
55✔
1297
  CTypeID fieldid = sct->sib;
55✔
1298
  while (fieldid) {
301✔
1299
    CType *ct = ctype_get(cp->cts, fieldid);
246✔
1300
    CTInfo attr = ct->size;  /* Field declaration attributes (temp.). */
246✔
1301

1302
    if (ctype_isfield(ct->info) ||
246✔
1303
        (ctype_isxattrib(ct->info, CTA_SUBTYPE) && attr)) {
1✔
1304
      CTSize align, amask;  /* Alignment (pow2) and alignment mask (bits). */
246✔
1305
      CTSize sz;
246✔
1306
      CTInfo info = lj_ctype_info(cp->cts, ctype_cid(ct->info), &sz);
246✔
1307
      CTSize bsz, csz = 8*sz;  /* Field size and container size (in bits). */
246✔
1308
      sinfo |= (info & (CTF_QUAL|CTF_VLA));  /* Merge pseudo-qualifiers. */
246✔
1309

1310
      /* Check for size overflow and determine alignment. */
1311
      if (sz >= 0x20000000u || bofs + csz < bofs || (info & CTF_VLA)) {
246✔
1312
        if (!(sz == CTSIZE_INVALID && ctype_isarray(info) &&
×
1313
              !(sinfo & CTF_UNION)))
×
1314
          cp_err(cp, LJ_ERR_FFI_INVSIZE);
×
1315
        csz = sz = 0;  /* Treat a[] and a[?] as zero-sized. */
×
1316
      }
1317
      align = cp_field_align(cp, ct, info);
246✔
1318
      if (((attr|sattr) & CTFP_PACKED) ||
246✔
1319
          ((attr & CTFP_ALIGNED) && ctype_align(attr) > align))
246✔
1320
        align = ctype_align(attr);
×
1321
      if (cp->packstack[cp->curpack] < align)
246✔
1322
        align = cp->packstack[cp->curpack];
1323
      if (align > maxalign) maxalign = align;
246✔
1324
      amask = (8u << align) - 1;
246✔
1325

1326
      bsz = ctype_bitcsz(ct->info);  /* Bitfield size (temp.). */
246✔
1327
      if (bsz == CTBSZ_FIELD || !ctype_isfield(ct->info)) {
246✔
1328
        bsz = csz;  /* Regular fields or subtypes always fill the container. */
246✔
1329
        bofs = (bofs + amask) & ~amask;  /* Start new aligned field. */
246✔
1330
        ct->size = (bofs >> 3);  /* Store field offset. */
246✔
1331
      } else {  /* Bitfield. */
1332
        if (bsz == 0 || (attr & CTFP_ALIGNED) ||
×
1333
            (!((attr|sattr) & CTFP_PACKED) && (bofs & amask) + bsz > csz))
×
1334
          bofs = (bofs + amask) & ~amask;  /* Start new aligned field. */
×
1335

1336
        /* Prefer regular field over bitfield. */
1337
        if (bsz == csz && (bofs & amask) == 0) {
×
1338
          ct->info = CTINFO(CT_FIELD, ctype_cid(ct->info));
×
1339
          ct->size = (bofs >> 3);  /* Store field offset. */
×
1340
        } else {
1341
          ct->info = CTINFO(CT_BITFIELD,
×
1342
            (info & (CTF_QUAL|CTF_UNSIGNED|CTF_BOOL)) +
1343
            (csz << (CTSHIFT_BITCSZ-3)) + (bsz << CTSHIFT_BITBSZ));
1344
#if LJ_BE
1345
          ct->info += ((csz - (bofs & (csz-1)) - bsz) << CTSHIFT_BITPOS);
1346
#else
1347
          ct->info += ((bofs & (csz-1)) << CTSHIFT_BITPOS);
×
1348
#endif
1349
          ct->size = ((bofs & ~(csz-1)) >> 3);  /* Store container offset. */
×
1350
        }
1351
      }
1352

1353
      /* Determine next offset or max. offset. */
1354
      if ((sinfo & CTF_UNION)) {
246✔
1355
        if (bsz > bmaxofs) bmaxofs = bsz;
25✔
1356
      } else {
1357
        bofs += bsz;
221✔
1358
      }
1359
    }  /* All other fields in the chain are already set up. */
1360

1361
    fieldid = ct->sib;
246✔
1362
  }
1363

1364
  /* Complete struct/union. */
1365
  sct->info = sinfo + CTALIGN(maxalign);
55✔
1366
  bofs = (sinfo & CTF_UNION) ? bmaxofs : bofs;
55✔
1367
  maxalign = (8u << maxalign) - 1;
55✔
1368
  sct->size = (((bofs + maxalign) & ~maxalign) >> 3);
55✔
1369
}
55✔
1370

1371
/* Parse struct/union declaration. */
1372
static CTypeID cp_decl_struct(CPState *cp, CPDecl *sdecl, CTInfo sinfo)
77✔
1373
{
1374
  CTypeID sid = cp_struct_name(cp, sdecl, sinfo);
77✔
1375
  if (cp_opt(cp, '{')) {  /* Struct/union definition. */
77✔
1376
    CTypeID lastid = sid;
1377
    int lastdecl = 0;
1378
    while (cp->tok != '}') {
194✔
1379
      CPDecl decl;
139✔
1380
      CPscl scl = cp_decl_spec(cp, &decl, CDF_STATIC);
139✔
1381
      decl.mode = scl ? CPARSE_MODE_DIRECT :
278✔
1382
        CPARSE_MODE_DIRECT|CPARSE_MODE_ABSTRACT|CPARSE_MODE_FIELD;
1383

1384
      for (;;) {
246✔
1385
        CTypeID ctypeid;
246✔
1386

1387
        if (lastdecl) cp_err_token(cp, '}');
×
1388

1389
        /* Parse field declarator. */
1390
        decl.bits = CTSIZE_INVALID;
246✔
1391
        cp_declarator(cp, &decl);
246✔
1392
        ctypeid = cp_decl_intern(cp, &decl);
246✔
1393

1394
        if ((scl & CDF_STATIC)) {  /* Static constant in struct namespace. */
246✔
1395
          CType *ct;
×
1396
          CTypeID fieldid = cp_decl_constinit(cp, &ct, ctypeid);
×
1397
          ctype_get(cp->cts, lastid)->sib = fieldid;
×
1398
          lastid = fieldid;
×
1399
          ctype_setname(ct, decl.name);
×
1400
        } else {
1401
          CTSize bsz = CTBSZ_FIELD;  /* Temp. for layout phase. */
246✔
1402
          CType *ct;
246✔
1403
          CTypeID fieldid = lj_ctype_new(cp->cts, &ct);  /* Do this first. */
246✔
1404
          CType *tct = ctype_raw(cp->cts, ctypeid);
246✔
1405

1406
          if (decl.bits == CTSIZE_INVALID) {  /* Regular field. */
246✔
1407
            if (ctype_isarray(tct->info) && tct->size == CTSIZE_INVALID)
246✔
1408
              lastdecl = 1;  /* a[] or a[?] must be the last declared field. */
×
1409

1410
            /* Accept transparent struct/union/enum. */
1411
            if (!decl.name) {
246✔
1412
              if (!((ctype_isstruct(tct->info) && !(tct->info & CTF_VLA)) ||
1✔
1413
                    ctype_isenum(tct->info)))
1414
                cp_err_token(cp, CTOK_IDENT);
×
1415
              ct->info = CTINFO(CT_ATTRIB, CTATTRIB(CTA_SUBTYPE) + ctypeid);
1✔
1416
              ct->size = ctype_isstruct(tct->info) ?
2✔
1417
                         (decl.attr|0x80000000u) : 0;  /* For layout phase. */
1✔
1418
              goto add_field;
1✔
1419
            }
1420
          } else {  /* Bitfield. */
1421
            bsz = decl.bits;
×
1422
            if (!ctype_isinteger_or_bool(tct->info) ||
×
1423
                (bsz == 0 && decl.name) || 8*tct->size > CTBSZ_MAX ||
×
1424
                bsz > ((tct->info & CTF_BOOL) ? 1 : 8*tct->size))
×
1425
              cp_errmsg(cp, ':', LJ_ERR_BADVAL);
×
1426
          }
1427

1428
          /* Create temporary field for layout phase. */
1429
          ct->info = CTINFO(CT_FIELD, ctypeid + (bsz << CTSHIFT_BITCSZ));
245✔
1430
          ct->size = decl.attr;
245✔
1431
          if (decl.name) ctype_setname(ct, decl.name);
245✔
1432

1433
        add_field:
×
1434
          ctype_get(cp->cts, lastid)->sib = fieldid;
246✔
1435
          lastid = fieldid;
246✔
1436
        }
1437
        if (!cp_opt(cp, ',')) break;
246✔
1438
        cp_decl_reset(&decl);
246✔
1439
      }
1440
      cp_check(cp, ';');
139✔
1441
    }
1442
    cp_check(cp, '}');
55✔
1443
    ctype_get(cp->cts, lastid)->sib = 0;  /* Drop sib = 1 for empty structs. */
55✔
1444
    cp_decl_attributes(cp, sdecl);  /* Layout phase needs postfix attributes. */
55✔
1445
    cp_struct_layout(cp, sid, sdecl->attr);
55✔
1446
  }
1447
  return sid;
77✔
1448
}
1449

1450
/* Parse enum declaration. */
1451
static CTypeID cp_decl_enum(CPState *cp, CPDecl *sdecl)
2✔
1452
{
1453
  CTypeID eid = cp_struct_name(cp, sdecl, CTINFO(CT_ENUM, CTID_VOID));
2✔
1454
  CTInfo einfo = CTINFO(CT_ENUM, CTALIGN(2) + CTID_UINT32);
2✔
1455
  CTSize esize = 4;  /* Only 32 bit enums are supported. */
2✔
1456
  if (cp_opt(cp, '{')) {  /* Enum definition. */
2✔
1457
    CPValue k;
2✔
1458
    CTypeID lastid = eid;
2✔
1459
    k.u32 = 0;
2✔
1460
    k.id = CTID_INT32;
2✔
1461
    do {
2✔
1462
      GCstr *name = cp->str;
2✔
1463
      if (cp->tok != CTOK_IDENT) cp_err_token(cp, CTOK_IDENT);
2✔
1464
      if (cp->val.id) cp_errmsg(cp, 0, LJ_ERR_FFI_REDEF, strdata(name));
2✔
1465
      cp_next(cp);
2✔
1466
      if (cp_opt(cp, '=')) {
2✔
1467
        cp_expr_kint(cp, &k);
1✔
1468
        if (k.id == CTID_UINT32) {
1✔
1469
          /* C99 says that enum constants are always (signed) integers.
1470
          ** But since unsigned constants like 0x80000000 are quite common,
1471
          ** those are left as uint32_t.
1472
          */
1473
          if (k.i32 >= 0) k.id = CTID_INT32;
×
1474
        } else {
1475
          /* OTOH it's common practice and even mandated by some ABIs
1476
          ** that the enum type itself is unsigned, unless there are any
1477
          ** negative constants.
1478
          */
1479
          k.id = CTID_INT32;
1✔
1480
          if (k.i32 < 0) einfo = CTINFO(CT_ENUM, CTALIGN(2) + CTID_INT32);
1✔
1481
        }
1482
      }
1483
      /* Add named enum constant. */
1484
      {
1485
        CType *ct;
2✔
1486
        CTypeID constid = lj_ctype_new(cp->cts, &ct);
2✔
1487
        ctype_get(cp->cts, lastid)->sib = constid;
2✔
1488
        lastid = constid;
2✔
1489
        ctype_setname(ct, name);
2✔
1490
        ct->info = CTINFO(CT_CONSTVAL, CTF_CONST|k.id);
2✔
1491
        ct->size = k.u32++;
2✔
1492
        if (k.u32 == 0x80000000u) k.id = CTID_UINT32;
2✔
1493
        lj_ctype_addname(cp->cts, ct, constid);
2✔
1494
      }
1495
      if (!cp_opt(cp, ',')) break;
2✔
1496
    } while (cp->tok != '}');  /* Trailing ',' is ok. */
×
1497
    cp_check(cp, '}');
2✔
1498
    /* Complete enum. */
1499
    ctype_get(cp->cts, eid)->info = einfo;
2✔
1500
    ctype_get(cp->cts, eid)->size = esize;
2✔
1501
  }
1502
  return eid;
2✔
1503
}
1504

1505
/* Parse declaration specifiers. */
1506
static CPscl cp_decl_spec(CPState *cp, CPDecl *decl, CPscl scl)
441,969✔
1507
{
1508
  uint32_t cds = 0, sz = 0;
441,969✔
1509
  CTypeID tdef = 0;
441,969✔
1510

1511
  decl->cp = cp;
441,969✔
1512
  decl->mode = cp->mode;
441,969✔
1513
  decl->name = NULL;
441,969✔
1514
  decl->redir = NULL;
441,969✔
1515
  decl->attr = 0;
441,969✔
1516
  decl->fattr = 0;
441,969✔
1517
  decl->pos = decl->top = 0;
441,969✔
1518
  decl->stack[0].next = 0;
441,969✔
1519

1520
  for (;;) {  /* Parse basic types. */
883,977✔
1521
    cp_decl_attributes(cp, decl);
883,977✔
1522
    if (cp->tok >= CTOK_FIRSTDECL && cp->tok <= CTOK_LASTDECLFLAG) {
883,977✔
1523
      uint32_t cbit;
966✔
1524
      if (cp->ct->size) {
966✔
1525
        if (sz) goto end_decl;
914✔
1526
        sz = cp->ct->size;
1527
      }
1528
      cbit = (1u << (cp->tok - CTOK_FIRSTDECL));
966✔
1529
      cds = cds | cbit | ((cbit & cds & CDF_LONG) << 1);
966✔
1530
      if (cp->tok >= CTOK_FIRSTSCL) {
966✔
1531
        if (!(scl & cbit)) cp_errmsg(cp, cp->tok, LJ_ERR_FFI_BADSCL);
32✔
1532
      } else if (tdef) {
934✔
1533
        goto end_decl;
×
1534
      }
1535
      cp_next(cp);
966✔
1536
      continue;
966✔
1537
    }
1538
    if (sz || tdef ||
883,011✔
1539
        (cds & (CDF_SHORT|CDF_LONG|CDF_SIGNED|CDF_UNSIGNED|CDF_COMPLEX)))
441,055✔
1540
      break;
1541
    switch (cp->tok) {
441,042✔
1542
    case CTOK_STRUCT:
71✔
1543
      tdef = cp_decl_struct(cp, decl, CTINFO(CT_STRUCT, 0));
71✔
1544
      continue;
71✔
1545
    case CTOK_UNION:
6✔
1546
      tdef = cp_decl_struct(cp, decl, CTINFO(CT_STRUCT, CTF_UNION));
6✔
1547
      continue;
6✔
1548
    case CTOK_ENUM:
2✔
1549
      tdef = cp_decl_enum(cp, decl);
2✔
1550
      continue;
2✔
1551
    case CTOK_IDENT:
440,961✔
1552
      if (ctype_istypedef(cp->ct->info)) {
440,961✔
1553
        tdef = ctype_cid(cp->ct->info);  /* Get typedef. */
440,961✔
1554
        cp_next(cp);
440,961✔
1555
        continue;
440,961✔
1556
      }
1557
      break;
1558
    case '$':
2✔
1559
      tdef = cp->val.id;
2✔
1560
      cp_next(cp);
2✔
1561
      continue;
2✔
1562
    default:
1563
      break;
1564
    }
1565
    break;
1566
  }
1567
end_decl:
441,969✔
1568

1569
  if ((cds & CDF_COMPLEX))  /* Use predefined complex types. */
441,969✔
1570
    tdef = sz == 4 ? CTID_COMPLEX_FLOAT : CTID_COMPLEX_DOUBLE;
15✔
1571

1572
  if (tdef) {
441,965✔
1573
    cp_push_type(decl, tdef);
441,057✔
1574
  } else if ((cds & CDF_VOID)) {
912✔
1575
    cp_push(decl, CTINFO(CT_VOID, (decl->attr & CTF_QUAL)), CTSIZE_INVALID);
178✔
1576
    decl->attr &= ~CTF_QUAL;
178✔
1577
  } else {
1578
    /* Determine type info and size. */
1579
    CTInfo info = CTINFO(CT_NUM, (cds & CDF_UNSIGNED) ? CTF_UNSIGNED : 0);
734✔
1580
    if ((cds & CDF_BOOL)) {
734✔
1581
      if ((cds & ~(CDF_SCL|CDF_BOOL|CDF_INT|CDF_SIGNED|CDF_UNSIGNED)))
11✔
1582
        cp_errmsg(cp, 0, LJ_ERR_FFI_INVTYPE);
×
1583
      info |= CTF_BOOL;
11✔
1584
      if (!(cds & CDF_SIGNED)) info |= CTF_UNSIGNED;
11✔
1585
      if (!sz) {
11✔
1586
        sz = 1;
1587
      }
1588
    } else if ((cds & CDF_FP)) {
723✔
1589
      info = CTINFO(CT_NUM, CTF_FP);
21✔
1590
      if ((cds & CDF_LONG)) sz = sizeof(long double);
21✔
1591
    } else if ((cds & CDF_CHAR)) {
702✔
1592
      if ((cds & (CDF_CHAR|CDF_SIGNED|CDF_UNSIGNED)) == CDF_CHAR)
1593
        info |= CTF_UCHAR;  /* Handle platforms where char is unsigned. */
1594
    } else if ((cds & CDF_SHORT)) {
431✔
1595
      sz = sizeof(short);
1596
    } else if ((cds & CDF_LONGLONG)) {
431✔
1597
      sz = 8;
1598
    } else if ((cds & CDF_LONG)) {
429✔
1599
      info |= CTF_LONG;
×
1600
      sz = sizeof(long);
×
1601
    } else if (!sz) {
429✔
1602
      if (!(cds & (CDF_SIGNED|CDF_UNSIGNED)))
×
1603
        cp_errmsg(cp, cp->tok, LJ_ERR_FFI_DECLSPEC);
×
1604
      sz = sizeof(int);
1605
    }
1606
    lj_assertCP(sz != 0, "basic ctype with zero size");
734✔
1607
    info += CTALIGN(lj_fls(sz));  /* Use natural alignment. */
734✔
1608
    info += (decl->attr & CTF_QUAL);  /* Merge qualifiers. */
734✔
1609
    cp_push(decl, info, sz);
734✔
1610
    decl->attr &= ~CTF_QUAL;
734✔
1611
  }
1612
  decl->specpos = decl->pos;
441,969✔
1613
  decl->specattr = decl->attr;
441,969✔
1614
  decl->specfattr = decl->fattr;
441,969✔
1615
  return (cds & CDF_SCL);  /* Return storage class. */
441,969✔
1616
}
1617

1618
/* Parse array declaration. */
1619
static void cp_decl_array(CPState *cp, CPDecl *decl)
291✔
1620
{
1621
  CTInfo info = CTINFO(CT_ARRAY, 0);
291✔
1622
  CTSize nelem = CTSIZE_INVALID;  /* Default size for a[] or a[?]. */
291✔
1623
  cp_decl_attributes(cp, decl);
291✔
1624
  if (cp_opt(cp, '?'))
291✔
1625
    info |= CTF_VLA;  /* Create variable-length array a[?]. */
1626
  else if (cp->tok != ']')
119✔
1627
    nelem = cp_expr_ksize(cp);
118✔
1628
  cp_check(cp, ']');
291✔
1629
  cp_add(decl, info, nelem);
291✔
1630
}
291✔
1631

1632
/* Parse function declaration. */
1633
static void cp_decl_func(CPState *cp, CPDecl *fdecl)
32✔
1634
{
1635
  CTSize nargs = 0;
32✔
1636
  CTInfo info = CTINFO(CT_FUNC, 0);
32✔
1637
  CTypeID lastid = 0, anchor = 0;
32✔
1638
  if (cp->tok != ')') {
32✔
1639
    do {
80✔
1640
      CPDecl decl;
80✔
1641
      CTypeID ctypeid, fieldid;
80✔
1642
      CType *ct;
80✔
1643
      if (cp_opt(cp, '.')) {  /* Vararg function. */
80✔
1644
        cp_check(cp, '.');  /* Workaround for the minimalistic lexer. */
1✔
1645
        cp_check(cp, '.');
1✔
1646
        info |= CTF_VARARG;
1✔
1647
        break;
4✔
1648
      }
1649
      cp_decl_spec(cp, &decl, CDF_REGISTER);
79✔
1650
      decl.mode = CPARSE_MODE_DIRECT|CPARSE_MODE_ABSTRACT;
79✔
1651
      cp_declarator(cp, &decl);
79✔
1652
      ctypeid = cp_decl_intern(cp, &decl);
79✔
1653
      ct = ctype_raw(cp->cts, ctypeid);
79✔
1654
      if (ctype_isvoid(ct->info))
79✔
1655
        break;
1656
      else if (ctype_isrefarray(ct->info))
77✔
1657
        ctypeid = lj_ctype_intern(cp->cts,
×
1658
          CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ct->info)), CTSIZE_PTR);
×
1659
      else if (ctype_isfunc(ct->info))
77✔
1660
        ctypeid = lj_ctype_intern(cp->cts,
×
1661
          CTINFO(CT_PTR, CTALIGN_PTR|ctypeid), CTSIZE_PTR);
×
1662
      /* Add new parameter. */
1663
      fieldid = lj_ctype_new(cp->cts, &ct);
77✔
1664
      if (anchor)
77✔
1665
        ctype_get(cp->cts, lastid)->sib = fieldid;
47✔
1666
      else
1667
        anchor = fieldid;
1668
      lastid = fieldid;
77✔
1669
      if (decl.name) ctype_setname(ct, decl.name);
77✔
1670
      ct->info = CTINFO(CT_FIELD, ctypeid);
77✔
1671
      ct->size = nargs++;
77✔
1672
    } while (cp_opt(cp, ','));
77✔
1673
  }
1674
  cp_check(cp, ')');
32✔
1675
  if (cp_opt(cp, '{')) {  /* Skip function definition. */
32✔
1676
    int level = 1;
×
1677
    cp->mode |= CPARSE_MODE_SKIP;
×
1678
    for (;;) {
×
1679
      if (cp->tok == '{') level++;
×
1680
      else if (cp->tok == '}' && --level == 0) break;
×
1681
      else if (cp->tok == CTOK_EOF) cp_err_token(cp, '}');
×
1682
      cp_next(cp);
×
1683
    }
1684
    cp->mode &= ~CPARSE_MODE_SKIP;
×
1685
    cp->tok = ';';  /* Ok for cp_decl_multi(), error in cp_decl_single(). */
×
1686
  }
1687
  info |= (fdecl->fattr & ~CTMASK_CID);
32✔
1688
  fdecl->fattr = 0;
32✔
1689
  fdecl->stack[cp_add(fdecl, info, nargs)].sib = anchor;
32✔
1690
}
32✔
1691

1692
/* Parse declarator. */
1693
static void cp_declarator(CPState *cp, CPDecl *decl)
442,079✔
1694
{
1695
  if (++cp->depth > CPARSE_MAX_DECLDEPTH) cp_err(cp, LJ_ERR_XLEVELS);
442,079✔
1696

1697
  for (;;) {  /* Head of declarator. */
442,535✔
1698
    if (cp_opt(cp, '*')) {  /* Pointer. */
442,535✔
1699
      CTSize sz;
456✔
1700
      CTInfo info;
456✔
1701
      cp_decl_attributes(cp, decl);
456✔
1702
      sz = CTSIZE_PTR;
456✔
1703
      info = CTINFO(CT_PTR, CTALIGN_PTR);
456✔
1704
#if LJ_64
1705
      if (ctype_msizeP(decl->attr) == 4) {
456✔
1706
        sz = 4;
×
1707
        info = CTINFO(CT_PTR, CTALIGN(2));
×
1708
      }
1709
#endif
1710
      info += (decl->attr & (CTF_QUAL|CTF_REF));
456✔
1711
      decl->attr &= ~(CTF_QUAL|(CTMASK_MSIZEP<<CTSHIFT_MSIZEP));
456✔
1712
      cp_push(decl, info, sz);
456✔
1713
    } else if (cp_opt(cp, '&') || cp_opt(cp, CTOK_ANDAND)) {  /* Reference. */
442,079✔
1714
      decl->attr &= ~(CTF_QUAL|(CTMASK_MSIZEP<<CTSHIFT_MSIZEP));
×
1715
      cp_push(decl, CTINFO_REF(0), CTSIZE_PTR);
×
1716
    } else {
1717
      break;
1718
    }
1719
  }
1720

1721
  if (cp_opt(cp, '(')) {  /* Inner declarator. */
442,079✔
1722
    CPDeclIdx pos;
6✔
1723
    cp_decl_attributes(cp, decl);
6✔
1724
    /* Resolve ambiguity between inner declarator and 1st function parameter. */
1725
    if ((decl->mode & CPARSE_MODE_ABSTRACT) &&
6✔
1726
        (cp->tok == ')' || cp_istypedecl(cp))) goto func_decl;
6✔
1727
    pos = decl->pos;
5✔
1728
    cp_declarator(cp, decl);
5✔
1729
    cp_check(cp, ')');
5✔
1730
    decl->pos = pos;
5✔
1731
  } else if (cp->tok == CTOK_IDENT) {  /* Direct declarator. */
442,073✔
1732
    if (!(decl->mode & CPARSE_MODE_DIRECT)) cp_err_token(cp, CTOK_EOF);
338✔
1733
    decl->name = cp->str;
338✔
1734
    decl->nameid = cp->val.id;
338✔
1735
    cp_next(cp);
338✔
1736
  } else {  /* Abstract declarator. */
1737
    if (!(decl->mode & CPARSE_MODE_ABSTRACT)) cp_err_token(cp, CTOK_IDENT);
441,735✔
1738
  }
1739

1740
  for (;;) {  /* Tail of declarator. */
442,401✔
1741
    if (cp_opt(cp, '[')) {  /* Array. */
442,401✔
1742
      cp_decl_array(cp, decl);
291✔
1743
    } else if (cp_opt(cp, '(')) {  /* Function. */
442,110✔
1744
    func_decl:
32✔
1745
      cp_decl_func(cp, decl);
32✔
1746
    } else {
1747
      break;
1748
    }
1749
  }
1750

1751
  if ((decl->mode & CPARSE_MODE_FIELD) && cp_opt(cp, ':'))  /* Field width. */
442,079✔
1752
    decl->bits = cp_expr_ksize(cp);
×
1753

1754
  /* Process postfix attributes. */
1755
  cp_decl_attributes(cp, decl);
442,079✔
1756
  cp_push_attributes(decl);
442,079✔
1757

1758
  cp->depth--;
442,079✔
1759
}
442,079✔
1760

1761
/* Parse an abstract type declaration and return it's C type ID. */
1762
static CTypeID cp_decl_abstract(CPState *cp)
×
1763
{
1764
  CPDecl decl;
×
1765
  cp_decl_spec(cp, &decl, 0);
×
1766
  decl.mode = CPARSE_MODE_ABSTRACT;
×
1767
  cp_declarator(cp, &decl);
×
1768
  return cp_decl_intern(cp, &decl);
×
1769
}
1770

1771
/* Handle pragmas. */
1772
static void cp_pragma(CPState *cp, BCLine pragmaline)
×
1773
{
1774
  cp_next(cp);
×
1775
  if (cp->tok == CTOK_IDENT && cp_str_is(cp->str, "pack"))  {
×
1776
    cp_next(cp);
×
1777
    cp_check(cp, '(');
×
1778
    if (cp->tok == CTOK_IDENT) {
×
1779
      if (cp_str_is(cp->str, "push")) {
×
1780
        if (cp->curpack < CPARSE_MAX_PACKSTACK) {
×
1781
          cp->packstack[cp->curpack+1] = cp->packstack[cp->curpack];
×
1782
          cp->curpack++;
×
1783
        }
1784
      } else if (cp_str_is(cp->str, "pop")) {
×
1785
        if (cp->curpack > 0) cp->curpack--;
×
1786
      } else {
1787
        cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL);
×
1788
      }
1789
      cp_next(cp);
×
1790
      if (!cp_opt(cp, ',')) goto end_pack;
×
1791
    }
1792
    if (cp->tok == CTOK_INTEGER) {
×
1793
      cp->packstack[cp->curpack] = cp->val.u32 ? lj_fls(cp->val.u32) : 0;
×
1794
      cp_next(cp);
×
1795
    } else {
1796
      cp->packstack[cp->curpack] = 255;
×
1797
    }
1798
  end_pack:
×
1799
    cp_check(cp, ')');
×
1800
  } else {  /* Ignore all other pragmas. */
1801
    while (cp->tok != CTOK_EOF && cp->linenumber == pragmaline)
×
1802
      cp_next(cp);
×
1803
  }
1804
}
×
1805

1806
/* Handle line number. */
1807
static void cp_line(CPState *cp, BCLine hashline)
×
1808
{
1809
  BCLine newline = cp->val.u32;
×
1810
  /* TODO: Handle file name and include it in error messages. */
1811
  while (cp->tok != CTOK_EOF && cp->linenumber == hashline)
×
1812
    cp_next(cp);
×
1813
  cp->linenumber = newline;
×
1814
}
1815

1816
/* Parse multiple C declarations of types or extern identifiers. */
1817
static void cp_decl_multi(CPState *cp)
25✔
1818
{
1819
  int first = 1;
25✔
1820
  while (cp->tok != CTOK_EOF) {
81✔
1821
    CPDecl decl;
64✔
1822
    CPscl scl;
64✔
1823
    if (cp_opt(cp, ';')) {  /* Skip empty statements. */
64✔
1824
      first = 0;
×
1825
      continue;
×
1826
    }
1827
    if (cp->tok == '#') {  /* Workaround, since we have no preprocessor, yet. */
64✔
1828
      BCLine hashline = cp->linenumber;
×
1829
      CPToken tok = cp_next(cp);
×
1830
      if (tok == CTOK_INTEGER) {
×
1831
        cp_line(cp, hashline);
×
1832
        continue;
×
1833
      } else if (tok == CTOK_IDENT && cp_str_is(cp->str, "line")) {
×
1834
        if (cp_next(cp) != CTOK_INTEGER) cp_err_token(cp, tok);
×
1835
        cp_line(cp, hashline);
×
1836
        continue;
×
1837
      } else if (tok == CTOK_IDENT && cp_str_is(cp->str, "pragma")) {
×
1838
        cp_pragma(cp, hashline);
×
1839
        continue;
×
1840
      } else {
1841
        cp_errmsg(cp, cp->tok, LJ_ERR_XSYMBOL);
×
1842
      }
1843
    }
1844
    scl = cp_decl_spec(cp, &decl, CDF_TYPEDEF|CDF_EXTERN|CDF_STATIC);
64✔
1845
    if ((cp->tok == ';' || cp->tok == CTOK_EOF) &&
64✔
1846
        ctype_istypedef(decl.stack[0].info)) {
2✔
1847
      CTInfo info = ctype_rawchild(cp->cts, &decl.stack[0])->info;
2✔
1848
      if (ctype_isstruct(info) || ctype_isenum(info))
2✔
1849
        goto decl_end;  /* Accept empty declaration of struct/union/enum. */
2✔
1850
    }
1851
    for (;;) {
62✔
1852
      CTypeID ctypeid;
62✔
1853
      cp_declarator(cp, &decl);
62✔
1854
      ctypeid = cp_decl_intern(cp, &decl);
62✔
1855
      if (decl.name && !decl.nameid) {  /* NYI: redeclarations are ignored. */
62✔
1856
        CType *ct;
62✔
1857
        CTypeID id;
62✔
1858
        if ((scl & CDF_TYPEDEF)) {  /* Create new typedef. */
62✔
1859
          id = lj_ctype_new(cp->cts, &ct);
32✔
1860
          ct->info = CTINFO(CT_TYPEDEF, ctypeid);
32✔
1861
          goto noredir;
32✔
1862
        } else if (ctype_isfunc(ctype_get(cp->cts, ctypeid)->info)) {
30✔
1863
          /* Treat both static and extern function declarations as extern. */
1864
          ct = ctype_get(cp->cts, ctypeid);
29✔
1865
          /* We always get new anonymous functions (typedefs are copied). */
1866
          lj_assertCP(gcref(ct->name) == NULL, "unexpected named function");
29✔
1867
          id = ctypeid;  /* Just name it. */
29✔
1868
        } else if ((scl & CDF_STATIC)) {  /* Accept static constants. */
1✔
1869
          id = cp_decl_constinit(cp, &ct, ctypeid);
×
1870
          goto noredir;
×
1871
        } else {  /* External references have extern or no storage class. */
1872
          id = lj_ctype_new(cp->cts, &ct);
1✔
1873
          ct->info = CTINFO(CT_EXTERN, ctypeid);
1✔
1874
        }
1875
        if (decl.redir) {  /* Add attribute for redirected symbol name. */
30✔
1876
          CType *cta;
3✔
1877
          CTypeID aid = lj_ctype_new(cp->cts, &cta);
3✔
1878
          ct = ctype_get(cp->cts, id);  /* Table may have been reallocated. */
3✔
1879
          cta->info = CTINFO(CT_ATTRIB, CTATTRIB(CTA_REDIR));
3✔
1880
          cta->sib = ct->sib;
3✔
1881
          ct->sib = aid;
3✔
1882
          ctype_setname(cta, decl.redir);
3✔
1883
        }
1884
      noredir:
27✔
1885
        ctype_setname(ct, decl.name);
62✔
1886
        lj_ctype_addname(cp->cts, ct, id);
62✔
1887
      }
1888
      if (!cp_opt(cp, ',')) break;
62✔
1889
      cp_decl_reset(&decl);
62✔
1890
    }
1891
  decl_end:
64✔
1892
    if (cp->tok == CTOK_EOF && first) break;  /* May omit ';' for 1 decl. */
64✔
1893
    first = 0;
56✔
1894
    cp_check(cp, ';');
56✔
1895
  }
1896
}
25✔
1897

1898
/* Parse a single C type declaration. */
1899
static void cp_decl_single(CPState *cp)
441,687✔
1900
{
1901
  CPDecl decl;
441,687✔
1902
  cp_decl_spec(cp, &decl, 0);
441,687✔
1903
  cp_declarator(cp, &decl);
441,687✔
1904
  cp->val.id = cp_decl_intern(cp, &decl);
441,687✔
1905
  if (cp->tok != CTOK_EOF) cp_err_token(cp, CTOK_EOF);
441,687✔
1906
}
441,687✔
1907

1908
/* ------------------------------------------------------------------------ */
1909

1910
/* Protected callback for C parser. */
1911
static TValue *cpcparser(lua_State *L, lua_CFunction dummy, void *ud)
441,712✔
1912
{
1913
  CPState *cp = (CPState *)ud;
441,712✔
1914
  UNUSED(dummy);
441,712✔
1915
  cframe_errfunc(L->cframe) = -1;  /* Inherit error function. */
441,712✔
1916
  cp_init(cp);
441,712✔
1917
  if ((cp->mode & CPARSE_MODE_MULTI))
441,712✔
1918
    cp_decl_multi(cp);
25✔
1919
  else
1920
    cp_decl_single(cp);
441,687✔
1921
  if (cp->param && cp->param != cp->L->top)
441,712✔
1922
    cp_err(cp, LJ_ERR_FFI_NUMPARAM);
×
1923
  lj_assertCP(cp->depth == 0, "unbalanced cparser declaration depth");
441,712✔
1924
  return NULL;
441,712✔
1925
}
1926

1927
/* C parser. */
1928
int lj_cparse(CPState *cp)
441,712✔
1929
{
1930
  LJ_CTYPE_SAVE(cp->cts);
441,712✔
1931
  int errcode = lj_vm_cpcall(cp->L, NULL, cp, cpcparser);
441,712✔
1932
  if (errcode)
441,712✔
1933
    LJ_CTYPE_RESTORE(cp->cts);
×
1934
  cp_cleanup(cp);
441,712✔
1935
  return errcode;
441,712✔
1936
}
1937

1938
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc