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

nickg / nvc / 18242687814

04 Oct 2025 09:39AM UTC coverage: 92.716% (+0.02%) from 92.692%
18242687814

push

github

nickg
Fix required argument calculation for subprograms with mode view

3 of 3 new or added lines in 1 file covered. (100.0%)

14 existing lines in 1 file now uncovered.

74547 of 80404 relevant lines covered (92.72%)

579235.9 hits per line

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

97.86
/src/bounds.c
1
//
2
//  Copyright (C) 2011-2025  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "common.h"
20
#include "diag.h"
21
#include "phase.h"
22
#include "type.h"
23

24
#include <assert.h>
25
#include <string.h>
26
#include <stdarg.h>
27
#include <stdlib.h>
28
#include <inttypes.h>
29

30
static void bounds_check_assignment(tree_t target, tree_t value);
31

32
typedef struct interval interval_t;
33

34
struct interval {
35
   int64_t     low;
36
   int64_t     high;
37
   interval_t *next;
38
};
39

40
#define bounds_error(t, ...) \
41
   do { error_at(tree_loc(t), __VA_ARGS__); } while (0)
42

43
static void bounds_check_string_literal(tree_t t)
29,992✔
44
{
45
   type_t type = tree_type(t);
29,992✔
46
   assert(!type_is_unconstrained(type));
29,992✔
47

48
   int64_t expect;
29,992✔
49
   if (folded_length(range_of(type, 0), &expect) && expect != tree_chars(t))
29,992✔
50
      bounds_error(t, "expected %"PRIi64" elements in string literal but "
29,992✔
51
                   "have %d", expect, tree_chars(t));
52
}
29,992✔
53

54
static void format_type_range(diag_t *d, type_t type, range_kind_t dir,
79✔
55
                              int64_t low, int64_t high)
56
{
57
   text_buf_t *tb = diag_text_buf(d);
79✔
58

59
   if (dir == RANGE_DOWNTO) {
79✔
60
      to_string(tb, type, high);
17✔
61
      tb_cat(tb, " downto ");
17✔
62
      to_string(tb, type, low);
17✔
63
   }
64
   else {
65
      to_string(tb, type, low);
62✔
66
      tb_cat(tb, " to ");
62✔
67
      to_string(tb, type, high);
62✔
68
   }
69
}
79✔
70

71
static void add_hint_string(diag_t *d, tree_t where)
38✔
72
{
73
   const char *what = "";
38✔
74
   switch (tree_kind(where)) {
38✔
75
   case T_VAR_DECL:
19✔
76
   case T_SIGNAL_DECL:
77
   case T_CONST_DECL:
78
   case T_REF:          what = class_str(class_of(where)); break;
19✔
79
   case T_PARAM_DECL:   what = "parameter"; break;
80
   case T_PORT_DECL:    what = "port"; break;
1✔
81
   case T_GENERIC_DECL: what = "generic"; break;
4✔
82
   case T_ALIAS:        what = "alias"; break;
1✔
83
   default: return;
84
   }
85

86
   diag_printf(d, " for %s %s", what, istr(tree_ident(where)));
35✔
87
}
88

89
static void bounds_check_scalar(tree_t value, type_t type, tree_t hint)
238,721✔
90
{
91
   if (type_is_generic(type))
238,721✔
92
      return;   // Cannot check yet
40✔
93

94
   tree_t r = range_of(type, 0);
238,681✔
95

96
   bool error = false;
238,681✔
97
   int64_t low, high, folded;
238,681✔
98
   double rlow, rhigh;
238,681✔
99
   if (folded_bounds(r, &low, &high)) {
238,681✔
100
      if (folded_int(value, &folded))
208,046✔
101
         error = (folded < low || folded > high);
158,359✔
102
   }
103
   else if (folded_bounds_real(r, &rlow, &rhigh)) {
30,635✔
104
      double folded_f;
30,529✔
105
      if (folded_real(value, &folded_f)) {
30,529✔
106
         error  = (folded_f < rlow || folded_f > rhigh);
21,484✔
107
         folded = FLOAT_BITS(folded_f);
21,484✔
108
         low    = FLOAT_BITS(rlow);
21,484✔
109
         high   = FLOAT_BITS(rhigh);
21,484✔
110
      }
111
   }
112

113
   if (error) {
109,720✔
114
      diag_t *d = diag_new(DIAG_ERROR, tree_loc(value));
26✔
115
      diag_printf(d, "value ");
26✔
116
      to_string(diag_text_buf(d), type, folded);
26✔
117
      diag_printf(d, " outside of %s range ", type_pp(type));
26✔
118
      format_type_range(d, type, tree_subkind(r), low, high);
26✔
119

120
      if (hint != NULL)
26✔
121
         add_hint_string(d, hint);
25✔
122

123
      diag_emit(d);
26✔
124
   }
125
}
126

127
static void bounds_check_array(tree_t value, type_t type, tree_t hint)
30,010✔
128
{
129
   if (type_is_unconstrained(type))
30,010✔
130
      return;
131

132
   type_t value_type = tree_type(value);
20,448✔
133
   if (type_is_unconstrained(value_type))
20,448✔
134
      return;
135

136
   const int ndims = dimension_of(type);
13,243✔
137
   for (int i = 0; i < ndims; i++) {
27,997✔
138
      int64_t target_w, value_w;
14,754✔
139
      if (!folded_length(range_of(type, i), &target_w))
14,754✔
140
         continue;
3,005✔
141
      else if (!folded_length(range_of(value_type, i), &value_w))
11,804✔
142
         continue;
55✔
143
      else if (target_w != value_w) {
11,749✔
144
         diag_t *d = diag_new(DIAG_ERROR, tree_loc(value));
14✔
145
         diag_printf(d, "length of ");
14✔
146
         if (i > 0)
14✔
147
            diag_printf(d, "dimension %d of ", i + 1);
×
148
         diag_printf(d, "value %"PRIi64" does not match length of target %"
14✔
149
                     PRIi64, value_w, target_w);
150
         if (hint != NULL)
14✔
151
            add_hint_string(d, hint);
13✔
152

153
         diag_emit(d);
14✔
154
      }
155
   }
156
}
157

158
static tree_t bounds_check_call_args(tree_t t)
108,091✔
159
{
160
   tree_t decl = tree_ref(t);
108,091✔
161

162
   const int nparams = tree_params(t);
108,091✔
163
   const int nports  = tree_ports(decl);
108,091✔
164

165
   bool known_arg_length = true;
108,091✔
166

167
   for (int i = 0; (i < nparams) && (i < nports); i++) {
329,608✔
168
      tree_t param = tree_param(t, i), port;
221,517✔
169
      switch (tree_subkind(param)) {
221,517✔
170
      case P_POS:
221,517✔
171
         port = tree_port(decl, tree_pos(param));
221,517✔
172
         break;
221,517✔
173
      case P_NAMED:
×
174
         port = tree_ref(name_to_ref(tree_name(param)));
×
175
         break;
×
176
      default:
×
177
         should_not_reach_here();
178
      }
179
      assert(tree_kind(port) == T_PARAM_DECL);
221,517✔
180

181
      tree_t value = tree_value(param);
221,517✔
182

183
      type_t ftype = tree_type(port);
221,517✔
184
      type_t atype = tree_type(value);
221,517✔
185

186
      if (type_is_array(ftype)) {
221,517✔
187
         // Check bounds of constrained array parameters
188

189
         if (type_is_unconstrained(atype)) {
51,961✔
190
            known_arg_length = false;
20,149✔
191
            continue;
20,149✔
192
         }
193
         else if (type_is_unconstrained(ftype))
31,812✔
194
            continue;
30,623✔
195

196
         const int ndims = dimension_of(ftype);
1,189✔
197

198
         for (int j = 0; j < ndims; j++) {
2,484✔
199
            tree_t formal_r = range_of(ftype, j);
1,295✔
200
            tree_t actual_r = range_of(atype, j);
1,295✔
201

202
            int64_t f_len, a_len;
1,295✔
203
            if (!folded_length(formal_r, &f_len))
1,295✔
204
               continue;
40✔
205
            else if (!folded_length(actual_r, &a_len)) {
1,283✔
206
               known_arg_length = false;
28✔
207
               continue;
28✔
208
            }
209

210
            if (f_len != a_len) {
1,255✔
211
               diag_t *d = diag_new(DIAG_ERROR, tree_loc(param));
3✔
212
               diag_printf(d, "actual length %"PRIi64, a_len);
3✔
213
               if (ndims > 1)
3✔
214
                  diag_printf(d, " for dimension %d", j + 1);
1✔
215
               diag_printf(d, " does not match formal length %"PRIi64
3✔
216
                           " for parameter %s", f_len, istr(tree_ident(port)));
217
               diag_emit(d);
3✔
218
            }
219
         }
220
      }
221
      else if (type_is_scalar(ftype))
169,556✔
222
         bounds_check_scalar(value, ftype, port);
160,051✔
223
   }
224

225
   if (tree_kind(decl) == T_GENERIC_DECL)
108,091✔
226
      return t;
227

228
   const subprogram_kind_t kind = tree_subkind(decl);
107,669✔
229
   if (known_arg_length && (kind == S_ARRAY_EQ || kind == S_ARRAY_NEQ)) {
107,669✔
230
      // Warn if calling the predefined array equality operators and the
231
      // left and right hand sides have different lengths as this always
232
      // returns FALSE
233

234
      type_t ltype = tree_type(tree_value(tree_param(t, 0)));
4,615✔
235
      type_t rtype = tree_type(tree_value(tree_param(t, 1)));
4,615✔
236

237
      const int ndims = dimension_of(ltype);
4,615✔
238
      for (int i = 0; i < ndims; i++) {
9,887✔
239
         tree_t left_r = range_of(ltype, i);
5,287✔
240
         tree_t right_r = range_of(rtype, i);
5,287✔
241

242
         int64_t left_len;
5,287✔
243
         if (!folded_length(left_r, &left_len))
5,287✔
244
            continue;
581✔
245

246
         int64_t right_len;
4,706✔
247
         if (!folded_length(right_r, &right_len))
4,706✔
248
            continue;
×
249

250
         if (left_len != right_len) {
4,706✔
251
            diag_t *d = diag_new(DIAG_WARN, tree_loc(t));
15✔
252
            diag_printf(d, "call to predefined operator %s always returns "
15✔
253
                        "FALSE", istr(tree_ident(t)));
254
            diag_hint(d, tree_loc(t), "left length is %"PRIi64" but right "
15✔
255
                      "length is %"PRIi64, left_len, right_len);
256
            diag_emit(d);
15✔
257
            break;
15✔
258
         }
259
      }
260
   }
261

262
   return t;
263
}
264

