diff options
Diffstat (limited to 'gcc/c-family/c-common.cc')
-rw-r--r-- | gcc/c-family/c-common.cc | 115 |
1 files changed, 91 insertions, 24 deletions
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 587d764..362dc50 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -394,6 +394,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 +3438,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 +4102,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 +5770,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 +5839,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 +5851,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 +6053,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 +6080,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 +6336,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); } |