Home | History | Annotate | Line # | Download | only in lint1
      1 /* $NetBSD: ckbool.c,v 1.32 2024/05/12 12:32:39 rillig Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2021 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Roland Illig <rillig (at) NetBSD.org>.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #if HAVE_NBTOOL_CONFIG_H
     33 #include "nbtool_config.h"
     34 #endif
     35 
     36 #include <sys/cdefs.h>
     37 
     38 #if defined(__RCSID)
     39 __RCSID("$NetBSD: ckbool.c,v 1.32 2024/05/12 12:32:39 rillig Exp $");
     40 #endif
     41 
     42 #include <string.h>
     43 
     44 #include "lint1.h"
     45 
     46 
     47 /*
     48  * The option -T treats _Bool as incompatible with all other scalar types.
     49  * See d_c99_bool_strict.c for the detailed rules and for examples.
     50  */
     51 
     52 
     53 static bool
     54 is_int_constant_zero(const tnode_t *tn, tspec_t t)
     55 {
     56 	return t == INT && tn->tn_op == CON && tn->u.value.u.integer == 0;
     57 }
     58 
     59 static bool
     60 is_typeok_strict_bool_binary(op_t op,
     61 			     const tnode_t *ln, tspec_t lt,
     62 			     const tnode_t *rn, tspec_t rt)
     63 {
     64 	if ((lt == BOOL) == (rt == BOOL))
     65 		return true;
     66 
     67 	if (op == FARG && rn->tn_sys)
     68 		return false;
     69 
     70 	if ((ln->tn_sys || rn->tn_sys) &&
     71 	    (is_int_constant_zero(ln, lt) || is_int_constant_zero(rn, rt)))
     72 		return true;
     73 
     74 	if (op == ASSIGN || op == ANDASS || op == XORASS || op == ORASS ||
     75 	    op == RETURN || op == INIT || op == FARG)
     76 		return lt != BOOL && (ln->tn_sys || rn->tn_sys);
     77 
     78 	if (op == EQ || op == NE ||
     79 	    op == BITAND || op == BITXOR || op == BITOR ||
     80 	    op == COLON)
     81 		return false;
     82 
     83 	return true;
     84 }
     85 
     86 /*
     87  * Some operators require that either both operands are bool or both are
     88  * scalar.
     89  *
     90  * Code that passes this check can be compiled in a pre-C99 environment that
     91  * doesn't implement the special rule C99 6.3.1.2, without silent change in
     92  * behavior.
     93  */
     94 static bool
     95 typeok_strict_bool_binary_compatible(op_t op, int arg,
     96 				     const tnode_t *ln, tspec_t lt,
     97 				     const tnode_t *rn, tspec_t rt)
     98 {
     99 	if (is_typeok_strict_bool_binary(op, ln, lt, rn, rt))
    100 		return true;
    101 
    102 	if (op == FARG)
    103 		/* parameter %d expects '%s', gets passed '%s' */
    104 		error(334, arg, tspec_name(lt), tspec_name(rt));
    105 	else if (op == RETURN)
    106 		/* function has return type '%s' but returns '%s' */
    107 		error(211, tspec_name(lt), tspec_name(rt));
    108 	else
    109 		/* operands of '%s' have incompatible types '%s' and '%s' */
    110 		error(107, op_name(op), tspec_name(lt), tspec_name(rt));
    111 
    112 	return false;
    113 }
    114 
    115 /*
    116  * In strict bool mode, check whether the types of the operands match the
    117  * operator.
    118  */
    119 bool
    120 typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
    121 			  const tnode_t *ln,
    122 			  const tnode_t *rn)
    123 {
    124 	ln = before_conversion(ln);
    125 	tspec_t lt = ln->tn_type->t_tspec;
    126 	tspec_t rt = NO_TSPEC;
    127 	if (rn != NULL) {
    128 		rn = before_conversion(rn);
    129 		rt = rn->tn_type->t_tspec;
    130 	}
    131 
    132 	if (rn != NULL &&
    133 	    !typeok_strict_bool_binary_compatible(op, arg, ln, lt, rn, rt))
    134 		return false;
    135 
    136 	if (mp->m_compares_with_zero) {
    137 		bool binary = mp->m_binary;
    138 		bool lbool = is_typeok_bool_compares_with_zero(ln, false);
    139 		bool ok = true;
    140 
    141 		if (!binary && !lbool) {
    142 			/* operand of '%s' must be bool, not '%s' */
    143 			error(330, op_name(op), tspec_name(lt));
    144 			ok = false;
    145 		}
    146 		if (binary && !lbool) {
    147 			/* left operand of '%s' must be bool, not '%s' */
    148 			error(331, op_name(op), tspec_name(lt));
    149 			ok = false;
    150 		}
    151 		if (binary && op != QUEST &&
    152 		    !is_typeok_bool_compares_with_zero(rn, false)) {
    153 			/* right operand of '%s' must be bool, not '%s' */
    154 			error(332, op_name(op), tspec_name(rt));
    155 			ok = false;
    156 		}
    157 		return ok;
    158 	}
    159 
    160 	if (!mp->m_takes_bool) {
    161 		bool binary = mp->m_binary;
    162 		bool lbool = lt == BOOL;
    163 		bool ok = true;
    164 
    165 		if (!binary && lbool) {
    166 			/* operand of '%s' must not be bool */
    167 			error(335, op_name(op));
    168 			ok = false;
    169 		}
    170 		if (binary && lbool) {
    171 			/* left operand of '%s' must not be bool */
    172 			error(336, op_name(op));
    173 			ok = false;
    174 		}
    175 		if (binary && rt == BOOL) {
    176 			/* right operand of '%s' must not be bool */
    177 			error(337, op_name(op));
    178 			ok = false;
    179 		}
    180 		return ok;
    181 	}
    182 
    183 	return true;
    184 }
    185 
    186 bool
    187 is_typeok_bool_compares_with_zero(const tnode_t *tn, bool is_do_while)
    188 {
    189 	while (tn->tn_op == COMMA)
    190 		tn = tn->u.ops.right;
    191 	tn = before_conversion(tn);
    192 
    193 	return tn->tn_type->t_tspec == BOOL
    194 	    || tn->tn_op == BITAND
    195 	    || (is_do_while && is_int_constant_zero(tn, tn->tn_type->t_tspec))
    196 	    || (tn->tn_sys && is_scalar(tn->tn_type->t_tspec));
    197 }
    198 
    199 bool
    200 fallback_symbol_strict_bool(sym_t *sym)
    201 {
    202 	if (strcmp(sym->s_name, "__lint_false") == 0) {
    203 		sym->s_scl = BOOL_CONST;
    204 		sym->s_type = gettyp(BOOL);
    205 		sym->u.s_bool_constant = false;
    206 		return true;
    207 	}
    208 
    209 	if (strcmp(sym->s_name, "__lint_true") == 0) {
    210 		sym->s_scl = BOOL_CONST;
    211 		sym->s_type = gettyp(BOOL);
    212 		sym->u.s_bool_constant = true;
    213 		return true;
    214 	}
    215 
    216 	return false;
    217 }
    218