265
static bool index_in_range(tree_t index, int64_t low, int64_t high,
7,743✔
266
                           int64_t *value)
267
{
268
   int64_t folded;
7,743✔
269
   if (folded_int(index, &folded)) {
7,743✔
270
      *value = folded;
7,739✔
271
      return folded >= low && folded <= high;
7,754✔
272
   }
273

274
   return true;
275
}
276

277
static bool bounds_check_index(tree_t index, type_t type, range_kind_t kind,
5,708✔
278
                               const char *what, int64_t low, int64_t high)
279
{
280
   int64_t folded;
5,708✔
281
   if (!index_in_range(index, low, high, &folded) && low <= high) {
5,708✔
282
      diag_t *d = diag_new(DIAG_ERROR, tree_loc(index));
10✔
283
      diag_printf(d, "%s index ", what);
10✔
284
      to_string(diag_text_buf(d), type, folded);
10✔
285
      diag_printf(d, " outside of %s range ", type_pp(type));
10✔
286
      format_type_range(d, type, kind, low, high);
10✔
287
      diag_emit(d);
10✔
288

289
      return false;
10✔
290
   }
291

292
   return true;
293
}
294

295
static void bounds_check_array_ref(tree_t t)
18,560✔
296
{
297
   tree_t value = tree_value(t);
18,560✔
298

299
   if (!tree_has_type(value))
18,560✔
300
      return;
301
   else if (tree_flags(t) & TREE_F_ELIDE_BOUNDS)
18,560✔
302
      return;
303

304
   type_t value_type = tree_type(value);
18,256✔
305

306
   const bool unconstrained = type_is_unconstrained(value_type);
18,256✔
307
   const bool value_is_ref = tree_kind(value) == T_REF;
18,256✔
308

309
   int nstatic = 0;
18,256✔
310
   const int nparams = tree_params(t);
18,256✔
311
   for (int i = 0; i < nparams; i++) {
38,559✔
312
      tree_t p = tree_param(t, i);
20,303✔
313
      tree_t pvalue = tree_value(p);
20,303✔
314
      bool checked = false;
20,303✔
315

316
      if (!unconstrained) {
20,303✔
317
         tree_t r = range_of(value_type, i);
16,361✔
318
         type_t index_type = index_type_of(value_type, i);
16,361✔
319
         const range_kind_t dir = tree_subkind(r);
16,361✔
320

321
         int64_t ivalue, low, high;
16,361✔
322
         if (folded_int(pvalue, &ivalue) && folded_bounds(r, &low, &high)) {
16,361✔
323
            checked = true;
7,259✔
324

325
            if (ivalue < low || ivalue > high) {
7,259✔
326
               diag_t *d = diag_new(DIAG_ERROR, tree_loc(pvalue));
11✔
327
               diag_printf(d, "array");
11✔
328
               if (tree_kind(value) == T_REF)
11✔
329
                  diag_printf(d, " %s", istr(tree_ident(value)));
10✔
330
               diag_printf(d, " index ");
11✔
331
               to_string(diag_text_buf(d), index_type, ivalue);
11✔
332
               diag_printf(d, " outside of %s range ", type_pp(index_type));
11✔
333
               format_type_range(d, index_type, dir, low, high);
11✔
334

335
               diag_emit(d);
11✔
336
            }
337
         }
338
      }
339

340
      if (value_is_ref && nparams == 1 && tree_kind(pvalue) == T_REF) {
20,303✔
341
         // Automatically elide bounds check in cases like
342
         //
343
         //   for i in x'range loop
344
         //     y := a(x);  -- Always in bounds
345

346
         type_t ptype = tree_type(pvalue);
8,028✔
347
         if (type_kind(ptype) == T_SUBTYPE && type_has_constraint(ptype)) {
8,028✔
348
            tree_t c = type_constraint(ptype);
6,230✔
349
            if (tree_subkind(c) == C_RANGE) {
6,230✔
350
               tree_t r = tree_range(c, 0);
6,230✔
351
               if (tree_subkind(r) == RANGE_EXPR) {
6,230✔
352
                  tree_t r_attr = tree_value(r);
2,248✔
353
                  assert(tree_kind(r_attr) == T_ATTR_REF);
2,248✔
354
                  tree_t r_base = tree_name(r_attr);
2,248✔
355
                  checked |= (tree_kind(r_base) == T_REF &&
5,468✔
356
                              tree_ref(r_base) == tree_ref(value));
2,247✔
357
               }
358
            }
359
         }
360
      }
361

362
      if (checked)
20,303✔
363
         nstatic++;
8,533✔
364
   }
365

366
   if (nstatic == nparams)
18,256✔
367
      tree_set_flag(t, TREE_F_ELIDE_BOUNDS);
7,031✔
368
}
369

370
static void bounds_check_array_slice(tree_t t)
3,317✔
371
{
372
   tree_t value = tree_value(t);
3,317✔
373

374
   if (!tree_has_type(value))
3,317✔
375
      return;
2,404✔
376

377
   type_t value_type = tree_type(value);
3,317✔
378

379
   if (type_is_unconstrained(value_type))
3,317✔
380
      return;
381

382
   tree_t b = range_of(value_type, 0);
3,019✔
383
   tree_t r = tree_range(t, 0);
3,019✔
384

385
   int64_t blow, bhigh;
3,019✔
386
   if (!folded_bounds(b, &blow, &bhigh))
3,019✔
387
      return;
388

389
   int64_t rlow, rhigh;
1,129✔
390
   if (!folded_bounds(r, &rlow, &rhigh))
1,129✔
391
      return;
392

393
   if (rlow > rhigh)
953✔
394
      return;  // Null range
395

396
   type_t index_type = index_type_of(value_type, 0);
913✔
397
   const range_kind_t dir = tree_subkind(b);
913✔
398

399
   int64_t folded;
913✔
400
   const char *error = NULL;
913✔
401
   if (!index_in_range(tree_left(r), blow, bhigh, &folded))
913✔
402
      error = "left";
403
   else if (!index_in_range(tree_right(r), blow, bhigh, &folded))
910✔
404
      error = "right";
405

406
   if (error) {
4✔
407
      diag_t *d = diag_new(DIAG_ERROR, tree_loc(r));
4✔
408
      diag_printf(d, "array");
4✔
409
      if (tree_kind(value) == T_REF)
4✔
410
         diag_printf(d, " %s", istr(tree_ident(value)));
4✔
411
      diag_printf(d, " slice %s index ", error);
4✔
412
      to_string(diag_text_buf(d), index_type, folded);
4✔
413
      diag_printf(d, " outside of %s range ", type_pp(index_type));
4✔
414
      format_type_range(d, index_type, dir, blow, bhigh);
4✔
415

416
      diag_emit(d);
4✔
417
   }
418
}
419

