aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-common.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-family/c-common.cc')
-rw-r--r--gcc/c-family/c-common.cc143
1 files changed, 107 insertions, 36 deletions
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d764..e7dd460 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print-markup.h"
#include "gcc-rich-location.h"
#include "gcc-urlifier.h"
+#include "diagnostics/diagnostics-selftests.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -394,6 +395,7 @@ const struct c_common_resword c_common_reswords[] =
{
{ "_Alignas", RID_ALIGNAS, D_CONLY },
{ "_Alignof", RID_ALIGNOF, D_CONLY },
+ { "_Countof", RID_COUNTOF, D_CONLY },
{ "_Atomic", RID_ATOMIC, D_CONLY },
{ "_BitInt", RID_BITINT, D_CONLY },
{ "_Bool", RID_BOOL, D_CONLY },
@@ -3437,20 +3439,41 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
an overflow error if the constant is negative but INTOP is not. */
&& (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (intop))
|| (TYPE_PRECISION (TREE_TYPE (intop))
- == TYPE_PRECISION (TREE_TYPE (ptrop)))))
- {
- enum tree_code subcode = resultcode;
- tree int_type = TREE_TYPE (intop);
- if (TREE_CODE (intop) == MINUS_EXPR)
- subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
- /* Convert both subexpression types to the type of intop,
- because weird cases involving pointer arithmetic
- can result in a sum or difference with different type args. */
- ptrop = build_binary_op (EXPR_LOCATION (TREE_OPERAND (intop, 1)),
- subcode, ptrop,
- convert (int_type, TREE_OPERAND (intop, 1)),
- true);
- intop = convert (int_type, TREE_OPERAND (intop, 0));
+ == TYPE_PRECISION (TREE_TYPE (ptrop))))
+ && TYPE_PRECISION (TREE_TYPE (intop)) <= TYPE_PRECISION (sizetype))
+ {
+ tree intop0 = TREE_OPERAND (intop, 0);
+ tree intop1 = TREE_OPERAND (intop, 1);
+ if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
+ || TYPE_UNSIGNED (TREE_TYPE (intop)) != TYPE_UNSIGNED (sizetype))
+ {
+ tree optype = c_common_type_for_size (TYPE_PRECISION (sizetype),
+ TYPE_UNSIGNED (sizetype));
+ intop0 = convert (optype, intop0);
+ intop1 = convert (optype, intop1);
+ }
+ tree t = fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (intop0), intop0,
+ convert (TREE_TYPE (intop0), size_exp));
+ intop0 = convert (sizetype, t);
+ if (TREE_OVERFLOW_P (intop0) && !TREE_OVERFLOW (t))
+ intop0 = wide_int_to_tree (TREE_TYPE (intop0), wi::to_wide (intop0));
+ t = fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (intop1), intop1,
+ convert (TREE_TYPE (intop1), size_exp));
+ intop1 = convert (sizetype, t);
+ if (TREE_OVERFLOW_P (intop1) && !TREE_OVERFLOW (t))
+ intop1 = wide_int_to_tree (TREE_TYPE (intop1), wi::to_wide (intop1));
+ intop = build_binary_op (EXPR_LOCATION (intop), TREE_CODE (intop),
+ intop0, intop1, true);
+
+ /* Create the sum or difference. */
+ if (resultcode == MINUS_EXPR)
+ intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop);
+
+ ret = fold_build_pointer_plus_loc (loc, ptrop, intop);
+
+ fold_undefer_and_ignore_overflow_warnings ();
+
+ return ret;
}
/* Convert the integer argument to a type the same size as sizetype
@@ -4080,6 +4103,31 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the _Countof keyword:
+ Return the number of elements of an array. */
+
+tree
+c_countof_type (location_t loc, tree type)
+{
+ enum tree_code type_code;
+
+ type_code = TREE_CODE (type);
+ if (type_code != ARRAY_TYPE)
+ {
+ error_at (loc, "invalid application of %<_Countof%> to type %qT", type);
+ return error_mark_node;
+ }
+ if (!COMPLETE_TYPE_P (type))
+ {
+ error_at (loc,
+ "invalid application of %<_Countof%> to incomplete type %qT",
+ type);
+ return error_mark_node;
+ }
+
+ return array_type_nelts_top (type);
+}
/* Handle C and C++ default attributes. */
@@ -5723,8 +5771,8 @@ struct nonnull_arg_ctx
/* The function whose arguments are being checked and its type (used
for calls through function pointers). */
const_tree fndecl, fntype;
- /* For nonnull_if_nonzero, index of the other argument. */
- unsigned HOST_WIDE_INT other;
+ /* For nonnull_if_nonzero, index of the other arguments. */
+ unsigned HOST_WIDE_INT other1, other2;
/* True if a warning has been issued. */
bool warned_p;
};
@@ -5792,6 +5840,7 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray)
check_function_arguments_recurse (check_nonnull_arg, &ctx,
argarray[i], i + 1,
OPT_Wnonnull);
+ a = NULL_TREE;
}
}
if (a == NULL_TREE)
@@ -5803,17 +5852,25 @@ check_function_nonnull (nonnull_arg_ctx &ctx, int nargs, tree *argarray)
unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
unsigned int idx2
= TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1;
+ unsigned int idx3 = idx2;
+ if (tree chain2 = TREE_CHAIN (TREE_CHAIN (args)))
+ idx3 = TREE_INT_CST_LOW (TREE_VALUE (chain2)) - 1;
if (idx < (unsigned) nargs - firstarg
&& idx2 < (unsigned) nargs - firstarg
+ && idx3 < (unsigned) nargs - firstarg
&& INTEGRAL_TYPE_P (TREE_TYPE (argarray[firstarg + idx2]))
- && integer_nonzerop (argarray[firstarg + idx2]))
+ && integer_nonzerop (argarray[firstarg + idx2])
+ && INTEGRAL_TYPE_P (TREE_TYPE (argarray[firstarg + idx3]))
+ && integer_nonzerop (argarray[firstarg + idx3]))
{
- ctx.other = firstarg + idx2 + 1;
+ ctx.other1 = firstarg + idx2 + 1;
+ ctx.other2 = firstarg + idx3 + 1;
check_function_arguments_recurse (check_nonnull_arg, &ctx,
argarray[firstarg + idx],
firstarg + idx + 1,
OPT_Wnonnull);
- ctx.other = 0;
+ ctx.other1 = 0;
+ ctx.other2 = 0;
}
}
return ctx.warned_p;
@@ -5997,14 +6054,25 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
}
else
{
- if (pctx->other)
+ if (pctx->other1 && pctx->other2 != pctx->other1)
+ warned = warning_at (loc, OPT_Wnonnull,
+ "argument %u null where non-null expected "
+ "because arguments %u and %u are nonzero",
+ (unsigned) param_num,
+ TREE_CODE (pctx->fntype) == METHOD_TYPE
+ ? (unsigned) pctx->other1 - 1
+ : (unsigned) pctx->other1,
+ TREE_CODE (pctx->fntype) == METHOD_TYPE
+ ? (unsigned) pctx->other2 - 1
+ : (unsigned) pctx->other2);
+ else if (pctx->other1)
warned = warning_at (loc, OPT_Wnonnull,
"argument %u null where non-null expected "
"because argument %u is nonzero",
(unsigned) param_num,
TREE_CODE (pctx->fntype) == METHOD_TYPE
- ? (unsigned) pctx->other - 1
- : (unsigned) pctx->other);
+ ? (unsigned) pctx->other1 - 1
+ : (unsigned) pctx->other1);
else
warned = warning_at (loc, OPT_Wnonnull,
"argument %u null where non-null expected",
@@ -6013,7 +6081,7 @@ check_nonnull_arg (void *ctx, tree param, unsigned HOST_WIDE_INT param_num)
inform (DECL_SOURCE_LOCATION (pctx->fndecl),
"in a call to function %qD declared %qs",
pctx->fndecl,
- pctx->other ? "nonnull_if_nonzero" : "nonnull");
+ pctx->other1 ? "nonnull_if_nonzero" : "nonnull");
}
if (warned)
@@ -6269,7 +6337,7 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype,
to do this if format checking is enabled. */
if (warn_nonnull)
{
- nonnull_arg_ctx ctx = { loc, fndecl, fntype, 0, false };
+ nonnull_arg_ctx ctx = { loc, fndecl, fntype, 0, 0, false };
warned_p = check_function_nonnull (ctx, nargs, argarray);
}
@@ -6958,7 +7026,7 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
/* Return the gcc option code associated with the reason for a cpp
message, or 0 if none. */
-static diagnostic_option_id
+static diagnostics::option_id
c_option_controlling_cpp_diagnostic (enum cpp_warning_reason reason)
{
const struct cpp_reason_option_codes_t *entry;
@@ -7000,8 +7068,8 @@ c_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
rich_location *richloc,
const char *msg, va_list *ap)
{
- diagnostic_info diagnostic;
- diagnostic_t dlevel;
+ diagnostics::diagnostic_info diagnostic;
+ enum diagnostics::kind dlevel;
bool save_warn_system_headers = global_dc->m_warn_system_headers;
bool ret;
@@ -7015,24 +7083,24 @@ c_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
case CPP_DL_WARNING:
if (flag_no_output)
return false;
- dlevel = DK_WARNING;
+ dlevel = diagnostics::kind::warning;
break;
case CPP_DL_PEDWARN:
if (flag_no_output && !flag_pedantic_errors)
return false;
- dlevel = DK_PEDWARN;
+ dlevel = diagnostics::kind::pedwarn;
break;
case CPP_DL_ERROR:
- dlevel = DK_ERROR;
+ dlevel = diagnostics::kind::error;
break;
case CPP_DL_ICE:
- dlevel = DK_ICE;
+ dlevel = diagnostics::kind::ice;
break;
case CPP_DL_NOTE:
- dlevel = DK_NOTE;
+ dlevel = diagnostics::kind::note;
break;
case CPP_DL_FATAL:
- dlevel = DK_FATAL;
+ dlevel = diagnostics::kind::fatal;
break;
default:
gcc_unreachable ();
@@ -9896,8 +9964,11 @@ c_family_tests (void)
c_indentation_cc_tests ();
c_pretty_print_cc_tests ();
c_spellcheck_cc_tests ();
- c_diagnostic_cc_tests ();
c_opt_problem_cc_tests ();
+
+ /* According to https://gcc.gnu.org/pipermail/gcc/2021-November/237703.html
+ this has some language-specific assumptions, so we run it here. */
+ diagnostics::selftest::context_cc_tests ();
}
} // namespace selftest
@@ -9979,7 +10050,7 @@ try_to_locate_new_include_insertion_point (const char *file, location_t loc)
return UNKNOWN_LOCATION;
/* The "start_location" is column 0, meaning "the whole line".
- rich_location and edit_context can't cope with this, so use
+ rich_location and diagnostics::changes can't cope with this, so use
column 1 instead. */
location_t col_0 = ord_map_for_insertion->start_location;
return linemap_position_for_loc_and_offset (line_table, col_0, 1);
@@ -10043,7 +10114,7 @@ maybe_add_include_fixit (rich_location *richloc, const char *header,
richloc->add_fixit_insert_before (include_insert_loc, text);
free (text);
- if (override_location && global_dc->m_source_printing.enabled)
+ if (override_location && global_dc->get_source_printing_options ().enabled)
{
/* Replace the primary location with that of the insertion point for the
fix-it hint.