示例#1
0
static void check_arg_voidness_and_nonnulls(
		expr *callexpr, symtable *stab,
		funcargs *args_from_decl, unsigned count_decl,
		expr **exprargs, char *sp)
{
	/* this block folds the args and type-checks */
	unsigned long nonnulls = 0;
	unsigned i;
	attribute *da;

	if((da = func_or_builtin_attr_present(callexpr, attr_nonnull)))
		nonnulls = da->bits.nonnull_args;

	for(i = 0; exprargs[i]; i++){
		expr *arg = FOLD_EXPR(exprargs[i], stab);
		char buf[64];

		ARG_BUF(buf, i, sp);

		if(fold_check_expr(arg, FOLD_CHK_NO_ST_UN, buf))
			continue;

		if(i < count_decl && (nonnulls & (1 << i))
		&& type_is_ptr(args_from_decl->arglist[i]->ref)
		&& expr_is_null_ptr(arg, NULL_STRICT_INT))
		{
			cc1_warn_at(&arg->where,
					attr_nonnull,
					"null passed where non-null required (arg %d)",
					i + 1);
		}
	}
}
示例#2
0
static void static_array_check(
		decl *arg_decl, expr *arg_expr)
{
	/* if ty_func is x[static %d], check counts */
	type *ty_expr = arg_expr->tree_type;
	type *ty_decl = decl_is_decayed_array(arg_decl);
	consty k_decl;

	if(!ty_decl)
		return;

	assert(ty_decl->type == type_array);
	if(!ty_decl->bits.array.is_static)
		return;

	/* want to check any pointer type */
	if(expr_is_null_ptr(arg_expr, NULL_STRICT_ANY_PTR)){
		cc1_warn_at(&arg_expr->where,
				attr_nonnull,
				"passing null-pointer where array expected");
		return;
	}

	if(!ty_decl->bits.array.size)
		return;

	const_fold(ty_decl->bits.array.size, &k_decl);

	if((ty_expr = type_is_decayed_array(ty_expr))){

		assert(ty_expr->type == type_array);

		if(ty_expr->bits.array.size){
			consty k_arg;

			const_fold(ty_expr->bits.array.size, &k_arg);

			if(k_decl.type == CONST_NUM
			&& K_INTEGRAL(k_arg.bits.num)
			&& k_arg.bits.num.val.i < k_decl.bits.num.val.i)
			{
				cc1_warn_at(&arg_expr->where,
						static_array_bad,
						"array of size %" NUMERIC_FMT_D
						" passed where size %" NUMERIC_FMT_D " needed",
						k_arg.bits.num.val.i, k_decl.bits.num.val.i);
			}
		}
	}
	/* else it's a random pointer, just be quiet */
}
示例#3
0
static void sentinel_check(where *w, expr *e, expr **args,
		const int variadic, const int nstdargs, symtable *stab)
{
#define ATTR_WARN_RET(w, ...) \
	do{ cc1_warn_at(w, attr_sentinel, __VA_ARGS__); return; }while(0)

	attribute *attr = func_or_builtin_attr_present(e, attr_sentinel);
	int i, nvs;
	expr *sentinel;

	if(!attr)
		return;

	if(!variadic)
		return; /* warning emitted elsewhere, on the decl */

	if(attr->bits.sentinel){
		consty k;

		FOLD_EXPR(attr->bits.sentinel, stab);
		const_fold(attr->bits.sentinel, &k);

		if(k.type != CONST_NUM || !K_INTEGRAL(k.bits.num))
			die_at(&attr->where, "sentinel attribute not reducible to integer constant");

		i = k.bits.num.val.i;
	}else{
		i = 0;
	}

	nvs = dynarray_count(args) - nstdargs;

	if(nvs == 0)
		ATTR_WARN_RET(w, "not enough variadic arguments for a sentinel");

	UCC_ASSERT(nvs >= 0, "too few args");

	if(i >= nvs)
		ATTR_WARN_RET(w, "sentinel index is not a variadic argument");

	sentinel = args[(nstdargs + nvs - 1) - i];

	/* must be of a pointer type, printf("%p\n", 0) is undefined */
	if(!expr_is_null_ptr(sentinel, NULL_STRICT_ANY_PTR))
		ATTR_WARN_RET(&sentinel->where, "sentinel argument expected (got %s)",
				type_to_str(sentinel->tree_type));

#undef ATTR_WARN_RET
}
示例#4
0
static void try_pointer_propagate(
		expr *e, enum type_cmp cmp,
		type *const tt_l, type *const tt_r)
{
	/* 6.5.15 p6 */
	int l_ptr = !!type_is_ptr_or_block(tt_l);
	int r_ptr = !!type_is_ptr_or_block(tt_r);

	/* if both the second and third operands are pointers */
	if(l_ptr && r_ptr){
		int allowed = TYPE_EQUAL_ANY
				| TYPE_QUAL_ADD
				| TYPE_QUAL_SUB
				| TYPE_QUAL_POINTED_ADD
				| TYPE_QUAL_POINTED_SUB;

		if(cmp & allowed){
			e->tree_type = pointer_to_qualified(type_next(tt_l), tt_l, tt_r);
		}
	}

	if(!e->tree_type && (l_ptr || r_ptr)){
		/* or one is a null pointer constant and the other is a pointer */
		int l_ptr_null = expr_is_null_ptr(
				e->lhs ? e->lhs : e->expr, NULL_STRICT_INT);

		int r_ptr_null = expr_is_null_ptr(e->rhs, NULL_STRICT_INT);

		/* both may still be pointers here */
		if((l_ptr && r_ptr_null) || (r_ptr && l_ptr_null)){
			type *pointed_to;

			if(l_ptr_null != r_ptr_null){
				/* only one is an int - pick the other side */
				pointed_to = type_next(l_ptr_null ? tt_r : tt_l);
			}else{
				/* both are pointers, pick either side */
				pointed_to = type_next(l_ptr ? tt_l : tt_r);
			}

			e->tree_type = pointer_to_qualified(
					pointed_to,
					l_ptr ? tt_l : NULL,
					r_ptr ? tt_r : NULL);
		}
	}

	if(!e->tree_type && l_ptr && r_ptr){
		e->tree_type = pointer_to_qualified(
					type_nav_btype(cc1_type_nav, type_void),
					tt_l, tt_r);

		/* gcc/clang relax the rule here.
		 * 0 ? (A *)0 : (B *)0
		 * becomes a void pointer too */
		if(!type_is_void_ptr(tt_l) && !type_is_void_ptr(tt_r)){
			char buf[TYPE_STATIC_BUFSIZ];

			cc1_warn_at(&e->where,
					mismatch_conditional,
					"conditional type mismatch (%s vs %s)",
					type_to_str(tt_l), type_to_str_r(buf, tt_r));
		}
	}

	if(!e->tree_type){
		char buf[TYPE_STATIC_BUFSIZ];

		warn_at_print_error(&e->where, "conditional type mismatch (%s vs %s)",
				type_to_str(tt_l), type_to_str_r(buf, tt_r));

		fold_had_error = 1;

		e->tree_type = type_nav_btype(cc1_type_nav, type_void);
	}
}
示例#5
0
void fold_expr_if(expr *e, symtable *stab)
{
	consty konst;
	type *tt_l, *tt_r;

	FOLD_EXPR(e->expr, stab);
	const_fold(e->expr, &konst);

	fold_check_expr(e->expr, FOLD_CHK_NO_ST_UN, "if-expr");

	if(e->lhs){
		FOLD_EXPR(e->lhs, stab);
		fold_check_expr(e->lhs,
				FOLD_CHK_NO_ST_UN | FOLD_CHK_ALLOW_VOID,
				"if-lhs");
	}

	FOLD_EXPR(e->rhs, stab);
	fold_check_expr(e->rhs,
			FOLD_CHK_NO_ST_UN | FOLD_CHK_ALLOW_VOID,
			"if-rhs");


	/*

	Arithmetic                             Arithmetic                           Arithmetic type after usual arithmetic conversions
	// Structure or union type                Compatible structure or union type   Structure or union type with all the qualifiers on both operands
	void                                   void                                 void
	Pointer to compatible type             Pointer to compatible type           Pointer to type with all the qualifiers specified for the type
	Pointer to type                        NULL pointer (the constant 0)        Pointer to type
	Pointer to object or incomplete type   Pointer to void                      Pointer to void with all the qualifiers specified for the type

	GCC and Clang seem to relax the last rule:
		a) resolve if either is any pointer, not just (void *)
	  b) resolve to a pointer to the incomplete-type
	*/

	tt_l = (e->lhs ? e->lhs : e->expr)->tree_type;
	tt_r = e->rhs->tree_type;

	if(type_is_integral(tt_l) && type_is_integral(tt_r)){
		expr **middle_op = e->lhs ? &e->lhs : &e->expr;

		expr_check_sign("?:", *middle_op, e->rhs, &e->where);

		e->tree_type = op_promote_types(
				op_unknown,
				middle_op, &e->rhs, &e->where, stab);

	}else if(type_is_void(tt_l) || type_is_void(tt_r)){
		e->tree_type = type_nav_btype(cc1_type_nav, type_void);

	}else if(type_cmp(tt_l, tt_r, 0) & TYPE_EQUAL_ANY){
		/* pointer to 'compatible' type */
		e->tree_type = type_qualify(tt_l,
				type_qual(tt_l) | type_qual(tt_r));

	}else{
		/* brace yourself. */
		int l_ptr_null = expr_is_null_ptr(
				e->lhs ? e->lhs : e->expr, NULL_STRICT_VOID_PTR);

		int r_ptr_null = expr_is_null_ptr(e->rhs, NULL_STRICT_VOID_PTR);

		int l_complete = !l_ptr_null && type_is_complete(tt_l);
		int r_complete = !r_ptr_null && type_is_complete(tt_r);

		if((l_complete && r_ptr_null) || (r_complete && l_ptr_null)){
			e->tree_type = l_ptr_null ? tt_r : tt_l;

		}else{
			int l_ptr = l_ptr_null || type_is(tt_l, type_ptr);
			int r_ptr = r_ptr_null || type_is(tt_r, type_ptr);

			if(l_ptr || r_ptr){
				fold_type_chk_warn(
						tt_l, tt_r, &e->where, "?: pointer type mismatch");

				/* qualified void * */
				e->tree_type = type_qualify(
						type_ptr_to(type_nav_btype(cc1_type_nav, type_void)),
						type_qual(tt_l) | type_qual(tt_r));

			}else{
				char buf[TYPE_STATIC_BUFSIZ];

				warn_at(&e->where, "conditional type mismatch (%s vs %s)",
						type_to_str(tt_l), type_to_str_r(buf, tt_r));

				e->tree_type = type_nav_btype(cc1_type_nav, type_void);
			}
		}
	}

	e->freestanding = (e->lhs ? e->lhs : e->expr)->freestanding || e->rhs->freestanding;
}