420
static void bounds_check_array_element(tree_t value, type_t type)
2,229✔
421
{
422
   assert(!type_is_unconstrained(type));
2,229✔
423

424
   type_t value_type = tree_type(value);
2,229✔
425
   if (type_is_unconstrained(value_type))
2,229✔
426
      return;
427

428
   const int ndims = dimension_of(type);
1,449✔
429
   for (int i = 0; i < ndims; i++) {
3,150✔
430
      int64_t target_w, value_w;
1,701✔
431
      if (!folded_length(range_of(type, i), &target_w))
1,701✔
432
         continue;
20✔
433
      else if (!folded_length(range_of(value_type, i), &value_w))
1,681✔
UNCOV
434
         continue;
×
435
      else if (target_w != value_w) {
1,681✔
436
         diag_t *d = diag_new(DIAG_ERROR, tree_loc(value));
1✔
437
         diag_printf(d, "length of ");
1✔
438
         if (i > 0)
1✔
UNCOV
439
            diag_printf(d, "dimension %d of ", i + 1);
×
440
         diag_printf(d, "element %"PRIi64" does not match expected length %"
1✔
441
                     PRIi64, value_w, target_w);
442

443
         diag_emit(d);
1✔
444
      }
445
   }
446
}
447

448
static void bounds_cover_choice(interval_t **isp, tree_t t, type_t type,
39,101✔
449
                                int64_t low, int64_t high)
450
{
451
   interval_t *it, *prev;
39,101✔
452
   for (it = *isp, prev = NULL;
39,101✔
453
        (it != NULL) && (it->low <= high);
42,333✔
454
        prev = it, it = it->next) {
3,232✔
455

456
      if ((low <= it->high) && (it->low <= high)) {
34,000✔
457
         const int64_t rlow  = MAX(low, it->low);
5✔
458
         const int64_t rhigh = MIN(high, it->high);
5✔
459
         if (type_is_integer(type)) {
5✔
460
            if (rlow == rhigh)
3✔
461
               bounds_error(t, "value %"PRIi64" is already covered", rlow);
2✔
462
            else
463
               bounds_error(t, "range %"PRIi64" to %"PRIi64" is already covered",
1✔
464
                            rlow, rhigh);
465
         }
466
         else if (type_is_enum(type)) {
2✔
467
            type_t base = type_base_recur(type);
2✔
468
            if (rlow == rhigh)
2✔
469
               bounds_error(t, "duplicate choice for %s",
2✔
470
                            istr(tree_ident(type_enum_literal(base, rlow))));
471
            else
UNCOV
472
               bounds_error(t, "duplicate choices for range %s to %s",
×
473
                            istr(tree_ident(type_enum_literal(base, rlow))),
474
                            istr(tree_ident(type_enum_literal(base, rhigh))));
475
         }
476
         it->low = MIN(low, it->low);
5✔
477
         it->high = MAX(high, it->high);
5✔
478
         return;
5✔
479
      }
480
      else if (high == it->low - 1) {
33,995✔
UNCOV
481
         it->low = low;
×
UNCOV
482
         return;
×
483
      }
484
      else if (low == it->high + 1) {
33,995✔
485
         it->high = high;
30,763✔
486
         return;
30,763✔
487
      }
488
   }
489

490
   interval_t *new = xmalloc(sizeof(interval_t));
8,333✔
491
   new->low  = low;
8,333✔
492
   new->high = high;
8,333✔
493

494
   if ((*isp == NULL) || (prev == NULL)) {
8,333✔
495
      new->next = *isp;
7,271✔
496
      *isp = new;
7,271✔
497
   }
498
   else {
499
      new->next = prev->next;
1,062✔
500
      prev->next = new;
1,062✔
501
   }
502
}
503

504
static void report_interval(diag_t *d, type_t type, range_kind_t dir,
33✔
505
                            int64_t low, int64_t high)
506
{
507
   if (low == high) {
33✔
508
      if (type_is_integer(type))
13✔
509
         diag_printf(d, "%"PRIi64, low);
6✔
510
      else if (type_is_enum(type)) {
7✔
511
         type_t base = type_base_recur(type);
7✔
512
         diag_printf(d, "%s", istr(tree_ident(type_enum_literal(base, low))));
7✔
513
      }
514
   }
515
   else
516
      format_type_range(d, type, dir, low, high);
20✔
517
}
33✔
518

519
static void bounds_check_missing_choices(tree_t t, type_t type,
4,845✔
520
                                         type_t index_type, range_kind_t dir,
521
                                         int64_t tlow, int64_t thigh,
522
                                         interval_t *covered)
523
{
524
   int missing = 0;
4,845✔
525
   interval_t *it;
4,845✔
526
   int64_t walk;
4,845✔
527

528
   for (it = covered, walk = tlow; it != NULL; it = it->next) {
10,534✔
529
      if (it->low != walk)
5,689✔
530
         missing += it->low - walk;
9✔
531
      walk = it->high + 1;
5,689✔
532
   }
533

534
   if (walk != thigh + 1)
4,845✔
535
      missing += (thigh + 1 - walk);
16✔
536

537
   if (missing == 0)
4,845✔
538
      return;
4,824✔
539

540
   // Allow downgrade to warning for case statement but not aggregates
541
   diag_t *d;
21✔
542
   if (index_type == NULL) {
21✔
543
      if ((d = pedantic_diag(tree_loc(t))) == NULL)
9✔
544
         return;
545
   }
546
   else
547
      d = diag_new(DIAG_ERROR, tree_loc(t));
12✔
548

549
   diag_printf(d, "missing choice%s for element%s ",
21✔
550
               missing > 1 ? "s" : "", missing > 1 ? "s" : "");
551

552
   int printed = 0;
21✔
553
   for (it = covered, walk = tlow; it != NULL; it = it->next) {
66✔
554
      if (it->low != walk) {
24✔
555
         if (printed++) diag_printf(d, ", ");
9✔
556
         report_interval(d, index_type ?: type, dir, walk, it->low - 1);
14✔
557
      }
558

559
      walk = it->high + 1;
24✔
560
   }
561

562
   if (walk != thigh + 1) {
21✔
563
      if (printed++) diag_printf(d, ", ");
16✔
564
      report_interval(d, index_type ?: type, dir, walk, thigh);
23✔
565
   }
566

567
   if (index_type == NULL)
21✔
568
      diag_printf(d, " of type %s", type_pp(type));
9✔
569
   else
570
      diag_printf(d, " of %s with index type %s", type_pp(type),
12✔
571
                  type_pp(index_type));
572

573
   type_t base = index_type ?: type;
21✔
574
   while (is_anonymous_subtype(base))
22✔
575
      base = type_base(base);
1✔
576

577
   int64_t rlow, rhigh;
21✔
578
   if (!folded_bounds(range_of(index_type ?: type, 0), &rlow, &rhigh))
21✔
579
      return;
580

581
   if (rlow != tlow || rhigh != thigh || !type_has_ident(index_type ?: type)) {
21✔
582
      diag_printf(d, " range ");
8✔
583
      report_interval(d, index_type ?: type, dir, tlow, thigh);
8✔
584
   }
585

586
   diag_emit(d);
21✔
587
}
588

589
static void bounds_free_intervals(interval_t **list)
9,766✔
590
{
591
   for (interval_t *it = *list, *tmp; it != NULL; it = tmp) {
18,099✔
592
      tmp = it->next;
8,333✔
593
      free(it);
8,333✔
594
   }
595
   *list = NULL;
9,766✔
596
}
9,766✔
597

