#include "lint.h"
#include "op.h"
typedef struct memory_pool {
struct memory_pool_item {
void *p;
#ifdef DEBUG_MEM
size_t size;
const char *descr;
#endif
} *items;
size_t len;
size_t cap;
} memory_pool;
typedef enum {
EM_PARSE,
EM_TYPE,
EM_EVAL,
} evaluation_mode;
#define LWARN_ALL (-2)
#define LWARN_NONE (-1)
typedef struct {
const char *p_file;
int p_line;
int p_uniq;
} pos_t;
typedef struct {
bool tq_const;
bool tq_restrict;
bool tq_volatile;
bool tq_atomic;
} type_qualifiers;
typedef struct {
bool used;
bool noreturn;
unsigned bit_width;
} type_attributes;
typedef struct {
tspec_t v_tspec;
bool v_unsigned_since_c90;
bool v_char_constant;
union {
int64_t integer;
long double floating;
} u;
} val_t;
typedef struct sym sym_t;
typedef struct {
unsigned int sou_size_in_bits;
unsigned int sou_align;
bool sou_incomplete:1;
sym_t *sou_first_member;
sym_t *sou_tag;
sym_t *sou_first_typedef;
} struct_or_union;
typedef struct {
bool en_incomplete:1;
sym_t *en_first_enumerator;
sym_t *en_tag;
sym_t *en_first_typedef;
} enumeration;
struct lint1_type {
tspec_t t_tspec;
bool t_incomplete_array:1;
bool t_const:1;
bool t_volatile:1;
bool t_proto:1;
bool t_identifier_params:1;
bool t_vararg:1;
bool t_noreturn:1;
bool t_typedef:1;
bool t_typeof:1;
bool t_bitfield:1;
bool t_is_enum:1;
bool t_packed:1;
union {
int dimension;
struct_or_union *sou;
enumeration *enumer;
sym_t *params;
} u;
unsigned int t_bit_field_width:8;
unsigned int t_bit_field_offset:24;
struct lint1_type *t_subt;
};
typedef enum {
SK_VCFT,
SK_MEMBER,
SK_TAG,
SK_LABEL
} symbol_kind;
typedef enum {
NO_SCL,
EXTERN,
STATIC,
AUTO,
REG,
TYPEDEF,
THREAD_LOCAL,
STRUCT_TAG,
UNION_TAG,
ENUM_TAG,
STRUCT_MEMBER,
UNION_MEMBER,
BOOL_CONST,
ENUM_CONST,
ABSTRACT,
} scl_t;
typedef enum {
FS_INLINE,
FS_NORETURN,
} function_specifier;
typedef enum {
NC_FALSE,
NC_TRUE,
NC_NULLPTR,
} named_constant;
struct sym {
const char *s_name;
const char *s_rename;
pos_t s_def_pos;
pos_t s_set_pos;
pos_t s_use_pos;
symbol_kind s_kind;
const struct keyword *s_keyword;
bool s_bitfield:1;
bool s_set:1;
bool s_used:1;
bool s_param:1;
bool s_register:1;
bool s_defparam:1;
bool s_return_type_implicit_int:1;
bool s_osdef:1;
bool s_inline:1;
sym_t *s_ext_sym;
def_t s_def;
scl_t s_scl;
int s_block_level;
type_t *s_type;
union {
bool s_bool_constant;
int s_enum_constant;
struct {
struct_or_union *sm_containing_type;
unsigned int sm_offset_in_bits;
} s_member;
struct {
int sk_token;
union {
tspec_t sk_tspec;
type_qualifiers sk_type_qualifier;
function_specifier function_specifier;
named_constant named_constant;
} u;
} s_keyword;
sym_t *s_old_style_params;
size_t s_array_nonnull_dimension;
} u;
sym_t *s_symtab_next;
sym_t **s_symtab_ref;
sym_t *s_next;
sym_t *s_level_next;
};
typedef struct {
const char *sb_name;
size_t sb_len;
sym_t *sb_sym;
} sbuf_t;
typedef struct {
struct tnode *func;
struct tnode **args;
size_t args_len;
size_t args_cap;
} function_call;
typedef struct tnode tnode_t;
struct tnode {
op_t tn_op;
type_t *tn_type;
bool tn_lvalue:1;
bool tn_cast:1;
bool tn_parenthesized:1;
bool tn_sys:1;
bool tn_system_dependent:1;
union {
struct {
tnode_t *left;
tnode_t *right;
} ops;
sym_t *sym;
val_t value;
buffer *str_literals;
function_call *call;
} u;
};
struct generic_selection {
const type_t *expr_type;
tnode_t *fallback;
tnode_t *matched;
bool assoc_matched;
};
typedef struct {
bool has_dim;
int dim;
} array_size;
typedef enum decl_level_kind {
DLK_EXTERN,
DLK_STRUCT,
DLK_UNION,
DLK_ENUM,
DLK_OLD_STYLE_PARAMS,
DLK_PROTO_PARAMS,
DLK_AUTO,
DLK_ABSTRACT
} decl_level_kind;
typedef struct decl_level {
decl_level_kind d_kind;
tspec_t d_abstract_type;
tspec_t d_complex_mod;
tspec_t d_sign_mod;
tspec_t d_rank_mod;
scl_t d_scl;
type_t *d_type;
sym_t *d_redeclared_symbol;
unsigned int d_sou_size_in_bits;
unsigned int d_sou_align;
unsigned int d_mem_align;
type_qualifiers d_qual;
bool d_inline:1;
bool d_multiple_storage_classes:1;
bool d_invalid_type_combination:1;
bool d_nonempty_decl:1;
bool d_no_type_specifier:1;
bool d_asm:1;
bool d_packed:1;
bool d_used:1;
bool d_noreturn:1;
type_t *d_tag_type;
sym_t *d_func_params;
pos_t d_func_def_pos;
sym_t *d_first_dlsym;
sym_t **d_last_dlsym;
sym_t *d_func_proto_syms;
bool d_finished;
struct decl_level *d_enclosing;
} decl_level;
typedef struct {
sym_t *first;
bool vararg:1;
bool prototype:1;
bool used:1;
bool noreturn:1;
bool identifier:1;
} parameter_list;
typedef struct qual_ptr {
type_qualifiers qualifiers;
struct qual_ptr *p_next;
} qual_ptr;
typedef struct {
val_t *vals;
size_t len;
size_t cap;
} case_labels;
typedef enum {
CS_DO_WHILE,
CS_FOR,
CS_FUNCTION_BODY,
CS_IF,
CS_SWITCH,
CS_WHILE
} control_statement_kind;
typedef struct control_statement {
control_statement_kind c_kind;
bool c_loop:1;
bool c_switch:1;
bool c_break:1;
bool c_continue:1;
bool c_default:1;
bool c_maybe_endless:1;
bool c_always_then:1;
bool c_reached_end_of_then:1;
bool c_had_return_noval:1;
bool c_had_return_value:1;
type_t *c_switch_type;
tnode_t *c_switch_expr;
case_labels c_case_labels;
memory_pool c_for_expr3_mem;
tnode_t *c_for_expr3;
pos_t c_for_expr3_pos;
pos_t c_for_expr3_csrc_pos;
struct control_statement *c_surrounding;
} control_statement;
typedef struct {
size_t lo;
size_t hi;
} range_t;
typedef enum designator_kind {
DK_MEMBER,
DK_SUBSCRIPT,
DK_SCALAR
} designator_kind;
typedef struct designator {
designator_kind dr_kind;
const sym_t *dr_member;
size_t dr_subscript;
bool dr_done;
} designator;
typedef struct designation {
designator *dn_items;
size_t dn_len;
size_t dn_cap;
} designation;
typedef enum {
LC_ARGSUSED,
LC_BITFIELDTYPE,
LC_FALLTHROUGH,
LC_LINTLIBRARY,
LC_LINTED,
LC_LONGLONG,
LC_NOTREACHED,
LC_PRINTFLIKE,
LC_PROTOLIB,
LC_SCANFLIKE,
LC_VARARGS,
} lint_comment;
typedef struct {
size_t start;
size_t end;
uint64_t value;
bool escaped;
bool named_escape;
bool literal_escape;
uint8_t octal_digits;
uint8_t hex_digits;
bool next_literal;
bool invalid_escape;
bool overflow;
bool missing_hex_digits;
bool unescaped_newline;
} quoted_iterator;
typedef enum {
TK_IDENTIFIER,
TK_CONSTANT,
TK_STRING_LITERALS,
TK_PUNCTUATOR,
} token_kind;
typedef struct token {
token_kind kind;
union {
const char *identifier;
val_t constant;
buffer string_literals;
const char *punctuator;
} u;
} token;
typedef struct balanced_token_sequence balanced_token_sequence;
typedef struct balanced_token balanced_token;
struct balanced_token_sequence {
balanced_token *tokens;
size_t len;
size_t cap;
};
struct balanced_token {
char kind;
union {
token token;
balanced_token_sequence tokens;
} u;
};
typedef struct {
const char *prefix;
const char *name;
balanced_token_sequence *arg;
} attribute;
typedef struct {
attribute *attrs;
size_t len;
size_t cap;
} attribute_list;
#include "externs1.h"
#define lint_assert(cond) \
do { \
if (!(cond)) \
assert_failed(__FILE__, __LINE__, __func__, #cond); \
} while (false)
#ifdef DEBUG
# include "err-msgs.h"
static inline void __printflike(1, 2)
check_printf(const char *fmt, ...)
{
}
# define wrap_check_printf_at(func, msgid, pos, args...) \
do { \
check_printf(__CONCAT(MSG_, msgid), ##args); \
(func)(msgid, pos, ##args); \
} while (false)
# define error_at(msgid, pos, args...) \
wrap_check_printf_at(error_at, msgid, pos, ##args)
# define warning_at(msgid, pos, args...) \
wrap_check_printf_at(warning_at, msgid, pos, ##args)
# define message_at(msgid, pos, args...) \
wrap_check_printf_at(message_at, msgid, pos, ##args)
# define wrap_check_printf(func, cond, msgid, args...) \
({ \
if (cond) \
debug_step("%s:%d: %s %d '%s' in %s", \
__FILE__, __LINE__, #func, msgid, \
__CONCAT(MSG_, msgid), __func__); \
check_printf(__CONCAT(MSG_, msgid), ##args); \
(func)(msgid, ##args); \
\
})
# define error(msgid, args...) wrap_check_printf(error, \
true, msgid, ##args)
# define warning(msgid, args...) wrap_check_printf(warning, \
true, msgid, ##args)
# define gnuism(msgid, args...) wrap_check_printf(gnuism, \
!allow_gcc || (!allow_trad && !allow_c99), msgid, ##args)
# define c99ism(msgid, args...) wrap_check_printf(c99ism, \
!allow_c99 && (!allow_gcc || !allow_trad), msgid, ##args)
# define c11ism(msgid, args...) wrap_check_printf(c11ism, \
!allow_c11 && !allow_gcc, msgid, ##args)
# define c23ism(msgid, args...) wrap_check_printf(c23ism, \
!allow_c23, msgid, ##args)
#endif
#ifdef DEBUG
# define query_message(query_id, args...) \
do { \
debug_step("%s:%d: query %d '%s' in %s", \
__FILE__, __LINE__, \
query_id, __CONCAT(MSG_Q, query_id), __func__); \
check_printf(__CONCAT(MSG_Q, query_id), ##args); \
(query_message)(query_id, ##args); \
} while (false)
#else
# define query_message(...) \
do { \
if (any_query_enabled) \
(query_message)(__VA_ARGS__); \
} while (false)
#endif
static inline pos_t
unique_curr_pos(void)
{
pos_t curr = curr_pos;
curr_pos.p_uniq++;
if (curr_pos.p_file == csrc_pos.p_file)
csrc_pos.p_uniq++;
return curr;
}
static inline bool
is_nonzero_val(const val_t *val)
{
return is_floating(val->v_tspec)
? val->u.floating != 0.0
: val->u.integer != 0;
}
static inline bool
constant_is_nonzero(const tnode_t *tn)
{
lint_assert(tn->tn_op == CON);
lint_assert(tn->tn_type->t_tspec == tn->u.value.v_tspec);
return is_nonzero_val(&tn->u.value);
}
static inline bool
is_zero(const tnode_t *tn)
{
return tn != NULL && tn->tn_op == CON && !is_nonzero_val(&tn->u.value);
}
static inline bool
is_nonzero(const tnode_t *tn)
{
return tn != NULL && tn->tn_op == CON && is_nonzero_val(&tn->u.value);
}
static inline const char *
op_name(op_t op)
{
return modtab[op].m_name;
}
static inline bool
is_binary(const tnode_t *tn)
{
return modtab[tn->tn_op].m_binary;
}
static inline uint64_t
bit(unsigned i)
{
if (i >= 64)
return 0;
lint_assert(i < 64);
return (uint64_t)1 << i;
}
static inline bool
msb(int64_t si, tspec_t t)
{
return ((uint64_t)si & bit(size_in_bits(t) - 1)) != 0;
}
static inline uint64_t
value_bits(unsigned bitsize)
{
lint_assert(bitsize > 0);
if (bitsize >= 64)
return ~(uint64_t)0;
return ~(~(uint64_t)0 << bitsize);
}
static inline bool
is_struct_or_union(tspec_t t)
{
return t == STRUCT || t == UNION;
}
static inline bool
is_member(const sym_t *sym)
{
return sym->s_scl == STRUCT_MEMBER || sym->s_scl == UNION_MEMBER;
}
static inline void
set_sym_kind(symbol_kind kind)
{
if (yflag)
debug_step("%s: %s -> %s", __func__,
symbol_kind_name(sym_kind), symbol_kind_name(kind));
sym_kind = kind;
}
static inline type_attributes
merge_type_attributes(type_attributes a, type_attributes b)
{
return (type_attributes){
.used = a.used || b.used,
.noreturn = a.noreturn || b.noreturn,
.bit_width = b.bit_width > 0 ? b.bit_width : a.bit_width,
};
}
static inline type_attributes
no_type_attributes(void)
{
return (type_attributes){ .used = false };
}