<commit_before>#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>

#include "defs.h"
#include "../util/util.h"
#include "data_structs.h"
#include "cc1.h"
#include "fold.h"
#include "fold_sym.h"
#include "sym.h"
#include "../util/platform.h"
#include "const.h"
#include "../util/alloc.h"
#include "../util/dynarray.h"
#include "../util/dynmap.h"
#include "sue.h"
#include "decl.h"
#include "decl_init.h"
#include "pack.h"
#include "funcargs.h"
#include "out/lbl.h"

decl     *curdecl_func;
type_ref *curdecl_ref_func_called; /* for funcargs-local labels and return type-checking */

/* FIXME: don't have the callers do type_ref_to_str() */
int fold_type_ref_equal(
		type_ref *a, type_ref *b, where *w,
		enum warning warn, enum decl_cmp extra_flags,
		const char *errfmt, ...)
{
	enum decl_cmp flags = extra_flags | DECL_CMP_ALLOW_VOID_PTR;

	if(!type_ref_is(a, type_ref_ptr) && !type_ref_is(b, type_ref_ptr))
		flags |= DECL_CMP_ALLOW_SIGNED_UNSIGNED;

	/* stronger checks for blocks, functions and and (non-void) pointers */
	if(type_ref_is_nonvoid_ptr(a)
	&& type_ref_is_nonvoid_ptr(b))
	{
		flags |= DECL_CMP_EXACT_MATCH;
	}
	else
	if(type_ref_is(a, type_ref_block)
	|| type_ref_is(b, type_ref_block)
	|| type_ref_is(a, type_ref_func)
	|| type_ref_is(b, type_ref_func))
	{
		flags |= DECL_CMP_EXACT_MATCH;
	}

	if(type_ref_equal(a, b, flags)){
		return 1;
	}else{
		int one_struct;
		va_list l;

		if(fopt_mode & FOPT_PLAN9_EXTENSIONS){
			/* allow b to be an anonymous member of a */
			struct_union_enum_st *a_sue = type_ref_is_s_or_u(type_ref_is_ptr(a)),
													 *b_sue = type_ref_is_s_or_u(type_ref_is_ptr(b));

			if(a_sue && b_sue /* they aren't equal */){
				/* b_sue has an a_sue,
				 * the implicit cast adjusts to return said a_sue */
				if(struct_union_member_find_sue(b_sue, a_sue))
					goto fin;
			}
		}

		/*cc1_warn_at(w, 0, 0, warn, "%s vs. %s for...", decl_to_str(a), decl_to_str_r(buf, b));*/

		one_struct = type_ref_is_s_or_u(a) || type_ref_is_s_or_u(b);

		va_start(l, errfmt);
		cc1_warn_atv(w, one_struct || type_ref_is_void(a) || type_ref_is_void(b), warn, errfmt, l);
		va_end(l);
	}
fin:
	return 0;
}

void fold_insert_casts(type_ref *dlhs, expr **prhs, symtable *stab, where *w, const char *desc)
{
	expr *const rhs = *prhs;

	if(!type_ref_equal(dlhs, rhs->tree_type,
				DECL_CMP_ALLOW_VOID_PTR |
				DECL_CMP_EXACT_MATCH))
	{
		/* insert a cast: rhs -> lhs */
		expr *cast;

		cast = expr_new_cast(rhs, dlhs, 1);
		*prhs = cast;

		/* need to fold the cast again - mainly for "loss of precision" warning */
		fold_expr_cast_descend(cast, stab, 0);
	}

	if(type_ref_is_signed(dlhs) != type_ref_is_signed(rhs->tree_type)){
		cc1_warn_at(w, 0, WARN_SIGN_COMPARE,
				"operation between signed and unsigned in %s", desc);
	}
}


