# shellcheck shell=bash

# Check for important gcc warnings
# TODO: adapt for clang?
# TODO: add -Wformat-security

gcc_warn_check() {
	local i reset_xtrace
	local -a patterns

	# Evaluate misc gcc warnings
	# In debug mode, this variable definition and corresponding grep calls
	# will produce false positives if they're shown in the trace.
	reset_xtrace=$(shopt -o -p xtrace)
	shopt -o -u xtrace

	patterns=(
		# only will and does, no might :)
		'.*(does|will).*\[-Wstrict-aliasing\]'
		'.*\[-Wrestrict\]'
		# strict aliasing violation in C++ (Clang)
		'.*\[-Wundefined-reinterpret-cast\]'

		# implicit declaration of function ‘...’
		'.*\[-Wimplicit-function-declaration\]'
		# with -Wall, goes in pair with -Wimplicit-function-declaration
		# but without -Wall, we need to assert for it alone
		'.*incompatible implicit declaration of built-in function'
		'.*\[-Wbuiltin-declaration-mismatch\]'

		# 'is used uninitialized in this function' and some more
		'.*\[-Wuninitialized\]'
		# comparisons like ‘X<=Y<=Z’ do not have their mathematical meaning
		'.*mathematical meaning.*\[-Wparentheses\]'
		# null argument where non-null required
		'.*\[-Wnonnull\]'

		# array subscript is above/below/outside array bounds (FORTIFY_SOURCE)
		'.*\[-Warray-bounds\]'
		# attempt to free a non-heap object
		'.*\[-Wfree-nonheap-object\]'
		# those three do not have matching -W flags, it seems
		'.*will always overflow destination buffer'
		# compile-time part of FORTIFY_SOURCE
		# XXX: Commented out because of gcc FPs (https://gcc.gnu.org/PR88443)
		#'.*\[-Wstringop-overflow\]'
		# XXX: Commented out because of gcc FPs (https://gcc.gnu.org/PR97048)
		#'.*\[-Wstringop-overread\]'
		# XXX: Commented out because of gcc FPs (https://gcc.gnu.org/PR88781)
		#'.*\[-Wstringop-truncation\]'
		# clang-only, equivalent of -Wstringop-overflow
		'.*\[-Wfortify-source\]'
		'.*assuming pointer wraparound does not occur'
		'.*escape sequence out of range'

		# all clang
		'.*\[-Wstrlcpy-strlcat-size\]'
		'.*\[-Wstrncat-size\]'
		'.*\[-Wsuspicious-bzero\]'
		'.*\[-Wvarargs\]'

		# left-hand operand of comma expression has no effect
		'.*left.*comma.*\[-Wunused-value\]'
		# converting to non-pointer type ... from NULL and likes
		'.*\[-Wconversion-null\]'
		# NULL used in arithmetic
		'.*NULL.*\[-Wpointer-arith\]'
		# pointer to a function used in arithmetic and likes
		'.*function.*\[-Wpointer-arith\]'
		# the address of ... will never be NULL and likes
		# (uses of function refs & string constants in conditionals)
		# XXX: Commented out because of gcc FPs (https://gcc.gnu.org/PR103360)
		#'.*\[-Waddress\]'

		# TODO: we want to enable these but bash currently triggers
		# them with a trick in random.c where it intentionally wants
		# some truncation :(
		#
		# warning: assignment/initialization to ... from ... makes integer from pointer without cast
		#'.*\[-Wint-conversion\]'
		# warning: cast to ... from integer of different size (or smaller size)
		#'.*\[-Wint-to-pointer-cast\]'
		# warning: cast to ... from (smaller) integer type
		#'.*\[-Wint-to-void-pointer-cast\]'
		# warning: cast from ... to integer of different size
		#'.*\[-Wpointer-to-int-cast\]'

		# -Wformat
		# TODO: comment out some time in future for time_t & LFS preparedness
		#'warning: .*\[-Wformat=\]'
		# -Wformat variants
		'.*too few arguments for format'
		'.*missing sentinel in function call.*\[-Wformat=\]'
		'.*\[-Wformat-truncation\]'
		# format ... expects a matching ... argument
		# (iow, too few arguments for format in new wording :))
		'.*matching.*\[-Wformat=\]'

		# function returns address of local variable
		# XXX: Commented out for bug #925460 (https://gcc.gnu.org/PR93644)
		#'.*\[-Wreturn-local-addr\]'
		# missing return at end of function, or non-void return in a void function
		# (clang at least aggressively optimises on this)
		'.*\[-Wreturn-type\]'
		# argument to sizeof ... is the same expression as the source
		'.*\[-Wsizeof-pointer-memaccess\]'
		# iteration invokes undefined behavior
		'.*\[-Waggressive-loop-optimizations\]'
		# conversion between pointers that have incompatible types
		'.*\[-Wincompatible-pointer-types\]'
		# more specific form of -Wincompatible-pointer-types (Clang)
		'.*\[-Wincompatible-function-pointer-types\]'
		# these will fail with CFI (https://reviews.llvm.org/D134831)
		# (gcc lacks -strict)
		#'.*\[-Wcast-function-type\]'
		'.*\[-Wcast-function-type-strict\]'
		# using wrong deallocator, e.g. using free() on object allocated using my_malloc()
		# when my_malloc() is annotated as needing my_free().
		'.*\[-Wmismatched-dealloc\]'
		# clobbered: Warn for variables that might be changed by longjmp or vfork
		# (This warning is also enabled by -Wextra.)
		'.*\[-Wclobbered\]'
		# LTO type mismatch (https://wiki.gentoo.org/wiki/Project:Toolchain/LTO)
		'.*\[-Wlto-type-mismatch\]'
		# ODR (https://wiki.gentoo.org/wiki/Project:Toolchain/LTO)
		'.*\[-Wodr\]'
		# warning: argument value A will result in undefined behaviour (Clang)
		'.*\[-Wargument-undefined-behaviour\]'
		# XXX: Commented out because of GCC FPs (https://gcc.gnu.org/PR86172)
		#'.*\[-Wnull-dereference\]'

		# general sensible warnings (will be rejected by modern compilers soon)
		'.*\[-Wmain\]'
		'.*\[-Wimplicit-int\]'
		'.*\[-Wstring-compare\]'

		# this may be valid code :/
		#' multi-character character constant'
		# need to check these two ...
		#' assuming signed overflow does not occur when'
		#' comparison with string literal results in unspecified behav'
		# yacc/lex likes to trigger this one
		#' extra tokens at end of .* directive'
		# only gcc itself triggers this ?
		#' .*noreturn.* function does return'
		# these throw false positives when 0 is used instead of NULL
		#' missing sentinel in function call'
		#' not enough variable arguments to fit a sentinel'
	)

	while read -r; do
		if (( i++ == 0 )); then
			__vecho -ne '\n'
			eqawarn "QA Notice: Package triggers severe warnings which indicate that it"
			eqawarn "           may exhibit random runtime failures."
		fi
		eqawarn "${REPLY}"
	done < <(
		# Coerce C as the character type for performance reasons, per
		# bug #160234. Coerce C as the collation to guarantee that
		# ranges are handled appropriately. Also, pass -a to GNU grep
		# to prevent binary data - that is, anything containing a NUL
		# byte - from suppressing the printing of matching lines.
		export LC_ALL= LC_COLLATE=C LC_CTYPE=C
		IFS='|'
		if [[ ${PORTAGE_LOG_FILE} == *.gz ]]; then
			gzip -cd -- "${PORTAGE_LOG_FILE}"
		else
			cat -- "${PORTAGE_LOG_FILE}"
		fi \
		| sed -E -e $'s/\033\[[0-9;]*[A-Za-z]//g' \
		| grep -E -a "warning: (${patterns[*]})" \
		| awk '!seen[$0]++'
	)

	if (( i > 0 )); then
		__vecho -ne '\n'
	fi

	eval "${reset_xtrace}"

	if (( i > 0 )); then
		while read -r; do eqawarn "${REPLY}"; done <<-EOF
		Please do not file a Gentoo bug and instead report the above QA issues directly
		to the upstream developers of this software.
		Homepage: ${HOMEPAGE}
		EOF
		if contains_word stricter "${FEATURES}"; then
			die "install aborted due to severe warnings shown above"
		fi
	fi
}

if [[ ${PORTAGE_LOG_FILE} && -r ${PORTAGE_LOG_FILE} ]]; then
	gcc_warn_check
fi

: # guarantee successful exit

# vim:ft=bash