598
static void bounds_check_aggregate(tree_t t)
14,074✔
599
{
600
   type_t type = tree_type(t);
14,074✔
601
   if (!type_is_array(type))
14,074✔
602
      return;
4,847✔
603

604
   // Find the tightest bounds for the index
605

606
   int64_t low, high, clow = 0, chigh = 0;
10,913✔
607
   type_t index_type = index_type_of(type, 0);
10,913✔
608
   range_kind_t dir;
10,913✔
609

610
   const bool unconstrained = type_is_unconstrained(type);
10,913✔
611

612
   if (unconstrained) {
10,913✔
613
      // Aggregate of unconstrained array type
614
      tree_t base_r = range_of(index_type, 0);
2,703✔
615
      if (!folded_bounds(base_r, &low, &high))
2,703✔
616
         return;
617

618
      clow = high, chigh = low;  // Actual bounds computed below
2,695✔
619
      dir = tree_subkind(base_r);
2,695✔
620
   }
621
   else {
622
      tree_t type_r = range_of(type, 0);
8,210✔
623
      if (!folded_bounds(type_r, &low, &high))
8,210✔
624
         return;
625

626
      clow = low, chigh = high;
6,532✔
627
      dir = tree_subkind(type_r);
6,532✔
628
   }
629

630
   const int ndims = dimension_of(type);
9,227✔
631
   type_t elem = type_elem(type);
9,227✔
632

633
   const bool check_scalar_elem = type_is_scalar(elem);
9,227✔
634
   const bool check_array_elem =
18,454✔
635
      !check_scalar_elem && ndims == 1 && type_is_array(elem)
1,288✔
636
      && !type_is_unconstrained(elem);
9,993✔
637

638
   interval_t *covered = NULL;
9,227✔
639
   bool known_elem_count = true;
9,227✔
640
   int next_pos = 0;
9,227✔
641
   const int nassocs = tree_assocs(t);
9,227✔
642
   for (int i = 0; i < nassocs; i++) {
52,930✔
643
      tree_t a = tree_assoc(t, i), value = tree_value(a);
43,703✔
644
      int64_t ilow = 0, ihigh = 0, count = 1;
43,703✔
645
      const assoc_kind_t akind = tree_subkind(a);
43,703✔
646

647
      if (akind == A_SLICE || akind == A_CONCAT) {
43,703✔
648
         type_t value_type = tree_type(value);
6,476✔
649
         if (type_is_unconstrained(value_type))
6,476✔
650
            known_elem_count = false;
651
         else if (!folded_length(range_of(value_type, 0), &count))
3,596✔
652
            known_elem_count = false;
289✔
653
      }
654
      else if (check_scalar_elem)
37,227✔
655
         bounds_check_scalar(value, elem, NULL);
33,957✔
656
      else if (check_array_elem)
3,270✔
657
         bounds_check_array_element(value, elem);
2,229✔
658

659
      switch (akind) {
43,703✔
660
      case A_NAMED:
1,632✔
661
         {
662
            tree_t name = tree_name(a);
1,632✔
663
            if (!bounds_check_index(name, index_type, dir,
1,632✔
664
                                    "aggregate choice", low, high))
665
               known_elem_count = false;
4✔
666
            if (folded_int(name, &ilow))
1,632✔
667
               ihigh = ilow;
1,628✔
668
            else
669
               known_elem_count = false;
670
         }
671
         break;
672

673
      case A_RANGE:
876✔
674
      case A_SLICE:
675
         {
676
            tree_t r = tree_range(a, 0);
876✔
677
            const range_kind_t rkind = tree_subkind(r);
876✔
678
            if (rkind == RANGE_TO || rkind == RANGE_DOWNTO) {
876✔
679
               tree_t left = tree_left(r), right = tree_right(r);
688✔
680

681
               int64_t ileft, iright;
688✔
682
               if (folded_int(left, &ileft) && folded_int(right, &iright)) {
688✔
683
                  ilow = (rkind == RANGE_TO ? ileft : iright);
495✔
684
                  ihigh = (rkind == RANGE_TO ? iright : ileft);
495✔
685

686
                  // Cannot check either index unless both are known
687
                  // since the range may be null
688
                  if (ilow <= ihigh) {
495✔
689
                     if (!bounds_check_index(left, index_type, rkind,
469✔
690
                                             "aggregate choice", low, high))
691
                        known_elem_count = false;
2✔
692
                     if (!bounds_check_index(right, index_type, rkind,
469✔
693
                                             "aggregate choice", low, high))
694
                        known_elem_count = false;
2✔
695
                  }
696
                  else
697
                     known_elem_count = false;
698
               }
699
               else
700
                  known_elem_count = false;
701

702
               if (count > 1 && known_elem_count && ihigh - ilow + 1 != count)
688✔
703
                  bounds_error(a, "discrete range has %"PRIi64" elements but "
2✔
704
                               "length of expression is %"PRIi64,
705
                               ihigh - ilow + 1, count);
706
               else if (unconstrained && akind == A_SLICE && count > 1) {
686✔
707
                  // VHDL-2008 range association determines index
708
                  // direction for unconstrained aggregate
UNCOV
709
                  assert(standard() >= STD_08);
×
710
                  dir = rkind;
711
               }
712
            }
713
            else
714
               known_elem_count = false;
715
         }
716
         break;
717

718
      case A_OTHERS:
1,792✔
719
         known_elem_count = false;
1,792✔
720
         break;
1,792✔
721

722
      case A_POS:
39,403✔
723
      case A_CONCAT:
724
         if (dir == RANGE_TO) {
39,403✔
725
            ilow = low + next_pos;
38,480✔
726
            ihigh = ilow + count - 1;
38,480✔
727
         }
728
         else {
729
            ihigh = high - next_pos;
923✔
730
            ilow = ihigh - count + 1;
923✔
731
         }
732

733
         next_pos += count;
39,403✔
734

735
         if ((ilow < low || ihigh > high) && known_elem_count) {
39,403✔
736
            diag_t *d = diag_new(DIAG_ERROR, tree_loc(t));
7✔
737
            diag_printf(d, "expected at most %"PRIi64" positional "
7✔
738
                        "associations in %s aggregate with index type %s "
739
                        "range ", MAX(0, high - low + 1), type_pp(type),
7✔
740
                        type_pp(index_type));
741
            format_type_range(d, index_type, dir, low, high);
7✔
742
            diag_emit(d);
7✔
743

744
            known_elem_count = false;
7✔
745
         }
746
         break;
747
      }
748

749
      if (unconstrained) {
43,703✔
750
         clow = MIN(clow, ilow);
6,550✔
751
         chigh = MAX(chigh, ihigh);
6,550✔
752
      }
753

754
      if (known_elem_count)
43,703✔
755
         bounds_cover_choice(&covered, a, index_type, ilow, ihigh);
36,019✔
756
   }
757

758
   if (known_elem_count)
9,227✔
759
      bounds_check_missing_choices(t, type, index_type, dir, clow, chigh,
4,714✔
760
                                   covered);
761

762
   bounds_free_intervals(&covered);
9,227✔
763

764
   // Check each sub-aggregate has the same length for an unconstrained
765
   // array aggregate
766

767
   if (ndims > 1) {
9,227✔
768
      int64_t length = -1;
769
      for (int i = 0; i < nassocs; i++) {
1,271✔
770
         tree_t a = tree_assoc(t, i);
958✔
771
         type_t value_type = tree_type(tree_value(a));
958✔
772

773
         if (type_is_unconstrained(value_type))
958✔
774
            continue;
4✔
775

776
         int64_t this_length;
958✔
777
         if (!folded_length(range_of(value_type, 0), &this_length))
958✔
778
            continue;
4✔
779

780
         if (length == -1)
954✔
781
            length = this_length;
309✔
782
         else if (length != this_length)
645✔
783
            bounds_error(a, "length of sub-aggregate %"PRIi64" does not match "
954✔
784
                         "expected length %"PRIi64, this_length, length);
785
      }
786
   }
787
}
788

