diff --git a/tests/usr.bin/xlint/lint1/expr_sizeof.c b/tests/usr.bin/xlint/lint1/expr_sizeof.c index 88b4edf987ec..313f2b2bc249 100644 --- a/tests/usr.bin/xlint/lint1/expr_sizeof.c +++ b/tests/usr.bin/xlint/lint1/expr_sizeof.c @@ -1,4 +1,4 @@ -/* $NetBSD: expr_sizeof.c,v 1.11 2023/06/30 16:39:17 rillig Exp $ */ +/* $NetBSD: expr_sizeof.c,v 1.12 2023/06/30 21:06:18 rillig Exp $ */ # 3 "expr_sizeof.c" /* @@ -152,8 +152,7 @@ anonymous_struct_and_union(void) unsigned char uc32[32]; }; } su_16_32; - /* FIXME: Must be 32, not 48. */ - /* expect+1: error: negative array dimension (-48) [20] */ + /* expect+1: error: negative array dimension (-32) [20] */ typedef int sizeof_su_16_32[-(int)sizeof(su_16_32)]; union { diff --git a/tests/usr.bin/xlint/lint1/init_braces.c b/tests/usr.bin/xlint/lint1/init_braces.c index b17ded3991ae..ceb2dad558a3 100644 --- a/tests/usr.bin/xlint/lint1/init_braces.c +++ b/tests/usr.bin/xlint/lint1/init_braces.c @@ -1,4 +1,4 @@ -/* $NetBSD: init_braces.c,v 1.4 2023/06/30 09:21:52 rillig Exp $ */ +/* $NetBSD: init_braces.c,v 1.5 2023/06/30 21:06:18 rillig Exp $ */ # 3 "init_braces.c" /* @@ -86,8 +86,6 @@ init_anonymous_struct_and_union(void) struct outer var = { /* struct outer */ { /* anonymous union */ { /* anonymous struct */ -/* FIXME: GCC and Clang both compile this initializer. */ -/* expect+1: error: type 'struct time' does not have member 'times' [101] */ .times = { .t0 = { .ns = 0, }, .t1 = { .ns = 0, }, diff --git a/tests/usr.bin/xlint/lint1/msg_102.c b/tests/usr.bin/xlint/lint1/msg_102.c index de682870b767..91c9aea2fc43 100644 --- a/tests/usr.bin/xlint/lint1/msg_102.c +++ b/tests/usr.bin/xlint/lint1/msg_102.c @@ -1,4 +1,4 @@ -/* $NetBSD: msg_102.c,v 1.5 2023/06/30 09:21:52 rillig Exp $ */ +/* $NetBSD: msg_102.c,v 1.6 2023/06/30 21:06:18 rillig Exp $ */ # 3 "msg_102.c" // Test for message: illegal use of member '%s' [102] @@ -31,14 +31,8 @@ static struct bit_fields_and_bits *b1, *b2; static inline _Bool eq(int x) { - /* - * TODO: Once this is fixed, enable lint in - * external/mit/xorg/lib/dri.old/Makefile again. - */ - if (x == 0) - /* expect+2: error: illegal use of member 'bits' [102] */ - /* expect+1: error: illegal use of member 'bits' [102] */ + /* Accessing a member from an unnamed struct member. */ return u1->bits == u2->bits; /* diff --git a/usr.bin/xlint/lint1/cgram.y b/usr.bin/xlint/lint1/cgram.y index 86589ff919bf..4ea84d93be8f 100644 --- a/usr.bin/xlint/lint1/cgram.y +++ b/usr.bin/xlint/lint1/cgram.y @@ -1,5 +1,5 @@ %{ -/* $NetBSD: cgram.y,v 1.441 2023/06/30 19:10:49 rillig Exp $ */ +/* $NetBSD: cgram.y,v 1.442 2023/06/30 21:06:18 rillig Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. @@ -35,7 +35,7 @@ #include #if defined(__RCSID) -__RCSID("$NetBSD: cgram.y,v 1.441 2023/06/30 19:10:49 rillig Exp $"); +__RCSID("$NetBSD: cgram.y,v 1.442 2023/06/30 21:06:18 rillig Exp $"); #endif #include @@ -120,14 +120,6 @@ restore_warning_flags_loc(const char *file, size_t line) #define save_warning_flags() save_warning_flags_loc(__FILE__, __LINE__) #define restore_warning_flags() restore_warning_flags_loc(__FILE__, __LINE__) -/* unbind the anonymous struct members from the struct */ -static void -anonymize(sym_t *s) -{ - for ( ; s != NULL; s = s->s_next) - s->u.s_member.sm_sou_type = NULL; -} - static bool is_either(const char *s, const char *a, const char *b) { @@ -968,11 +960,9 @@ struct_declaration: /* C99 6.7.2.1 */ if (!allow_c11 && !allow_gcc) /* anonymous struct/union members is a C11 feature */ warning(49); - if (is_struct_or_union(dcs->d_type->t_tspec)) { - $$ = dcs->d_type->t_sou->sou_first_member; - /* add all the members of the anonymous struct/union */ - anonymize($$); - } else { + if (is_struct_or_union(dcs->d_type->t_tspec)) + $$ = declare_unnamed_member(); + else { /* syntax error '%s' */ error(249, "unnamed member"); $$ = NULL; diff --git a/usr.bin/xlint/lint1/debug.c b/usr.bin/xlint/lint1/debug.c index e39cf762a2cc..7655e85259e7 100644 --- a/usr.bin/xlint/lint1/debug.c +++ b/usr.bin/xlint/lint1/debug.c @@ -1,4 +1,4 @@ -/* $NetBSD: debug.c,v 1.38 2023/06/30 14:39:23 rillig Exp $ */ +/* $NetBSD: debug.c,v 1.39 2023/06/30 21:06:18 rillig Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include #if defined(__RCSID) -__RCSID("$NetBSD: debug.c,v 1.38 2023/06/30 14:39:23 rillig Exp $"); +__RCSID("$NetBSD: debug.c,v 1.39 2023/06/30 21:06:18 rillig Exp $"); #endif #include @@ -367,8 +367,9 @@ debug_sym(const char *prefix, const sym_t *sym, const char *suffix) debug_printf(" value=%s", sym->u.s_bool_constant ? "true" : "false"); - if (is_member(sym) && sym->u.s_member.sm_sou_type != NULL) { + if (is_member(sym)) { struct_or_union *sou_type = sym->u.s_member.sm_sou_type; + lint_assert(sou_type != NULL); const char *tag = sou_type->sou_tag->s_name; const sym_t *def = sou_type->sou_first_typedef; if (tag == unnamed && def != NULL) diff --git a/usr.bin/xlint/lint1/decl.c b/usr.bin/xlint/lint1/decl.c index 38fb2ceefd0e..99dbbcc52b39 100644 --- a/usr.bin/xlint/lint1/decl.c +++ b/usr.bin/xlint/lint1/decl.c @@ -1,4 +1,4 @@ -/* $NetBSD: decl.c,v 1.328 2023/06/30 19:43:00 rillig Exp $ */ +/* $NetBSD: decl.c,v 1.329 2023/06/30 21:06:18 rillig Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. @@ -38,7 +38,7 @@ #include #if defined(__RCSID) -__RCSID("$NetBSD: decl.c,v 1.328 2023/06/30 19:43:00 rillig Exp $"); +__RCSID("$NetBSD: decl.c,v 1.329 2023/06/30 21:06:18 rillig Exp $"); #endif #include @@ -1016,6 +1016,49 @@ check_bit_field(sym_t *dsym, tspec_t *inout_t, type_t **const inout_tp) } } +/* Add a member to the struct or union type that is being built in 'dcs'. */ +static void +dcs_add_member(sym_t *mem) +{ + type_t *tp = mem->s_type; + + unsigned int union_offset = 0; + if (dcs->d_kind == DK_UNION_MEMBER) { + union_offset = dcs->d_offset_in_bits; + dcs->d_offset_in_bits = 0; + } + + if (mem->s_bitfield) { + dcs_align(alignment_in_bits(tp), tp->t_bit_field_width); + // XXX: Why round down? + mem->u.s_member.sm_offset_in_bits = dcs->d_offset_in_bits + - dcs->d_offset_in_bits % size_in_bits(tp->t_tspec); + tp->t_bit_field_offset = dcs->d_offset_in_bits + - mem->u.s_member.sm_offset_in_bits; + dcs->d_offset_in_bits += tp->t_bit_field_width; + } else { + dcs_align(alignment_in_bits(tp), 0); + mem->u.s_member.sm_offset_in_bits = dcs->d_offset_in_bits; + dcs->d_offset_in_bits += type_size_in_bits(tp); + } + + if (union_offset > dcs->d_offset_in_bits) + dcs->d_offset_in_bits = union_offset; +} + +sym_t * +declare_unnamed_member(void) +{ + + sym_t *mem = block_zero_alloc(sizeof(*mem)); + mem->s_name = unnamed; + mem->s_type = dcs->d_type; + + dcs_add_member(mem); + bitfieldtype_ok = false; + return mem; +} + sym_t * declare_member(sym_t *dsym) { @@ -1056,25 +1099,7 @@ declare_member(sym_t *dsym) c99ism(39, dsym->s_name); } - unsigned int union_offset = 0; - if (dcs->d_kind == DK_UNION_MEMBER) { - union_offset = dcs->d_offset_in_bits; - dcs->d_offset_in_bits = 0; - } - if (dsym->s_bitfield) { - dcs_align(alignment_in_bits(tp), tp->t_bit_field_width); - dsym->u.s_member.sm_offset_in_bits = dcs->d_offset_in_bits - - dcs->d_offset_in_bits % size_in_bits(t); - tp->t_bit_field_offset = dcs->d_offset_in_bits - - dsym->u.s_member.sm_offset_in_bits; - dcs->d_offset_in_bits += tp->t_bit_field_width; - } else { - dcs_align(alignment_in_bits(tp), 0); - dsym->u.s_member.sm_offset_in_bits = dcs->d_offset_in_bits; - dcs->d_offset_in_bits += sz; - } - if (union_offset > dcs->d_offset_in_bits) - dcs->d_offset_in_bits = union_offset; + dcs_add_member(dsym); check_function_definition(dsym, false); @@ -1683,6 +1708,20 @@ storage_class_name(scl_t sc) /* NOTREACHED */ } +static bool +has_named_member(const type_t *tp) +{ + for (const sym_t *mem = tp->t_sou->sou_first_member; + mem != NULL; mem = mem->s_next) { + if (mem->s_name != unnamed) + return true; + if (is_struct_or_union(mem->s_type->t_tspec) + && has_named_member(mem->s_type)) + return true; + } + return false; +} + type_t * complete_struct_or_union(sym_t *first_member) { @@ -1705,27 +1744,7 @@ complete_struct_or_union(sym_t *first_member) if (sp->sou_size_in_bits == 0) { /* zero sized %s is a C99 feature */ c99ism(47, tspec_name(tp->t_tspec)); - } - - bool has_named_member = false; - for (sym_t *mem = first_member; mem != NULL; mem = mem->s_next) { - if (mem->s_name != unnamed) - has_named_member = true; - /* bind anonymous members to the structure */ - if (mem->u.s_member.sm_sou_type == NULL) { - mem->u.s_member.sm_sou_type = sp; - if (mem->s_type->t_bitfield) { - sp->sou_size_in_bits += - bit_fields_width(&mem, &has_named_member); - if (mem == NULL) - break; - } - sp->sou_size_in_bits += - type_size_in_bits(mem->s_type); - } - } - - if (!has_named_member && sp->sou_size_in_bits != 0) { + } else if (!has_named_member(tp)) { /* '%s' has no named members */ warning(65, type_name(tp)); } diff --git a/usr.bin/xlint/lint1/externs1.h b/usr.bin/xlint/lint1/externs1.h index c0eac73db8a3..55e7c416136f 100644 --- a/usr.bin/xlint/lint1/externs1.h +++ b/usr.bin/xlint/lint1/externs1.h @@ -1,4 +1,4 @@ -/* $NetBSD: externs1.h,v 1.181 2023/06/30 19:10:49 rillig Exp $ */ +/* $NetBSD: externs1.h,v 1.182 2023/06/30 21:06:18 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -203,6 +203,7 @@ int length_in_bits(const type_t *, const char *); unsigned int alignment_in_bits(const type_t *); sym_t *concat_symbols(sym_t *, sym_t *); void check_type(sym_t *); +sym_t *declare_unnamed_member(void); sym_t *declare_member(sym_t *); sym_t *set_bit_field_width(sym_t *, int); qual_ptr *merge_qualified_pointer(qual_ptr *, qual_ptr *); diff --git a/usr.bin/xlint/lint1/init.c b/usr.bin/xlint/lint1/init.c index 16d27fc10191..ba7e7d5475fd 100644 --- a/usr.bin/xlint/lint1/init.c +++ b/usr.bin/xlint/lint1/init.c @@ -1,4 +1,4 @@ -/* $NetBSD: init.c,v 1.242 2023/05/22 17:53:27 rillig Exp $ */ +/* $NetBSD: init.c,v 1.243 2023/06/30 21:06:18 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -38,7 +38,7 @@ #include #if defined(__RCSID) -__RCSID("$NetBSD: init.c,v 1.242 2023/05/22 17:53:27 rillig Exp $"); +__RCSID("$NetBSD: init.c,v 1.243 2023/06/30 21:06:18 rillig Exp $"); #endif #include @@ -209,12 +209,19 @@ can_init_character_array(const type_t *ltp, const tnode_t *rn) : lst == WCHAR; } -/* C99 6.7.8p9 */ +/* + * C11 6.7.9p9 seems to say that all unnamed members are skipped. C11 6.7.2.1p8 + * suggests an exception to that rule, and together with C11 6.7.2.1p13, it + * says that the members from an anonymous struct/union member are "considered + * to be members of the containing structure or union", thereby preventing that + * the containing structure or union has only unnamed members. + */ static const sym_t * skip_unnamed(const sym_t *m) { - while (m != NULL && m->s_name == unnamed) + while (m != NULL && m->s_name == unnamed + && !is_struct_or_union(m->s_type->t_tspec)) m = m->s_next; return m; } diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c index 4f6e6ba8db40..d6a179526c15 100644 --- a/usr.bin/xlint/lint1/tree.c +++ b/usr.bin/xlint/lint1/tree.c @@ -1,4 +1,4 @@ -/* $NetBSD: tree.c,v 1.536 2023/06/30 12:21:25 rillig Exp $ */ +/* $NetBSD: tree.c,v 1.537 2023/06/30 21:06:18 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -37,7 +37,7 @@ #include #if defined(__RCSID) -__RCSID("$NetBSD: tree.c,v 1.536 2023/06/30 12:21:25 rillig Exp $"); +__RCSID("$NetBSD: tree.c,v 1.537 2023/06/30 21:06:18 rillig Exp $"); #endif #include @@ -1882,6 +1882,26 @@ all_members_compatible(const sym_t *msym) return true; } +static sym_t * +find_member(const type_t *tp, const char *name) +{ + for (sym_t *mem = tp->t_sou->sou_first_member; + mem != NULL; mem = mem->s_next) { + if (strcmp(mem->s_name, name) == 0) + return mem; + } + for (sym_t *mem = tp->t_sou->sou_first_member; + mem != NULL; mem = mem->s_next) { + if (is_struct_or_union(mem->s_type->t_tspec) && + mem->s_name == unnamed) { + sym_t *nested_mem = find_member(mem->s_type, name); + if (nested_mem != NULL) + return nested_mem; + } + } + return NULL; +} + /* * Returns a symbol which has the same name as the msym argument and is a * member of the struct or union specified by the tn argument. @@ -1913,13 +1933,14 @@ struct_or_union_member(tnode_t *tn, op_t op, sym_t *msym) return msym; } - /* Set str to the tag of which msym is expected to be a member. */ - struct_or_union *str = NULL; + /* Determine the tag type of which msym is expected to be a member. */ + const type_t *tp = NULL; if (op == POINT && is_struct_or_union(tn->tn_type->t_tspec)) - str = tn->tn_type->t_sou; + tp = tn->tn_type; if (op == ARROW && tn->tn_type->t_tspec == PTR && is_struct_or_union(tn->tn_type->t_subt->t_tspec)) - str = tn->tn_type->t_subt->t_sou; + tp = tn->tn_type->t_subt; + struct_or_union *str = tp != NULL ? tp->t_sou : NULL; /* * If this struct/union has a member with the name of msym, return it. @@ -1934,6 +1955,12 @@ struct_or_union_member(tnode_t *tn, op_t op, sym_t *msym) } } + if (tp != NULL) { + sym_t *nested_mem = find_member(tp, msym->s_name); + if (nested_mem != NULL) + return nested_mem; + } + bool eq = all_members_compatible(msym); /*