Use the existing array-aware qualifier helper when propagating qualifiers from a const or volatile aggregate to a selected field. This keeps address-of array members from spuriously warning while preserving warnings for discarded qualifiers and read-only writes. Add regression coverage for pointer-to-array returns, array decay, and writes through const array members.
Unified · Split
| @@ -6184,7 +6184,8 @@ special_math_val: · 6183 unmodified lines | |||
| 6184 | gen_op('+'); | 6184 | gen_op('+'); |
| 6185 | /* change type to field type, and set to lvalue */ | 6185 | /* change type to field type, and set to lvalue */ |
| 6186 | vtop->type = s->type; | 6186 | vtop->type = s->type; |
| 6187 | vtop->type.t |= qualifiers; | 6187 | if (qualifiers) |
| 6188 | parse_btype_qualify(&vtop->type, qualifiers); | ||
| 6188 | /* an array is never an lvalue */ | 6189 | /* an array is never an lvalue */ |
| 6189 | if (!(vtop->type.t & VT_ARRAY)) { | 6190 | if (!(vtop->type.t & VT_ARRAY)) { |
| 6190 | vtop->r |= VT_LVAL; | 6191 | vtop->r |= VT_LVAL; |
| @@ -551,4 +551,114 @@ int main(int argc, char **argv) · 550 unmodified lines | |||
| 551 | 551 | ||
| 552 | } | 552 | } |
| 553 | 553 | ||
| 554 | #elif defined test_const_array_member_addr_ok | ||
| 555 | |||
| 556 | typedef int int_array[1]; | ||
| 557 | typedef struct { int_array arr; } my_struct; | ||
| 558 | |||
| 559 | int_array const *get_array(const my_struct *s) | ||
| 560 | { | ||
| 561 | return &(s->arr); | ||
| 562 | } | ||
| 563 | |||
| 564 | #elif defined test_const_array_member_decay_ok | ||
| 565 | |||
| 566 | typedef int int_array[1]; | ||
| 567 | typedef struct { int_array arr; } my_struct; | ||
| 568 | |||
| 569 | const int *good_decay(const my_struct *s) | ||
| 570 | { | ||
| 571 | return s->arr; | ||
| 572 | } | ||
| 573 | |||
| 574 | #elif defined test_const_array_member_addr_bad | ||
| 575 | |||
| 576 | typedef int int_array[1]; | ||
| 577 | typedef struct { int_array arr; } my_struct; | ||
| 578 | |||
| 579 | int_array *bad_array_addr(const my_struct *s) | ||
| 580 | { | ||
| 581 | return &(s->arr); | ||
| 582 | } | ||
| 583 | |||
| 584 | #elif defined test_const_array_member_decay_bad | ||
| 585 | |||
| 586 | typedef int int_array[1]; | ||
| 587 | typedef struct { int_array arr; } my_struct; | ||
| 588 | |||
| 589 | int *bad_decay(const my_struct *s) | ||
| 590 | { | ||
| 591 | return s->arr; | ||
| 592 | } | ||
| 593 | |||
| 594 | #elif defined test_const_array_member_write_bad | ||
| 595 | |||
| 596 | typedef int int_array[1]; | ||
| 597 | typedef struct { int_array arr; } my_struct; | ||
| 598 | |||
| 599 | void bad_write(const my_struct *s) | ||
| 600 | { | ||
| 601 | s->arr[0] = 1; | ||
| 602 | } | ||
| 603 | |||
| 604 | #elif defined test_const_struct_array_member_write_bad | ||
| 605 | |||
| 606 | typedef struct { int x; } inner; | ||
| 607 | typedef struct { inner arr[1]; } outer; | ||
| 608 | |||
| 609 | void bad_inner_write(const outer *s) | ||
| 610 | { | ||
| 611 | s->arr[0].x = 1; | ||
| 612 | } | ||
| 613 | |||
| 614 | #elif defined test_volatile_array_member_addr_ok | ||
| 615 | |||
| 616 | typedef int int_array[1]; | ||
| 617 | typedef struct { int_array arr; } my_struct; | ||
| 618 | |||
| 619 | int_array volatile *get_volatile_array(volatile my_struct *s) | ||
| 620 | { | ||
| 621 | return &(s->arr); | ||
| 622 | } | ||
| 623 | |||
| 624 | #elif defined test_volatile_array_member_decay_ok | ||
| 625 | |||
| 626 | typedef int int_array[1]; | ||
| 627 | typedef struct { int_array arr; } my_struct; | ||
| 628 | |||
| 629 | volatile int *good_volatile_decay(volatile my_struct *s) | ||
| 630 | { | ||
| 631 | return s->arr; | ||
| 632 | } | ||
| 633 | |||
| 634 | #elif defined test_volatile_array_member_addr_bad | ||
| 635 | |||
| 636 | typedef int int_array[1]; | ||
| 637 | typedef struct { int_array arr; } my_struct; | ||
| 638 | |||
| 639 | int_array *bad_volatile_array_addr(volatile my_struct *s) | ||
| 640 | { | ||
| 641 | return &(s->arr); | ||
| 642 | } | ||
| 643 | |||
| 644 | #elif defined test_volatile_array_member_decay_bad | ||
| 645 | |||
| 646 | typedef int int_array[1]; | ||
| 647 | typedef struct { int_array arr; } my_struct; | ||
| 648 | |||
| 649 | int *bad_volatile_decay(volatile my_struct *s) | ||
| 650 | { | ||
| 651 | return s->arr; | ||
| 652 | } | ||
| 653 | |||
| 654 | #elif defined test_volatile_array_member_write_ok | ||
| 655 | |||
| 656 | typedef int int_array[1]; | ||
| 657 | typedef struct { int_array arr; } my_struct; | ||
| 658 | |||
| 659 | void good_volatile_write(volatile my_struct *s) | ||
| 660 | { | ||
| 661 | s->arr[0] = 1; | ||
| 662 | } | ||
| 663 | |||
| 554 | #endif | 664 | #endif |
| @@ -262,3 +262,31 @@ bar 15 12 34 · 261 unmodified lines | |||
| 262 | [test_scope_3] | 262 | [test_scope_3] |
| 263 | 60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type | 263 | 60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type |
| 264 | 60_errors_and_warnings.c:549: error: initialization of incomplete type | 264 | 60_errors_and_warnings.c:549: error: initialization of incomplete type |
| 265 | |||
| 266 | [test_const_array_member_addr_ok] | ||
| 267 | |||
| 268 | [test_const_array_member_decay_ok] | ||
| 269 | |||
| 270 | [test_const_array_member_addr_bad] | ||
| 271 | 60_errors_and_warnings.c:581: warning: assignment discards qualifiers from pointer target type | ||
| 272 | |||
| 273 | [test_const_array_member_decay_bad] | ||
| 274 | 60_errors_and_warnings.c:591: warning: assignment discards qualifiers from pointer target type | ||
| 275 | |||
| 276 | [test_const_array_member_write_bad] | ||
| 277 | 60_errors_and_warnings.c:601: warning: assignment of read-only location | ||
| 278 | |||
| 279 | [test_const_struct_array_member_write_bad] | ||
| 280 | 60_errors_and_warnings.c:611: warning: assignment of read-only location | ||
| 281 | |||
| 282 | [test_volatile_array_member_addr_ok] | ||
| 283 | |||
| 284 | [test_volatile_array_member_decay_ok] | ||
| 285 | |||
| 286 | [test_volatile_array_member_addr_bad] | ||
| 287 | 60_errors_and_warnings.c:641: warning: assignment discards qualifiers from pointer target type | ||
| 288 | |||
| 289 | [test_volatile_array_member_decay_bad] | ||
| 290 | 60_errors_and_warnings.c:651: warning: assignment discards qualifiers from pointer target type | ||
| 291 | |||
| 292 | [test_volatile_array_member_write_ok] | ||