789
static void bounds_check_index_contraints(type_t type)
25,838✔
790
{
791
   if (type_kind(type) != T_SUBTYPE || !type_has_constraint(type))
25,838✔
792
      return;
2,765✔
793

794
   tree_t c0 = type_constraint(type);
23,073✔
795

796
   const constraint_kind_t kind = tree_subkind(c0);
23,073✔
797
   if (kind != C_INDEX && kind != C_RANGE)
23,073✔
798
      return;
799

800
   // Check folded range does not violate index constraints of base type
801

802
   const int ndims = dimension_of(type);
22,718✔
803
   for (int i = 0; i < ndims; i++) {
45,871✔
804
      tree_t dim = tree_range(c0, i);
23,153✔
805

806
      const range_kind_t dir = tree_subkind(dim);
23,153✔
807
      if (dir != RANGE_TO && dir != RANGE_DOWNTO)
23,153✔
808
         continue;
2,761✔
809

810
      type_t cons = kind == C_INDEX ? index_type_of(type, i) : type_base(type);
20,392✔
811
      if (type_kind(cons) == T_GENERIC)
20,392✔
812
         continue;   // Cannot check
4✔
813

814
      tree_t bounds = range_of(cons, 0);
20,388✔
815

816
      // Only check here if range can be determined to be non-null
817

818
      if (kind == C_RANGE && type_is_real(type)) {
20,388✔
819
         double dim_low, bounds_low;
41✔
820
         double dim_high, bounds_high;
41✔
821

822
         const bool is_static =
82✔
823
            folded_bounds_real(dim, &dim_low, &dim_high)
41✔
824
            && folded_bounds_real(bounds, &bounds_low, &bounds_high);
41✔
825

826
         if (!is_static)
41✔
827
            continue;
5✔
828

829
         const bool is_null =
72✔
830
            dim_low > dim_high || bounds_low > bounds_high;
36✔
831

832
         if (is_null)
36✔
UNCOV
833
            continue;
×
834

835
         if (dim_low < bounds_low)
36✔
836
            bounds_error(dir == RANGE_TO ? tree_left(dim) : tree_right(dim),
1✔
837
                         "%s index %g violates constraint %s",
838
                         dir == RANGE_TO ? "left" : "right",
839
                         dim_low, type_pp(cons));
840

841
         if (dim_high > bounds_high)
36✔
842
            bounds_error(dir == RANGE_TO ? tree_right(dim) : tree_left(dim),
36✔
843
                         "%s index %g violates constraint %s",
844
                         dir == RANGE_TO ? "right" : "left",
845
                         dim_high, type_pp(cons));
846

847
      }
848
      else {
849
         int64_t dim_low, bounds_low;
20,347✔
850
         int64_t dim_high, bounds_high;
20,347✔
851

852
         const bool is_static =
40,694✔
853
            folded_bounds(dim, &dim_low, &dim_high)
20,347✔
854
            && folded_bounds(bounds, &bounds_low, &bounds_high);
20,347✔
855

856
         if (!is_static)
20,347✔
857
            continue;
8,396✔
858

859
         const bool is_null =
24,438✔
860
            dim_low > dim_high || bounds_low > bounds_high;
12,219✔
861

862
         if (is_null)
12,219✔
863
            continue;
268✔
864

865
         if (type_is_enum(cons)) {
11,951✔
866
            if (dim_low < bounds_low) {
631✔
867
               type_t cons_base = type_base_recur(cons);
1✔
868
               tree_t lit = type_enum_literal(cons_base, (unsigned)dim_low);
1✔
869
               bounds_error(dir == RANGE_TO ? tree_left(dim) : tree_right(dim),
1✔
870
                            "%s index %s violates constraint %s",
871
                            dir == RANGE_TO ? "left" : "right",
872
                            istr(tree_ident(lit)), type_pp(cons));
873
            }
874

875
            if (dim_high > bounds_high) {
631✔
876
               type_t cons_base = type_base_recur(cons);
2✔
877
               tree_t lit = type_enum_literal(cons_base, (unsigned)dim_high);
2✔
878
               bounds_error(dir == RANGE_TO ? tree_right(dim) : tree_left(dim),
2✔
879
                            "%s index %s violates constraint %s",
880
                            dir == RANGE_TO ? "right" : "left",
881
                            istr(tree_ident(lit)), type_pp(cons));
882
            }
883
         }
884
         else if (dim_high > bounds_high)
11,320✔
885
            bounds_error(dir == RANGE_TO ? tree_right(dim) : tree_left(dim),
2✔
886
                         "%s index %"PRIi64" violates constraint %s",
887
                         dir == RANGE_TO ? "right" : "left",
888
                         dim_high, type_pp(cons));
889
         else if (dim_low < bounds_low)
11,318✔
890
            bounds_error(dir == RANGE_TO ? tree_left(dim) : tree_right(dim),
11,952✔
891
                         "%s index %"PRIi64" violates constraint %s",
892
                         dir == RANGE_TO ? "left" : "right",
893
                         dim_low, type_pp(cons));
894
      }
895
   }
896
}
897

898
static void bounds_check_assignment(tree_t target, tree_t value)
62,895✔
899
{
900
   type_t target_type = tree_type(target);
62,895✔
901

902
   if (type_is_scalar(target_type))
62,895✔
903
      bounds_check_scalar(value, target_type, target);
36,594✔
904
   else if (type_is_array(target_type))
26,301✔
905
      bounds_check_array(value, target_type, target);
21,003✔
906
}
62,895✔
907

908
static void bounds_check_object_decl(tree_t t)
32,249✔
909
{
910
   if (tree_has_value(t))
32,249✔
911
      bounds_check_assignment(t, tree_value(t));
13,210✔
912

913
   type_t type = tree_type(t);
32,249✔
914
   if (is_anonymous_subtype(type))
32,249✔
915
      bounds_check_index_contraints(type);
12,604✔
916
}
32,249✔
917

918
static void bounds_check_alias_decl(tree_t t)
3,279✔
919
{
920
   if (!tree_has_type(t))
3,279✔
921
      return;   // Alias declaration without subtype indication
922

923
   if (tree_has_value(t))
3,057✔
924
      bounds_check_assignment(t, tree_value(t));
3,057✔
925

926
   type_t type = tree_type(t);
3,057✔
927
   if (is_anonymous_subtype(type))
3,057✔
928
      bounds_check_index_contraints(type);
785✔
929
}
930

931
static void bounds_check_elem_constraint(tree_t t)
743✔
932
{
933
   type_t type = tree_type(t);
743✔
934
   if (is_anonymous_subtype(type))
743✔
935
      bounds_check_index_contraints(type);
743✔
936
}
743✔
937

938
static void bounds_check_type_decl(tree_t t)
5,673✔
939
{
940
   type_t type = tree_type(t);
5,673✔
941

942
   if (type_is_record(type)) {
5,673✔
943
      const int nfields = type_fields(type);
1,534✔
944
      for (int i = 0; i < nfields; i++) {
6,189✔
945
         type_t ft = tree_type(type_field(type, i));
4,655✔
946
         if (is_anonymous_subtype(ft))
4,655✔
947
            bounds_check_index_contraints(ft);
916✔
948
      }
949
   }
950
   else if (type_is_array(type)) {
4,139✔
951
      bounds_check_index_contraints(type);
3,037✔
952

953
      type_t elem = type_elem(type);
3,037✔
954
      if (is_anonymous_subtype(elem))
3,037✔
955
         bounds_check_index_contraints(elem);
217✔
956
   }
957
   else if (type_is_scalar(type)) {
1,102✔
958
      int64_t low, high;
638✔
959
      if (folded_bounds(range_of(type, 0), &low, &high) && low > high)
638✔
960
         warn_at(tree_loc(t), "type %s has null range", type_pp(type));
1✔
961
   }
962
}
5,673✔
963

964
static void bounds_check_subtype_decl(tree_t t)
1,772✔
965
{
966
   bounds_check_index_contraints(tree_type(t));
1,772✔
967
}
1,772✔
968

969
static void bounds_check_interface_decl(tree_t t)
133,330✔
970
{
971
   const class_t class = tree_class(t);
133,330✔
972
   if (class == C_FUNCTION || class == C_PROCEDURE || class == C_PACKAGE)
133,330✔
973
      return;
974

975
   const port_mode_t mode = tree_subkind(t);
131,025✔
976
   if (mode != PORT_ARRAY_VIEW && mode != PORT_RECORD_VIEW && tree_has_value(t))
131,025✔
977
      bounds_check_assignment(t, tree_value(t));
7,818✔
978

979
   type_t type = tree_type(t);
131,025✔
980
   if (is_anonymous_subtype(type))
131,025✔
981
      bounds_check_index_contraints(type);
5,764✔
982
}
983

984
static void bounds_check_signal_assign(tree_t t)
9,912✔
985
{
986
   int64_t last_delay = 0;
9,912✔
987
   tree_t target = tree_target(t);
9,912✔
988

989
   const int nwaves = tree_waveforms(t);
9,912✔
990
   for (int i = 0; i < nwaves; i++) {
20,128✔
991
      tree_t w = tree_waveform(t, i);
10,216✔
992

993
      if (tree_has_value(w))
10,216✔
994
         bounds_check_assignment(target, tree_value(w));
10,184✔
995

996
      int64_t delay = 0;
10,216✔
997
      bool delay_is_known = true;
10,216✔
998
      const bool has_delay = tree_has_delay(w);
10,216✔
999

1000
      if (has_delay) {
10,216✔
1001
         delay_is_known = folded_int(tree_delay(w), &delay);
1,163✔
1002
         if (delay_is_known && delay < 0)
1,163✔
1003
            bounds_error(tree_delay(w), "assignment delay may not be "
4✔
1004
                         "negative");
1005
      }
1006

1007
      if (i == 0) {
10,216✔
1008
         int64_t rlimit;
9,904✔
1009
         if (tree_has_reject(t) && folded_int(tree_reject(t), &rlimit)) {
9,904✔
1010
            if ((rlimit < 0) && (delay >= 0))
788✔
1011
               bounds_error(tree_reject(t), "rejection limit may not be "
1✔
1012
                            "negative");
1013

1014
            if (rlimit > delay)
788✔
1015
               bounds_error(tree_reject(t), "rejection limit may not be "
9,904✔
1016
                            "greater than first assignment delay");
1017
         }
1018
      } else if (delay_is_known && delay <= last_delay)
312✔
1019
         bounds_error(has_delay ? tree_delay(w) : w, "assignment delays "
5✔
1020
                      "must be in ascending time order");
1021

1022
      // even if the delay isn't known, it has to be at least zero
1023
      last_delay = delay;
10,216✔
1024
   }
1025
}
9,912✔
1026