void fold_check_restrict(expr *lhs, expr *rhs, const char *desc, where *w)
{
	/* restrict operation checks */
	const enum type_qualifier ql = type_ref_qual(lhs->tree_type),
				                    qr = type_ref_qual(rhs->tree_type);

	if((ql & qual_restrict) && (qr & qual_restrict))<commit_msg>Implicit casts mirror their operand's location<commit_after>#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>

#include "defs.h"
#include "../util/util.h"
#include "data_structs.h"
#include "cc1.h"
#include "fold.h"
#include "fold_sym.h"
#include "sym.h"
#include "../util/platform.h"
#include "const.h"
#include "../util/alloc.h"
#include "../util/dynarray.h"
#include "../util/dynmap.h"
#include "sue.h"
#include "decl.h"
#include "decl_init.h"
#include "pack.h"
#include "funcargs.h"
#include "out/lbl.h"

decl     *curdecl_func;
type_ref *curdecl_ref_func_called; /* for funcargs-local labels and return type-checking */

/* FIXME: don't have the callers do type_ref_to_str() */
int fold_type_ref_equal(
		type_ref *a, type_ref *b, where *w,
		enum warning warn, enum decl_cmp extra_flags,
		const char *errfmt, ...)
{
	enum decl_cmp flags = extra_flags | DECL_CMP_ALLOW_VOID_PTR;

	if(!type_ref_is(a, type_ref_ptr) && !type_ref_is(b, type_ref_ptr))
		flags |= DECL_CMP_ALLOW_SIGNED_UNSIGNED;

	/* stronger checks for blocks, functions and and (non-void) pointers */
	if(type_ref_is_nonvoid_ptr(a)
	&& type_ref_is_nonvoid_ptr(b))
	{
		flags |= DECL_CMP_EXACT_MATCH;
	}
	else
	if(type_ref_is(a, type_ref_block)
	|| type_ref_is(b, type_ref_block)
	|| type_ref_is(a, type_ref_func)
	|| type_ref_is(b, type_ref_func))
	{
		flags |= DECL_CMP_EXACT_MATCH;
	}

	if(type_ref_equal(a, b, flags)){
		return 1;
	}else{
		int one_struct;
		va_list l;

		if(fopt_mode & FOPT_PLAN9_EXTENSIONS){
			/* allow b to be an anonymous member of a */
			struct_union_enum_st *a_sue = type_ref_is_s_or_u(type_ref_is_ptr(a)),
													 *b_sue = type_ref_is_s_or_u(type_ref_is_ptr(b));

			if(a_sue && b_sue /* they aren't equal */){
				/* b_sue has an a_sue,
				 * the implicit cast adjusts to return said a_sue */
				if(struct_union_member_find_sue(b_sue, a_sue))
					goto fin;
			}
		}

		/*cc1_warn_at(w, 0, 0, warn, "%s vs. %s for...", decl_to_str(a), decl_to_str_r(buf, b));*/

		one_struct = type_ref_is_s_or_u(a) || type_ref_is_s_or_u(b);

		va_start(l, errfmt);
		cc1_warn_atv(w, one_struct || type_ref_is_void(a) || type_ref_is_void(b), warn, errfmt, l);
		va_end(l);
	}
fin:
	return 0;
}

void fold_insert_casts(type_ref *dlhs, expr **prhs, symtable *stab, where *w, const char *desc)
{
	expr *const rhs = *prhs;

	if(!type_ref_equal(dlhs, rhs->tree_type,
				DECL_CMP_ALLOW_VOID_PTR |
				DECL_CMP_EXACT_MATCH))
	{
		/* insert a cast: rhs -> lhs */
		expr *cast = expr_set_where(
				expr_new_cast(rhs, dlhs, 1),
				&rhs->where);

		*prhs = cast;

		/* need to fold the cast again - mainly for "loss of precision" warning */
		fold_expr_cast_descend(cast, stab, 0);
	}

	if(type_ref_is_signed(dlhs) != type_ref_is_signed(rhs->tree_type)){
		cc1_warn_at(w, 0, WARN_SIGN_COMPARE,
				"operation between signed and unsigned in %s", desc);
	}
}


void fold_check_restrict(expr *lhs, expr *rhs, const char *desc, where *w)
{
	/* restrict operation checks */
	const enum type_qualifier ql = type_ref_qual(lhs->tree_type),
				                    qr = type_ref_qual(rhs->tree_type);

	if((ql & qual_restrict) && (qr & qual_restrict))
{'fraction_non_alphanumeric': 0.14410688722761253, 'fraction_numerical': 0.0038174009861619215, 'mean_word_length': 4.231281198003328, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '602258', 'n_tokens_mistral': 2848, 'n_tokens_neox': 2640, 'n_words': 553}