Module Name: src
Committed By: rillig
Date: Thu Jul 13 23:11:11 UTC 2023
Modified Files:
src/usr.bin/xlint/lint1: cgram.y debug.c decl.c externs1.h lex.c
lint1.h
Log Message:
lint: use separate types for parsing pointer types and type qualifiers
The documentation of the previous 'qual_ptr_t' was misleading, as that
type was used for other type qualifier lists as well, even if these were
not related to pointer types.
To generate a diff of this commit:
cvs rdiff -u -r1.460 -r1.461 src/usr.bin/xlint/lint1/cgram.y
cvs rdiff -u -r1.53 -r1.54 src/usr.bin/xlint/lint1/debug.c
cvs rdiff -u -r1.353 -r1.354 src/usr.bin/xlint/lint1/decl.c
cvs rdiff -u -r1.194 -r1.195 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.184 -r1.185 src/usr.bin/xlint/lint1/lex.c
cvs rdiff -u -r1.190 -r1.191 src/usr.bin/xlint/lint1/lint1.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/xlint/lint1/cgram.y
diff -u src/usr.bin/xlint/lint1/cgram.y:1.460 src/usr.bin/xlint/lint1/cgram.y:1.461
--- src/usr.bin/xlint/lint1/cgram.y:1.460 Thu Jul 13 08:40:38 2023
+++ src/usr.bin/xlint/lint1/cgram.y Thu Jul 13 23:11:11 2023
@@ -1,5 +1,5 @@
%{
-/* $NetBSD: cgram.y,v 1.460 2023/07/13 08:40:38 rillig Exp $ */
+/* $NetBSD: cgram.y,v 1.461 2023/07/13 23:11:11 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: cgram.y,v 1.460 2023/07/13 08:40:38 rillig Exp $");
+__RCSID("$NetBSD: cgram.y,v 1.461 2023/07/13 23:11:11 rillig Exp $");
#endif
#include <limits.h>
@@ -141,7 +141,7 @@ is_either(const char *s, const char *a,
op_t y_op;
scl_t y_scl;
tspec_t y_tspec;
- tqual_t y_tqual;
+ type_qualifiers y_type_qualifiers;
function_specifier y_function_specifier;
type_t *y_type;
tnode_t *y_tnode;
@@ -166,7 +166,7 @@ is_either(const char *s, const char *a,
%printer { fprintf(yyo, "%s", op_name($$)); } <y_op>
%printer { fprintf(yyo, "%s", scl_name($$)); } <y_scl>
%printer { fprintf(yyo, "%s", tspec_name($$)); } <y_tspec>
-%printer { fprintf(yyo, "%s", tqual_name($$)); } <y_tqual>
+%printer { fprintf(yyo, "%s", type_qualifiers_string($$)); } <y_type_qualifiers>
%printer {
fprintf(yyo, "%s", function_specifier_name($$));
} <y_function_specifier>
@@ -181,10 +181,7 @@ is_either(const char *s, const char *a,
%printer { fprintf(yyo, "%zu to %zu", $$.lo, $$.hi); } <y_range>
%printer { fprintf(yyo, "length %zu", $$->st_len); } <y_string>
%printer {
- fprintf(yyo, "%s%s%s",
- $$->p_const ? "const " : "",
- $$->p_volatile ? "volatile " : "",
- $$->p_pointer ? "*" : "");
+ fprintf(yyo, "%s *", type_qualifiers_string($$->qualifiers));
} <y_qual_ptr>
%printer { fprintf(yyo, "%s", $$ ? "yes" : "no"); } <y_seen_statement>
%printer { fprintf(yyo, "%s", type_name($$->ga_arg)); } <y_generic>
@@ -234,9 +231,8 @@ is_either(const char *s, const char *a,
*/
%token <y_tspec> T_TYPE
-/* qualifiers (const, volatile, restrict, _Thread_local) */
-%token <y_tqual> T_QUAL
-%token <y_tqual> T_ATOMIC
+%token <y_type_qualifiers> T_QUAL
+%token <y_type_qualifiers> T_ATOMIC
/* struct or union */
%token <y_tspec> T_STRUCT_OR_UNION
@@ -338,13 +334,11 @@ is_either(const char *s, const char *a,
%type <y_sym> enums_with_opt_comma
%type <y_sym> enumerator_list
%type <y_sym> enumerator
-%type <y_tqual> type_qualifier
+%type <y_type_qualifiers> type_qualifier
/* No type for atomic. */
%type <y_qual_ptr> pointer
-%type <y_qual_ptr> asterisk
-%type <y_qual_ptr> type_qualifier_list_opt
-%type <y_qual_ptr> type_qualifier_list
-%type <y_qual_ptr> type_qualifier_list_elem
+%type <y_type_qualifiers> type_qualifier_list_opt
+%type <y_type_qualifiers> type_qualifier_list
/* No type for notype_init_declarators. */
/* No type for type_init_declarators. */
/* No type for notype_init_declarator. */
@@ -846,7 +840,7 @@ begin_type_declaration_specifiers: /* se
begin_type_declmods: /* see C99 6.7 */
begin_type type_qualifier {
- dcs_add_qualifier($2);
+ dcs_add_qualifiers($2);
}
| begin_type T_SCLASS {
dcs_add_storage_class($2);
@@ -870,7 +864,7 @@ begin_type_specifier_qualifier_list_post
dcs_add_type($2);
}
| begin_type_specifier_qualifier_list_postfix type_qualifier {
- dcs_add_qualifier($2);
+ dcs_add_qualifiers($2);
}
| begin_type_specifier_qualifier_list_postfix notype_type_specifier {
dcs_add_type($2);
@@ -889,16 +883,16 @@ begin_type_typespec:
begin_type_qualifier_list:
begin_type type_qualifier {
- dcs_add_qualifier($2);
+ dcs_add_qualifiers($2);
}
| begin_type_qualifier_list type_qualifier {
- dcs_add_qualifier($2);
+ dcs_add_qualifiers($2);
}
;
declmod:
type_qualifier {
- dcs_add_qualifier($1);
+ dcs_add_qualifiers($1);
}
| T_SCLASS {
dcs_add_storage_class($1);
@@ -1223,7 +1217,7 @@ enumerator: /* C99 6.7.2.2 */
type_qualifier: /* C99 6.7.3 */
T_QUAL
| atomic {
- $$ = ATOMIC;
+ $$ = (type_qualifiers){ .tq_atomic = true };
}
;
@@ -1237,43 +1231,29 @@ atomic: /* helper */
;
pointer: /* C99 6.7.5 */
- asterisk type_qualifier_list_opt {
- $$ = merge_qualified_pointer($1, $2);
- }
-| asterisk type_qualifier_list_opt pointer {
- $$ = merge_qualified_pointer($1, $2);
- $$ = merge_qualified_pointer($$, $3);
+ T_ASTERISK type_qualifier_list_opt {
+ $$ = xcalloc(1, sizeof(*$$));
+ add_type_qualifiers(&$$->qualifiers, $2);
}
-;
-
-asterisk: /* helper for 'pointer' */
- T_ASTERISK {
+| T_ASTERISK type_qualifier_list_opt pointer {
$$ = xcalloc(1, sizeof(*$$));
- $$->p_pointer = true;
+ add_type_qualifiers(&$$->qualifiers, $2);
+ $$ = append_qualified_pointer($$, $3);
}
;
type_qualifier_list_opt: /* see C99 6.7.5 */
/* empty */ {
- $$ = NULL;
+ $$ = (type_qualifiers){ .tq_const = false };
}
| type_qualifier_list
;
type_qualifier_list: /* C99 6.7.5 */
- type_qualifier_list_elem
-| type_qualifier_list type_qualifier_list_elem {
- $$ = merge_qualified_pointer($1, $2);
- }
-;
-
-type_qualifier_list_elem: /* helper for 'pointer' */
- type_qualifier {
- $$ = xcalloc(1, sizeof(*$$));
- if ($1 == CONST)
- $$->p_const = true;
- if ($1 == VOLATILE)
- $$->p_volatile = true;
+ type_qualifier
+| type_qualifier_list type_qualifier {
+ $$ = $1;
+ add_type_qualifiers(&$$, $2);
}
;
@@ -1470,7 +1450,7 @@ array_size:
}
| type_qualifier {
/* C11 6.7.6.2 */
- if ($1 != RESTRICT)
+ if (!$1.tq_restrict)
yyerror("Bad attribute");
$$ = NULL;
}
@@ -2210,7 +2190,7 @@ gcc_attribute:
| T_NAME T_LPAREN T_RPAREN
| T_NAME T_LPAREN gcc_attribute_parameters T_RPAREN
| type_qualifier {
- if ($1 != CONST)
+ if (!$1.tq_const)
yyerror("Bad attribute");
}
;
@@ -2259,7 +2239,7 @@ cgram_to_string(int token, YYSTYPE val)
case T_STRUCT_OR_UNION:
return tspec_name(val.y_tspec);
case T_QUAL:
- return tqual_name(val.y_tqual);
+ return type_qualifiers_string(val.y_type_qualifiers);
case T_FUNCTION_SPECIFIER:
return function_specifier_name(val.y_function_specifier);
case T_NAME:
Index: src/usr.bin/xlint/lint1/debug.c
diff -u src/usr.bin/xlint/lint1/debug.c:1.53 src/usr.bin/xlint/lint1/debug.c:1.54
--- src/usr.bin/xlint/lint1/debug.c:1.53 Thu Jul 13 19:59:08 2023
+++ src/usr.bin/xlint/lint1/debug.c Thu Jul 13 23:11:11 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: debug.c,v 1.53 2023/07/13 19:59:08 rillig Exp $ */
+/* $NetBSD: debug.c,v 1.54 2023/07/13 23:11:11 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: debug.c,v 1.53 2023/07/13 19:59:08 rillig Exp $");
+__RCSID("$NetBSD: debug.c,v 1.54 2023/07/13 23:11:11 rillig Exp $");
#endif
#include <stdlib.h>
@@ -303,16 +303,16 @@ symt_name(symt_t kind)
}
const char *
-tqual_name(tqual_t qual)
+type_qualifiers_string(type_qualifiers tq)
{
- static const char *const name[] = {
- "const",
- "volatile",
- "restrict",
- "_Atomic",
- };
+ static char buf[32];
- return name[qual];
+ snprintf(buf, sizeof(buf), "%s%s%s%s",
+ tq.tq_const ? " const" : "",
+ tq.tq_restrict ? " restrict" : "",
+ tq.tq_volatile ? " volatile" : "",
+ tq.tq_atomic ? " atomic" : "");
+ return buf[0] != '\0' ? buf + 1 : "none";
}
const char *
@@ -392,8 +392,8 @@ debug_sym(const char *prefix, const sym_
debug_printf(" %s",
tspec_name(sym->u.s_keyword.u.sk_tspec));
if (t == T_QUAL)
- debug_printf(" %s",
- tqual_name(sym->u.s_keyword.u.sk_qualifier));
+ debug_printf(" %s", type_qualifiers_string(
+ sym->u.s_keyword.u.sk_type_qualifier));
if (t == T_FUNCTION_SPECIFIER)
debug_printf(" %s", function_specifier_name(
sym->u.s_keyword.u.function_specifier));
Index: src/usr.bin/xlint/lint1/decl.c
diff -u src/usr.bin/xlint/lint1/decl.c:1.353 src/usr.bin/xlint/lint1/decl.c:1.354
--- src/usr.bin/xlint/lint1/decl.c:1.353 Thu Jul 13 20:30:21 2023
+++ src/usr.bin/xlint/lint1/decl.c Thu Jul 13 23:11:11 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: decl.c,v 1.353 2023/07/13 20:30:21 rillig Exp $ */
+/* $NetBSD: decl.c,v 1.354 2023/07/13 23:11:11 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: decl.c,v 1.353 2023/07/13 20:30:21 rillig Exp $");
+__RCSID("$NetBSD: decl.c,v 1.354 2023/07/13 23:11:11 rillig Exp $");
#endif
#include <sys/param.h>
@@ -499,24 +499,22 @@ dcs_set_used(void)
* declarators.
*/
void
-dcs_add_qualifier(tqual_t q)
+dcs_add_qualifiers(type_qualifiers qs)
{
- if (q == CONST) {
+ if (qs.tq_const) {
if (dcs->d_const) {
/* duplicate '%s' */
warning(10, "const");
}
dcs->d_const = true;
- } else if (q == VOLATILE) {
+ }
+ if (qs.tq_volatile) {
if (dcs->d_volatile) {
/* duplicate '%s' */
warning(10, "volatile");
}
dcs->d_volatile = true;
- } else {
- lint_assert(q == RESTRICT || q == ATOMIC);
- /* Silently ignore these qualifiers. */
}
}
@@ -1153,45 +1151,36 @@ set_bit_field_width(sym_t *dsym, int bit
return dsym;
}
-/*
- * A sequence of asterisks and qualifiers, from right to left. For example,
- * 'const ***volatile **const volatile' results in [cvp, p, vp, p, p]. The
- * leftmost 'const' is not included in this list, it is stored in dcs->d_const
- * instead.
- */
+void
+add_type_qualifiers(type_qualifiers *dst, type_qualifiers src)
+{
+
+ if (src.tq_const && dst->tq_const)
+ /* duplicate '%s' */
+ warning(10, "const");
+ if (src.tq_volatile && dst->tq_volatile)
+ /* duplicate '%s' */
+ warning(10, "volatile");
+
+ dst->tq_const = dst->tq_const || src.tq_const;
+ dst->tq_restrict = dst->tq_restrict || src.tq_restrict;
+ dst->tq_volatile = dst->tq_volatile || src.tq_volatile;
+ dst->tq_atomic = dst->tq_atomic || src.tq_atomic;
+}
+
qual_ptr *
-merge_qualified_pointer(qual_ptr *p1, qual_ptr *p2)
+append_qualified_pointer(qual_ptr *p1, qual_ptr *p2)
{
if (p2 == NULL)
- return p1; /* for optional qualifiers */
+ return p1;
- if (p2->p_pointer) {
- /* append p1 to p2, keeping p2 */
- qual_ptr *tail = p2;
- while (tail->p_next != NULL)
- tail = tail->p_next;
- tail->p_next = p1;
- return p2;
- }
-
- /* merge p2 into p1, keeping p1 */
- if (p2->p_const) {
- if (p1->p_const) {
- /* duplicate '%s' */
- warning(10, "const");
- }
- p1->p_const = true;
- }
- if (p2->p_volatile) {
- if (p1->p_volatile) {
- /* duplicate '%s' */
- warning(10, "volatile");
- }
- p1->p_volatile = true;
- }
- free(p2);
- return p1;
+ /* append p1 to p2, keeping p2 */
+ qual_ptr *tail = p2;
+ while (tail->p_next != NULL)
+ tail = tail->p_next;
+ tail->p_next = p1;
+ return p2;
}
static type_t *
@@ -1229,7 +1218,7 @@ add_pointer(sym_t *decl, qual_ptr *p)
while (p != NULL) {
*tpp = block_derive_pointer(dcs->d_type,
- p->p_const, p->p_volatile);
+ p->qualifiers.tq_const, p->qualifiers.tq_volatile);
tpp = &(*tpp)->t_subt;
Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.194 src/usr.bin/xlint/lint1/externs1.h:1.195
--- src/usr.bin/xlint/lint1/externs1.h:1.194 Thu Jul 13 08:40:38 2023
+++ src/usr.bin/xlint/lint1/externs1.h Thu Jul 13 23:11:11 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: externs1.h,v 1.194 2023/07/13 08:40:38 rillig Exp $ */
+/* $NetBSD: externs1.h,v 1.195 2023/07/13 23:11:11 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -122,7 +122,7 @@ void expr_restore_memory(memory_pool);
const char *decl_level_kind_name(decl_level_kind);
const char *scl_name(scl_t);
const char *symt_name(symt_t);
-const char *tqual_name(tqual_t);
+const char *type_qualifiers_string(type_qualifiers);
const char *function_specifier_name(function_specifier);
void debug_dcs(bool);
void debug_node(const tnode_t *);
@@ -196,7 +196,7 @@ bool is_incomplete(const type_t *);
void dcs_add_function_specifier(function_specifier);
void dcs_add_storage_class(scl_t);
void dcs_add_type(type_t *);
-void dcs_add_qualifier(tqual_t);
+void dcs_add_qualifiers(type_qualifiers);
void dcs_add_packed(void);
void dcs_set_used(void);
void begin_declaration_level(decl_level_kind);
@@ -211,7 +211,8 @@ 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 *);
+void add_type_qualifiers(type_qualifiers *, type_qualifiers);
+qual_ptr *append_qualified_pointer(qual_ptr *, qual_ptr *);
sym_t *add_pointer(sym_t *, qual_ptr *);
sym_t *add_array(sym_t *, bool, int);
sym_t *add_function(sym_t *, sym_t *);
Index: src/usr.bin/xlint/lint1/lex.c
diff -u src/usr.bin/xlint/lint1/lex.c:1.184 src/usr.bin/xlint/lint1/lex.c:1.185
--- src/usr.bin/xlint/lint1/lex.c:1.184 Thu Jul 13 20:30:21 2023
+++ src/usr.bin/xlint/lint1/lex.c Thu Jul 13 23:11:11 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: lex.c,v 1.184 2023/07/13 20:30:21 rillig Exp $ */
+/* $NetBSD: lex.c,v 1.185 2023/07/13 23:11:11 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
-__RCSID("$NetBSD: lex.c,v 1.184 2023/07/13 20:30:21 rillig Exp $");
+__RCSID("$NetBSD: lex.c,v 1.185 2023/07/13 23:11:11 rillig Exp $");
#endif
#include <ctype.h>
@@ -94,7 +94,7 @@ bool in_system_header;
#define kwdef_type(name, tspec, since) \
kwdef(name, T_TYPE, .u.kw_tspec = (tspec), since, 0, 1)
#define kwdef_tqual(name, tqual, since, gcc, deco) \
- kwdef(name, T_QUAL, .u.kw_tqual = (tqual), since, gcc, deco)
+ kwdef(name, T_QUAL, .u.kw_tqual = {.tqual = true}, since, gcc, deco)
#define kwdef_keyword(name, token) \
kwdef(name, token, {false}, 78, 0, 1)
@@ -107,7 +107,7 @@ static const struct keyword {
scl_t kw_scl; /* if kw_token is T_SCLASS */
tspec_t kw_tspec; /* if kw_token is T_TYPE or
* T_STRUCT_OR_UNION */
- tqual_t kw_tqual; /* if kw_token is T_QUAL */
+ type_qualifiers kw_tqual; /* if kw_token is T_QUAL */
function_specifier kw_fs; /* if kw_token is
* T_FUNCTION_SPECIFIER */
} u;
@@ -132,7 +132,7 @@ static const struct keyword {
kwdef_keyword( "case", T_CASE),
kwdef_type( "char", CHAR, 78),
kwdef_type( "_Complex", COMPLEX, 99),
- kwdef_tqual( "const", CONST, 90,0,7),
+ kwdef_tqual( "const", tq_const, 90,0,7),
kwdef_keyword( "continue", T_CONTINUE),
kwdef_keyword( "default", T_DEFAULT),
kwdef_keyword( "do", T_DO),
@@ -157,7 +157,7 @@ static const struct keyword {
kwdef_token( "__packed", T_PACKED, 78,0,1),
kwdef_token( "__real__", T_REAL, 78,1,1),
kwdef_sclass( "register", REG, 78,0,1),
- kwdef_tqual( "restrict", RESTRICT, 99,0,7),
+ kwdef_tqual( "restrict", tq_restrict, 99,0,7),
kwdef_keyword( "return", T_RETURN),
kwdef_type( "short", SHORT, 78),
kwdef( "signed", T_TYPE, .u.kw_tspec = SIGNED, 90,0,3),
@@ -178,7 +178,7 @@ static const struct keyword {
kwdef("union", T_STRUCT_OR_UNION, .u.kw_tspec = UNION, 78,0,1),
kwdef_type( "unsigned", UNSIGN, 78),
kwdef_type( "void", VOID, 78),
- kwdef_tqual( "volatile", VOLATILE, 90,0,7),
+ kwdef_tqual( "volatile", tq_volatile, 90,0,7),
kwdef_keyword( "while", T_WHILE),
#undef kwdef
#undef kwdef_token
@@ -359,7 +359,7 @@ add_keyword(const struct keyword *kw, bo
if (tok == T_SCLASS)
sym->s_scl = kw->u.kw_scl;
if (tok == T_QUAL)
- sym->u.s_keyword.u.sk_qualifier = kw->u.kw_tqual;
+ sym->u.s_keyword.u.sk_type_qualifier = kw->u.kw_tqual;
if (tok == T_FUNCTION_SPECIFIER)
sym->u.s_keyword.u.function_specifier = kw->u.kw_fs;
@@ -440,7 +440,8 @@ lex_keyword(sym_t *sym)
if (tok == T_TYPE || tok == T_STRUCT_OR_UNION)
yylval.y_tspec = sym->u.s_keyword.u.sk_tspec;
if (tok == T_QUAL)
- yylval.y_tqual = sym->u.s_keyword.u.sk_qualifier;
+ yylval.y_type_qualifiers =
+ sym->u.s_keyword.u.sk_type_qualifier;
if (tok == T_FUNCTION_SPECIFIER)
yylval.y_function_specifier =
sym->u.s_keyword.u.function_specifier;
Index: src/usr.bin/xlint/lint1/lint1.h
diff -u src/usr.bin/xlint/lint1/lint1.h:1.190 src/usr.bin/xlint/lint1/lint1.h:1.191
--- src/usr.bin/xlint/lint1/lint1.h:1.190 Thu Jul 13 19:59:08 2023
+++ src/usr.bin/xlint/lint1/lint1.h Thu Jul 13 23:11:11 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: lint1.h,v 1.190 2023/07/13 19:59:08 rillig Exp $ */
+/* $NetBSD: lint1.h,v 1.191 2023/07/13 23:11:11 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -79,13 +79,12 @@ typedef struct strg {
void *st_mem; /* char[] for st_char, or wchar_t[] */
} strg_t;
-/* type qualifiers (only used during parsing) */
-typedef enum {
- CONST,
- VOLATILE,
- RESTRICT,
- ATOMIC,
-} tqual_t;
+typedef struct {
+ bool tq_const:1;
+ bool tq_restrict:1;
+ bool tq_volatile:1;
+ bool tq_atomic:1;
+} type_qualifiers;
/* An integer or floating-point value. */
typedef struct {
@@ -257,7 +256,7 @@ typedef struct sym {
/* if T_TYPE or T_STRUCT_OR_UNION */
tspec_t sk_tspec;
/* if T_QUAL */
- tqual_t sk_qualifier;
+ type_qualifiers sk_type_qualifier;
/* if T_FUNCTION_SPECIFIER */
function_specifier function_specifier;
} u;
@@ -390,11 +389,14 @@ typedef struct decl_level {
struct decl_level *d_enclosing; /* the enclosing declaration level */
} decl_level;
-/* One level of pointer indirection in declarators, including qualifiers. */
+/*
+ * A sequence of asterisks and qualifiers, from right to left. For example,
+ * 'const ***volatile **const volatile' results in [c-v-, ----, --v-, ----,
+ * ----]. The leftmost 'const' is not included in this list, it is stored in
+ * dcs->d_const instead.
+ */
typedef struct qual_ptr {
- bool p_const:1;
- bool p_volatile:1;
- bool p_pointer:1;
+ type_qualifiers qualifiers;
struct qual_ptr *p_next;
} qual_ptr;