1027
static void bounds_check_var_assign(tree_t t)
22,498✔
1028
{
1029
   bounds_check_assignment(tree_target(t), tree_value(t));
22,498✔
1030
}
22,498✔
1031

1032
static void bounds_check_scalar_case(tree_t t, type_t type, bool matching)
539✔
1033
{
1034
   // Check that the full range of the type is covered
1035

1036
   tree_t type_r = range_of(type, 0);
539✔
1037

1038
   int64_t tlow = INT64_MIN, thigh = INT64_MAX;
539✔
1039
   while (!folded_bounds(type_r, &tlow, &thigh)
539✔
1040
          && type_kind(type) == T_SUBTYPE) {
540✔
1041
      // LRM 08 section 10.9: if the case expression does not have a
1042
      // locally static subtype then the choices must cover every value
1043
      // of the base type
1044
      type = type_base(type);
1✔
1045
      type_r = range_of(type, 0);
1✔
1046
   }
1047

1048
   const range_kind_t tdir = tree_subkind(type_r);
539✔
1049

1050
   bool have_others = false;
539✔
1051
   interval_t *covered = NULL;
539✔
1052

1053
   const int nstmts = tree_stmts(t);
539✔
1054
   for (int i = 0; i < nstmts; i++) {
3,142✔
1055
      tree_t alt = tree_stmt(t, i);
2,603✔
1056

1057
      const int nassocs = tree_assocs(alt);
2,603✔
1058
      for (int j = 0; j < nassocs; j++) {
6,094✔
1059
         tree_t a = tree_assoc(alt, j);
3,491✔
1060

1061
         int64_t low = INT64_MIN, high = INT64_MAX;
3,491✔
1062
         switch (tree_subkind(a)) {
3,491✔
1063
         case A_OTHERS:
398✔
1064
            have_others = true;
398✔
1065
            continue;
398✔
1066

1067
         case A_NAMED:
3,048✔
1068
            {
1069
               int64_t pos;
3,048✔
1070
               tree_t name = tree_name(a);
3,048✔
1071
               if (!bounds_check_index(name, type, tdir, "case choice",
3,048✔
1072
                                       tlow, thigh))
1073
                  have_others = true;
1074
               else if (matching && folded_int(name, &pos) && pos == 8)
3,047✔
1075
                  have_others = true;    // Has a '-' choice
1076
               else
1077
                  low = high = assume_int(tree_name(a));
3,039✔
1078
            }
1079
            break;
3,048✔
1080

1081
         case A_RANGE:
45✔
1082
            {
1083
               tree_t r = tree_range(a, 0);
45✔
1084
               const range_kind_t dir = tree_subkind(r);
45✔
1085

1086
               if (dir == RANGE_EXPR)
45✔
UNCOV
1087
                  fatal_at(tree_loc(r), "locally static range not folded");
×
1088

1089
               tree_t left = tree_left(r);
45✔
1090
               tree_t right = tree_right(r);
45✔
1091

1092
               if (!bounds_check_index(left, type, dir, "case choice",
45✔
1093
                                       tlow, thigh))
1094
                  have_others = true;
1✔
1095
               if (!bounds_check_index(right, type, dir, "case choice",
45✔
1096
                                       tlow, thigh))
UNCOV
1097
                  have_others = true;
×
1098

1099
               low = assume_int(dir == RANGE_TO ? left : right);
48✔
1100
               high = assume_int(dir == RANGE_TO ? right : left);
45✔
1101
            }
1102
            break;
45✔
1103
         }
1104

1105
         if (!have_others)
3,093✔
1106
            bounds_cover_choice(&covered, a, type, low, high);
3,082✔
1107
      }
1108
   }
1109

1110
   if (!have_others)
539✔
1111
      bounds_check_missing_choices(t, type, NULL, direction_of(type, 0),
131✔
1112
                                   tlow, thigh, covered);
1113

1114
   bounds_free_intervals(&covered);
539✔
1115
}
539✔
1116

1117
static void bounds_check_duplicate_choice(tree_t old, tree_t new, int length)
2✔
1118
{
1119
   for (int i = 0; i < length; i++) {
13✔
1120
      if (get_case_choice_char(old, i) != get_case_choice_char(new, i))
11✔
1121
         return;
1122
   }
1123

1124
   diag_t *d = diag_new(DIAG_ERROR, tree_loc(new));
2✔
1125
   diag_printf(d, "duplicate choice in case statement");
2✔
1126
   diag_hint(d, tree_loc(new), "repeated here");
2✔
1127
   diag_hint(d, tree_loc(old), "previous choice for this value");
2✔
1128
   diag_hint(d, NULL, "each value of the subtype of the expression must be "
2✔
1129
             "represented once and only once in the set of choices");
1130
   diag_lrm(d, STD_93, "8.8");
2✔
1131
   diag_emit(d);
2✔
1132
}
1133

1134
static void bounds_check_array_case(tree_t t, type_t type, bool matching)
174✔
1135
{
1136
   type_t elem = type_elem(type);
174✔
1137
   assert(type_is_enum(elem));
174✔
1138

1139
   // Calculate how many values each element has
1140
   int64_t elemsz = INT64_MAX;
174✔
1141
   while (!folded_length(range_of(elem, 0), &elemsz)
348✔
1142
          && type_kind(elem) == T_SUBTYPE)
348✔
UNCOV
1143
      elem = type_base(elem);
×
1144

1145
   int64_t expect = -1, length = -1;
174✔
1146

1147
   const bool known_length =
348✔
1148
      !type_is_unconstrained(type) && folded_length(range_of(type, 0), &length);
174✔
1149

1150
   if (known_length && !ipow_safe(elemsz, length, &expect))
174✔
1151
      expect = INT64_MAX;   // Overflow
5✔
1152

1153
   int nchoices = 0;
174✔
1154
   const int nstmts = tree_stmts(t);
174✔
1155
   for (int i = 0; i < nstmts; i++)
1,199✔
1156
      nchoices += tree_assocs(tree_stmt(t, i));
1,025✔
1157

1158
   int64_t have = 0;
174✔
1159
   int64_t *hashes LOCAL = xmalloc_array(nchoices, sizeof(int64_t));
348✔
1160
   tree_t *choices LOCAL = xmalloc_array(nchoices, sizeof(tree_t));
348✔
1161
   int hptr = 0;
174✔
1162

1163
   for (int i = 0; i < nstmts; i++) {
1,196✔
1164
      tree_t alt = tree_stmt(t, i);
1,023✔
1165

1166
      const int nassocs = tree_assocs(alt);
1,023✔
1167
      for (int j = 0; j < nassocs; j++, hptr++) {
2,090✔
1168
         tree_t a = tree_assoc(alt, j);
1,068✔
1169
         hashes[hptr] = INT64_MAX;
1,068✔
1170
         choices[hptr] = NULL;
1,068✔
1171

1172
         if (tree_subkind(a) == A_OTHERS) {
1,068✔
1173
            have = expect;
152✔
1174
            continue;
152✔
1175
         }
1176

1177
         assert(tree_subkind(a) == A_NAMED);
916✔
1178
         tree_t name = choices[hptr] = tree_name(a);
916✔
1179

1180
         int64_t covered = 1, pos;
916✔
1181
         if (matching && tree_kind(name) == T_STRING) {
916✔
1182
            const int nchars = tree_chars(name);
88✔
1183
            for (int i = 0; i < nchars; i++) {
384✔
1184
               if (folded_int(tree_char(name, i), &pos) && pos == 8)
296✔
1185
                  covered *= 9;    // Has a '-' choice
114✔
1186
            }
1187
         }
1188
         have += covered;
916✔
1189

1190
         type_t choice_type = tree_type(name);
916✔
1191
         if (type_is_unconstrained(choice_type))
916✔
UNCOV
1192
            continue;
×
1193

1194
         int64_t choice_length;
916✔
1195
         if (folded_length(range_of(choice_type, 0), &choice_length)) {
916✔
1196
            if (length == -1) {
916✔
1197
               length = choice_length;
41✔
1198
               if (!ipow_safe(elemsz, length, &expect))
41✔
1199
                  expect = INT64_MAX;
4✔
1200
            }
1201
            else if (choice_length != length) {
875✔
1202
               diag_t *d = diag_new(DIAG_ERROR, tree_loc(name));
1✔
1203
               diag_printf(d, "expected case choice to have length %"PRIi64
1✔
1204
                           " but is %"PRIi64, length, choice_length);
1205
               diag_hint(d, NULL, "the values of all choices for a case "
1✔
1206
                         "expression with one-dimensional character array "
1207
                         "type must have the same length");
1208
               diag_lrm(d, STD_08, "10.9");
1✔
1209
               diag_emit(d);
1✔
1210
               return;
1✔
1211
            }
1212

1213
            hashes[hptr] = encode_case_choice(name, choice_length, 0);
915✔
1214

1215
            for (int k = 0; k < hptr; k++) {
5,300✔
1216
               if (hashes[k] == INT64_MAX)
4,385✔
UNCOV
1217
                  continue;
×
1218
               else if (hashes[hptr] == hashes[k]) {
4,385✔
1219
                  tree_t old = choices[k];
2✔
1220
                  bounds_check_duplicate_choice(old, name, choice_length);
2✔
1221
               }
1222
            }
1223
         }
1224
      }
1225
   }
1226

1227
   if (have < expect && expect != -1) {
173✔
1228
      const loc_t *loc = tree_loc(tree_value(t));
6✔
1229
      diag_t *d = pedantic_diag(loc);
6✔
1230
      if (d != NULL) {
6✔
1231
         diag_printf(d, "choices cover only %"PRIi64" of ", have);
6✔
1232
         if (expect > 100000)
6✔
1233
            diag_printf(d, "%"PRIi64" ** %"PRIi64, elemsz, length);
3✔
1234
         else
1235
            diag_printf(d, "%"PRIi64, expect);
3✔
1236
         diag_printf(d, " possible values");
6✔
1237

1238
         diag_hint(d, loc, "expression has %"PRIi64" elements of type %s, "
6✔
1239
                   "each of which has %"PRIi64" possible values",
1240
                   length, type_pp(type_elem(type)), elemsz);
1241

1242
         if (!known_length)
6✔
1243
            diag_hint(d, NULL, "the case expression subtype is not locally "
2✔
1244
                      "static so the length was derived from the choices");
1245

1246
         diag_emit(d);
6✔
1247
      }
1248
   }
1249
}
1250

1251
static void bounds_check_case(tree_t t)
666✔
1252
{
1253
   type_t type = tree_type(tree_value(t));
666✔
1254

1255
   if (type_is_scalar(type))
666✔
1256
      bounds_check_scalar_case(t, type, false);
531✔
1257
   else if (type_is_array(type))
135✔
1258
      bounds_check_array_case(t, type, false);
135✔
1259
}
666✔
1260

1261
static void bounds_check_match_case(tree_t t)
47✔
1262
{
1263
   type_t type = tree_type(tree_value(t)), elem = type_elem_recur(type);
47✔
1264

1265
   const bool matching = type_eq(elem, ieee_type(IEEE_STD_ULOGIC));
47✔
1266

1267
   if (type_is_scalar(type))
47✔
1268
      bounds_check_scalar_case(t, type, matching);
8✔
1269
   else if (type_is_array(type))
39✔
1270
      bounds_check_array_case(t, type, matching);
39✔
1271
}
47✔
1272

1273
static void bounds_check_conv_integer(tree_t value, type_t from, type_t to)
200✔
1274
{
1275
   int64_t ival = 0;
200✔
1276
   double rval = 0.0;
200✔
1277
   bool folded = false;
200✔
1278
   if (type_is_real(from)) {
200✔
1279
      folded = folded_real(value, &rval);
135✔
1280
      ival = (int64_t)(rval + 0.5);
135✔
1281
   }
1282
   else if (type_is_integer(from))
65✔
1283
      folded = folded_int(value, &ival);
65✔
1284

1285
   if (folded) {
200✔
1286
      int64_t b_low, b_high;
2✔
1287
      if (folded_bounds(range_of(to, 0), &b_low, &b_high)
2✔
1288
          && (ival < b_low || ival > b_high)) {
2✔
1289
         char *argstr LOCAL = type_is_real(from)
2✔
1290
            ? xasprintf("%lg", rval) : xasprintf("%"PRIi64, ival);
2✔
1291
         bounds_error(value, "type conversion argument %s out of "
2✔
1292
                      "bounds %"PRIi64" to %"PRIi64, argstr, b_low, b_high);
1293
      }
1294
   }
1295
}
200✔
1296

1297
static void bounds_check_conv_array(tree_t value, type_t from, type_t to)
2,756✔
1298
{
1299
   const int ndims = dimension_of(to);
2,756✔
1300
   assert(ndims == dimension_of(from));
2,756✔
1301

1302
   const bool to_constrained = !type_is_unconstrained(to);
2,756✔
1303
   const bool from_constrained = !type_is_unconstrained(from);
2,756✔
1304

1305
   if (to_constrained && from_constrained) {
2,756✔
1306
      for (int i = 0; i < ndims; i++) {
58✔
1307
         tree_t r_to = range_of(to, i);
29✔
1308
         tree_t r_from = range_of(from, i);
29✔
1309

1310
         int64_t to_length;
29✔
1311
         if (!folded_length(r_to, &to_length))
29✔
1312
            continue;
8✔
1313

1314
         int64_t from_length;
25✔
1315
         if (!folded_length(r_from, &from_length))
25✔
1316
            continue;
4✔
1317

1318
         if (to_length != from_length)
21✔
1319
            bounds_error(value, "length of type conversion argument %"PRIi64
21✔
1320
                         " does not match expected length %"PRIi64
1321
                         " for constrained array subtype %s",
1322
                         from_length, to_length, type_pp(to));
1323
      }
1324
   }
1325
   else if (!to_constrained && from_constrained) {
2,727✔
1326
      for (int i = 0; i < ndims; i++) {
1,206✔
1327
         type_t index_type = index_type_of(to, i);
603✔
1328
         tree_t r_to = range_of(index_type, i);
603✔
1329
         tree_t r_from = range_of(from, i);
603✔
1330

1331
         if (tree_subkind(r_from) == RANGE_EXPR)
603✔
1332
            continue;
497✔
1333

1334
         int64_t low, high;
487✔
1335
         if (!folded_bounds(r_to, &low, &high))
487✔
UNCOV
1336
            continue;
×
1337

1338
         int64_t f_low, f_high;
487✔
1339
         if (!folded_bounds(r_from, &f_low, &f_high))
487✔
1340
            continue;
380✔
1341
         else if (f_low > f_high)
107✔
1342
            continue;  // Null range
1✔
1343

1344
         int64_t folded = 0;
106✔
1345
         const char *error = NULL;
106✔
1346
         if (!index_in_range(tree_left(r_from), low, high, &folded))
106✔
1347
            error = "left";
1348
         else if (!index_in_range(tree_right(r_from), low, high, &folded))
106✔
1349
            error = "right";
1350

1351
         if (error) {
1✔
1352
            diag_t *d = diag_new(DIAG_ERROR, tree_loc(value));
1✔
1353
            diag_printf(d, "array ");
1✔
1354
            if (tree_kind(value) == T_REF)
1✔
1355
               diag_printf(d, "%s ", istr(tree_ident(value)));
1✔
1356
            diag_printf(d, "%s bound ", error);
1✔
1357
            to_string(diag_text_buf(d), index_type, folded);
1✔
1358
            diag_printf(d, " violates %s index constraint ", type_pp(to));
1✔
1359
            format_type_range(d, index_type, tree_subkind(r_to), low, high);
1✔
1360
            diag_emit(d);
1✔
1361
         }
1362
      }
1363
   }
1364
}
2,756✔
1365

1366
static void bounds_check_type_conv(tree_t t)
3,202✔
1367
{
1368
   tree_t value = tree_value(t);
3,202✔
1369

1370
   type_t from = tree_type(value);
3,202✔
1371
   type_t to   = tree_type(t);
3,202✔
1372

1373
   if (type_is_integer(to))
3,202✔
1374
      bounds_check_conv_integer(value, from, to);
200✔
1375
   else if (type_is_array(to))
3,002✔
1376
      bounds_check_conv_array(value, from, to);
2,756✔
1377
}
3,202✔
1378

1379
static void bounds_check_attr_ref(tree_t t)
29,927✔
1380
{
1381
   switch (tree_subkind(t)) {
29,927✔
1382
   case ATTR_LENGTH:
24,988✔
1383
   case ATTR_LOW:
1384
   case ATTR_HIGH:
1385
   case ATTR_LEFT:
1386
   case ATTR_RIGHT:
1387
   case ATTR_RANGE:
1388
   case ATTR_REVERSE_RANGE:
1389
      if (tree_params(t) > 0) {
24,988✔
1390
         type_t type = tree_type(tree_name(t));
106✔
1391
         if (type_is_array(type)) {
106✔
1392
            tree_t dim_tree = tree_value(tree_param(t, 0));
106✔
1393

1394
            int64_t dim;
106✔
1395
            if (!folded_int(dim_tree, &dim))
106✔
UNCOV
1396
               bounds_error(dim_tree, "dimension is not constant");
×
1397
            else if (dim < 1 || dim > dimension_of(type))
106✔
1398
               bounds_error(dim_tree, "invalid dimension %"PRIi64" for type %s",
106✔
1399
                            dim, type_pp(type));
1400
         }
1401
      }
1402
      break;
1403

1404
   default:
1405
      break;
1406
   }
1407
}
29,927✔
1408

1409
static void bounds_check_wait(tree_t t)
16,807✔
1410
{
1411
   int64_t delay = 0;
16,807✔
1412
   if (tree_has_delay(t) && folded_int(tree_delay(t), &delay) && delay < 0)
16,807✔
1413
      bounds_error(tree_delay(t), "wait timeout may not be negative");
16,807✔
1414
}
16,807✔
1415

1416
static void bounds_check_return(tree_t t)
18,829✔
1417
{
1418
   if (!tree_has_value(t))
18,829✔
1419
      return;
1420

1421
   tree_t value = tree_value(t);
18,485✔
1422

1423
   type_t type = tree_type(t);
18,485✔
1424
   if (type_is_scalar(type))
18,485✔
1425
      bounds_check_scalar(value, type, NULL);
8,119✔
1426
   else if (type_is_array(type))
10,366✔
1427
      bounds_check_array(value, type, NULL);
9,007✔
1428
}
1429

1430
static void bounds_check_generic_map(tree_t t, tree_t unit)
2,502✔
1431
{
1432
   const int ngenmaps = tree_genmaps(t);
2,502✔
1433
   for (int i = 0; i < ngenmaps; i++) {
5,265✔
1434
      tree_t m = tree_genmap(t, i);
2,763✔
1435
      assert(tree_subkind(m) == P_POS);
2,763✔
1436

1437
      tree_t g = tree_generic(unit, i);
2,763✔
1438
      if (tree_class(g) == C_CONSTANT)
2,763✔
1439
         bounds_check_assignment(g, tree_value(m));
1,666✔
1440
   }
1441
}
2,502✔
1442

1443
static void bounds_check_port_map(tree_t t, tree_t unit)
2,159✔
1444
{
1445
   const int nparams = tree_params(t);
2,159✔
1446
   for (int i = 0; i < nparams; i++) {
6,788✔
1447
      tree_t m = tree_param(t, i);
4,629✔
1448

1449
      tree_t value = tree_value(m);
4,629✔
1450
      switch (tree_kind(value)) {
4,629✔
1451
      case T_OPEN:
49✔
1452
         continue;
49✔
1453
      case T_INERTIAL:
46✔
1454
         value = tree_value(value);
46✔
1455
         break;
46✔
1456
      default:
1457
         break;
1458
      }
1459

1460
      tree_t formal = NULL;
4,580✔
1461
      switch (tree_subkind(m)) {
4,580✔
1462
      case P_POS:
1,788✔
1463
         formal = tree_port(unit, tree_pos(m));
1,788✔
1464
         break;
1,788✔
1465
      case P_NAMED:
2,792✔
1466
         formal = tree_name(m);
2,792✔
1467
         break;
2,792✔
1468
      }
1469

1470
      switch (tree_kind(formal)) {
4,580✔
1471
      case T_TYPE_CONV:
118✔
1472
      case T_CONV_FUNC:
1473
         continue;   // Ignore for now
118✔
1474
      default:
4,462✔
1475
         bounds_check_assignment(formal, value);
4,462✔
1476
         break;
4,462✔
1477
      }
1478
   }
1479
}
2,159✔
1480

1481
static tree_t bounds_visit_fn(tree_t t, void *context)
1,854,330✔
1482
{
1483
   switch (tree_kind(t)) {
1,854,330✔
1484
   case T_PCALL:
108,091✔
1485
   case T_FCALL:
1486
      bounds_check_call_args(t);
108,091✔
1487
      break;
108,091✔
1488
   case T_ARRAY_REF:
18,560✔
1489
      bounds_check_array_ref(t);
18,560✔
1490
      break;
18,560✔
1491
   case T_ARRAY_SLICE:
3,317✔
1492
      bounds_check_array_slice(t);
3,317✔
1493
      break;
3,317✔
1494
   case T_AGGREGATE:
14,074✔
1495
      bounds_check_aggregate(t);
14,074✔
1496
      break;
14,074✔
1497
   case T_SIGNAL_DECL:
32,249✔
1498
   case T_CONST_DECL:
1499
   case T_VAR_DECL:
1500
      bounds_check_object_decl(t);
32,249✔
1501
      break;
32,249✔
1502
   case T_PORT_DECL:
133,330✔
1503
   case T_PARAM_DECL:
1504
   case T_GENERIC_DECL:
1505
      bounds_check_interface_decl(t);
133,330✔
1506
      break;
133,330✔
1507
   case T_ALIAS:
3,279✔
1508
      bounds_check_alias_decl(t);
3,279✔
1509
      break;
3,279✔
1510
   case T_SIGNAL_ASSIGN:
9,912✔
1511
      bounds_check_signal_assign(t);
9,912✔
1512
      break;
9,912✔
1513
   case T_VAR_ASSIGN:
22,498✔
1514
      bounds_check_var_assign(t);
22,498✔
1515
      break;
22,498✔
1516
   case T_CASE:
666✔
1517
      bounds_check_case(t);
666✔
1518
      break;
666✔
1519
   case T_MATCH_CASE:
47✔
1520
      bounds_check_match_case(t);
47✔
1521
      break;
47✔
1522
   case T_STRING:
29,992✔
1523
      bounds_check_string_literal(t);
29,992✔
1524
      break;
29,992✔
1525
   case T_TYPE_CONV:
3,202✔
1526
      bounds_check_type_conv(t);
3,202✔
1527
      break;
3,202✔
1528
   case T_ATTR_REF:
29,927✔
1529
      bounds_check_attr_ref(t);
29,927✔
1530
      break;
29,927✔
1531
   case T_WAIT:
16,807✔
1532
      bounds_check_wait(t);
16,807✔
1533
      break;
16,807✔
1534
   case T_RETURN:
18,829✔
1535
      bounds_check_return(t);
18,829✔
1536
      break;
18,829✔
1537
   case T_ELEM_CONSTRAINT:
743✔
1538
      bounds_check_elem_constraint(t);
743✔
1539
      break;
743✔
1540
   case T_TYPE_DECL:
5,673✔
1541
      bounds_check_type_decl(t);
5,673✔
1542
      break;
5,673✔
1543
   case T_SUBTYPE_DECL:
1,772✔
1544
      bounds_check_subtype_decl(t);
1,772✔
1545
      break;
1,772✔
1546
   case T_BLOCK:
420✔
1547
      bounds_check_generic_map(t, t);
420✔
1548
      bounds_check_port_map(t, t);
420✔
1549
      break;
420✔
1550
   case T_INSTANCE:
1,739✔
1551
      {
1552
         tree_t primary = primary_unit_of(tree_ref(t));
1,739✔
1553
         bounds_check_generic_map(t, primary);
1,739✔
1554
         bounds_check_port_map(t, primary);
1,739✔
1555
      }
1556
      break;
1,739✔
1557
   case T_PACK_INST:
343✔
1558
      bounds_check_generic_map(t, tree_ref(t));
343✔
1559
      break;
343✔
1560
   default:
1561
      break;
1562
   }
1563

1564
   return t;
1,854,330✔
1565
}
1566

1567
void bounds_check(tree_t top)
15,118✔
1568
{
1569
   tree_rewrite(top, NULL, bounds_visit_fn, NULL, NULL);
15,118✔
1570
}
15,118✔
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

© 2026 Coveralls, Inc