@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "substring-locations.h"
#include "spellcheck.h"
+#include "gcc-rich-location.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -13156,4 +13157,59 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl)
return warned;
}
+/* Warn if an argument at position param_pos is passed to a
+ restrict-qualified param, and it aliases with another argument. */
+
+void
+warn_for_restrict (unsigned param_pos, vec<tree, va_gc> *args)
+{
+ tree arg = (*args)[param_pos];
+ if (TREE_VISITED (arg) || operand_equal_p (arg, null_pointer_node, 0))
+ return;
+
+ location_t loc = EXPR_LOC_OR_LOC (arg, input_location);
+ gcc_rich_location richloc (loc);
+
+ unsigned i;
+ tree current_arg;
+ int *arg_positions = XNEWVEC (int, args->length ());
+ unsigned arg_positions_len = 0;
+
+ FOR_EACH_VEC_ELT (*args, i, current_arg)
+ {
+ if (i == param_pos)
+ continue;
+
+ tree current_arg = (*args)[i];
+ if (operand_equal_p (arg, current_arg, 0))
+ {
+ TREE_VISITED (current_arg) = 1;
+ arg_positions[arg_positions_len++] = (i + 1);
+ }
+ }
+
+ if (arg_positions_len == 0)
+ {
+ free (arg_positions);
+ return;
+ }
+
+ for (unsigned i = 0; i < arg_positions_len; i++)
+ {
+ unsigned pos = arg_positions[i];
+ tree arg = (*args)[pos - 1];
+ if (EXPR_HAS_LOCATION (arg))
+ richloc.add_range (EXPR_LOCATION (arg), false);
+ }
+
+ warning_at_rich_loc_n (&richloc, OPT_Wrestrict, arg_positions_len,
+ "passing argument %i to restrict-qualified parameter"
+ " aliases with argument %Z",
+ "passing argument %i to restrict-qualified parameter"
+ " aliases with arguments %Z",
+ param_pos + 1, arg_positions, arg_positions_len);
+
+ free (arg_positions);
+}
+
#include "gt-c-family-c-common.h"
@@ -923,6 +923,7 @@ extern void c_parse_final_cleanups (void);
extern void warn_for_omitted_condop (location_t, tree);
extern void warn_for_memset (location_t, tree, tree, int);
+extern void warn_for_restrict (unsigned, vec<tree, va_gc> *);
/* These macros provide convenient access to the various _STMT nodes. */
@@ -713,6 +713,7 @@ static const format_char_info gcc_tdiag_char_table[] =
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
@@ -736,6 +737,7 @@ static const format_char_info gcc_cdiag_char_table[] =
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
@@ -762,6 +764,7 @@ static const format_char_info gcc_cxxdiag_char_table[] =
{ "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "cR", NULL },
{ "<>'R",0, STD_C89, NOARGUMENTS, "", "", NULL },
{ "m", 0, STD_C89, NOARGUMENTS, "q", "", NULL },
+ { "Z", 1, STD_C89, { T89_I, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "", &gcc_tdiag_char_table[0] },
{ NULL, 0, STD_C89, NOLENGTHS, NULL, NULL, NULL }
};
@@ -1054,6 +1054,11 @@ Wduplicate-decl-specifier
C ObjC Var(warn_duplicate_decl_specifier) Warning LangEnabledBy(C ObjC,Wall)
Warn when a declaration has duplicate const, volatile, restrict or _Atomic specifier.
+Wrestrict
+C ObjC C++ ObjC++ Var(warn_restrict) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
+Warn when an argument passed to a restrict-qualified parameter aliases with
+another argument.
+
ansi
C ObjC C++ ObjC++
A synonym for -std=c89 (for C) or -std=c++98 (for C++).
@@ -8451,6 +8451,28 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask);
}
+ if (TREE_CODE (expr.value) == FUNCTION_DECL && warn_restrict)
+ {
+ unsigned i;
+ tree arg;
+ FOR_EACH_VEC_SAFE_ELT (exprlist, i, arg)
+ TREE_VISITED (arg) = 0;
+
+ unsigned param_pos = 0;
+ function_args_iterator iter;
+ tree t;
+ FOREACH_FUNCTION_ARGS (TREE_TYPE (expr.value), t, iter)
+ {
+ if (POINTER_TYPE_P (t) && TYPE_RESTRICT (t)
+ && !TYPE_READONLY (TREE_TYPE (t)))
+ warn_for_restrict (param_pos, exprlist);
+ param_pos++;
+ }
+
+ FOR_EACH_VEC_SAFE_ELT (exprlist, i, arg)
+ TREE_VISITED (arg) = 0;
+ }
+
start = expr.get_start ();
finish = parser->tokens_buf[0].get_finish ();
expr.value
@@ -6878,6 +6878,29 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
warn_for_memset (input_location, arg0, arg2, literal_mask);
}
+ if (TREE_CODE (postfix_expression) == FUNCTION_DECL
+ && warn_restrict)
+ {
+ unsigned i;
+ tree arg;
+ FOR_EACH_VEC_SAFE_ELT (args, i, arg)
+ TREE_VISITED (arg) = 0;
+
+ unsigned param_pos = 0;
+ for (tree decl = DECL_ARGUMENTS (postfix_expression);
+ decl != NULL_TREE;
+ decl = DECL_CHAIN (decl), param_pos++)
+ {
+ tree type = TREE_TYPE (decl);
+ if (POINTER_TYPE_P (type) && TYPE_RESTRICT (type)
+ && !TYPE_READONLY (TREE_TYPE (type)))
+ warn_for_restrict (param_pos, args);
+ }
+
+ FOR_EACH_VEC_SAFE_ELT (args, i, arg)
+ TREE_VISITED (arg) = 0;
+ }
+
if (TREE_CODE (postfix_expression) == COMPONENT_REF)
{
tree instance = TREE_OPERAND (postfix_expression, 0);
@@ -65,6 +65,9 @@ extern bool warning_at (location_t, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_at_rich_loc (rich_location *, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
+extern bool warning_at_rich_loc_n (rich_location *, int, int, const char *,
+ const char *, ...)
+ ATTRIBUTE_GCC_DIAG(4, 6) ATTRIBUTE_GCC_DIAG(5, 6);
extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
extern void error_n (location_t, int, const char *, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
@@ -53,6 +53,10 @@ static bool diagnostic_impl (rich_location *, int, const char *,
static bool diagnostic_n_impl (location_t, int, int, const char *,
const char *, va_list *,
diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
+static bool diagnostic_n_impl_richloc (rich_location *, int, int, const char *,
+ const char *, va_list *,
+ diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
+
static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
static void real_abort (void) ATTRIBUTE_NORETURN;
@@ -1064,6 +1068,22 @@ diagnostic_impl (rich_location *richloc, int opt,
return report_diagnostic (&diagnostic);
}
+/* Same as diagonostic_n_impl taking rich_location instead of location_t. */
+static bool
+diagnostic_n_impl_richloc (rich_location *richloc, int opt, int n,
+ const char *singular_gmsgid,
+ const char *plural_gmsgid,
+ va_list *ap, diagnostic_t kind)
+{
+ diagnostic_info diagnostic;
+ diagnostic_set_info_translated (&diagnostic,
+ ngettext (singular_gmsgid, plural_gmsgid, n),
+ ap, richloc, kind);
+ if (kind == DK_WARNING)
+ diagnostic.option_index = opt;
+ return report_diagnostic (&diagnostic);
+}
+
/* Implement inform_n, warning_n, and error_n, as documented and
defined below. */
static bool
@@ -1072,14 +1092,9 @@ diagnostic_n_impl (location_t location, int opt, int n,
const char *plural_gmsgid,
va_list *ap, diagnostic_t kind)
{
- diagnostic_info diagnostic;
rich_location richloc (line_table, location);
- diagnostic_set_info_translated (&diagnostic,
- ngettext (singular_gmsgid, plural_gmsgid, n),
- ap, &richloc, kind);
- if (kind == DK_WARNING)
- diagnostic.option_index = opt;
- return report_diagnostic (&diagnostic);
+ return diagnostic_n_impl_richloc (&richloc, opt, n,
+ singular_gmsgid, plural_gmsgid, ap, kind);
}
bool
@@ -1170,6 +1185,21 @@ warning_at_rich_loc (rich_location *richloc, int opt, const char *gmsgid, ...)
return ret;
}
+/* Same as warning_at_rich_loc but for plural variant. */
+
+bool
+warning_at_rich_loc_n (rich_location *richloc, int opt, int n,
+ const char *singular_gmsgid, const char *plural_gmsgid, ...)
+{
+ va_list ap;
+ va_start (ap, plural_gmsgid);
+ bool ret = diagnostic_n_impl_richloc (richloc, opt, n,
+ singular_gmsgid, plural_gmsgid,
+ &ap, DK_WARNING);
+ va_end (ap);
+ return ret;
+}
+
/* A warning at LOCATION. Use this for code which is correct according to the
relevant language specification but is likely to be buggy anyway.
Returns true if the warning was printed, false if it was inhibited. */
@@ -290,7 +290,7 @@ Objective-C and Objective-C++ Dialects}.
-Wparentheses -Wno-pedantic-ms-format @gol
-Wplacement-new -Wplacement-new=@var{n} @gol
-Wpointer-arith -Wno-pointer-to-int-cast @gol
--Wno-pragmas -Wredundant-decls -Wno-return-local-addr @gol
+-Wno-pragmas -Wredundant-decls -Wrestrict -Wno-return-local-addr @gol
-Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol
-Wshift-overflow -Wshift-overflow=@var{n} @gol
-Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value @gol
@@ -5544,6 +5544,12 @@ compilations.
Warn when deleting a pointer to incomplete type, which may cause
undefined behavior at runtime. This warning is enabled by default.
+@item -Wrestrict
+@opindex Wrestrict
+@opindex Wno-restrict
+Warn when an argument passed to a restrict-qualified parameter
+aliases with another argument
+
@item -Wuseless-cast @r{(C++ and Objective-C++ only)}
@opindex Wuseless-cast
@opindex Wno-useless-cast
@@ -294,6 +294,8 @@ pp_indent (pretty_printer *pp)
integer.
%Ns: likewise, but length specified as constant in the format string.
Flag 'q': quote formatted text (must come immediately after '%').
+ %Z: Requires two arguments - array of int, and len. Prints elements
+ of the array.
Arguments can be used sequentially, or through %N$ resp. *N$
notation Nth argument after the format string. If %N$ / *N$
@@ -610,6 +612,23 @@ pp_format (pretty_printer *pp, text_info *text)
(pp, *text->args_ptr, precision, unsigned, "u");
break;
+ case 'Z':
+ {
+ int *v = va_arg (*text->args_ptr, int *);
+ unsigned len = va_arg (*text->args_ptr, unsigned);
+
+ for (unsigned i = 0; i < len; ++i)
+ {
+ pp_scalar (pp, "%i", v[i]);
+ if (i < len - 1)
+ {
+ pp_comma (pp);
+ pp_space (pp);
+ }
+ }
+ break;
+ }
+
case 'x':
if (wide)
pp_scalar (pp, HOST_WIDE_INT_PRINT_HEX,
@@ -1424,6 +1443,13 @@ test_pp_format ()
"`\33[01m\33[Kfoo\33[m\33[K' 12345678", "%qs %x",
"foo", 0x12345678);
+ /* Verify %Z. */
+ int v[] = { 1, 2, 3 };
+ ASSERT_PP_FORMAT_3 ("1, 2, 3 12345678", "%Z %x", v, 3, 0x12345678);
+
+ int v2[] = { 0 };
+ ASSERT_PP_FORMAT_3 ("0 12345678", "%Z %x", v2, 1, 0x12345678);
+
/* Verify that combinations work, along with unformatted text. */
assert_pp_format (SELFTEST_LOCATION,
"the quick brown fox jumps over the lazy dog",
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-Wrestrict" } */
+
+int foo (char *__restrict buf, const char *__restrict fmt, ...);
+
+void f(void)
+{
+ char buf[100] = "hello";
+ foo (buf, "%s-%s", buf, "world"); /* { dg-warning "passing argument 1 to restrict-qualified parameter aliases with argument 3" } */
+}
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-show-caret -Wrestrict" } */
+
+void f(int *__restrict x, int *y, int *__restrict z, int *w);
+
+void foo(int alpha, int beta)
+{
+ f (&alpha, &beta, &alpha, &alpha); /* { dg-warning "passing argument 1 to restrict-qualified parameter aliases with arguments 3, 4" } */
+
+/* { dg-begin-multiline-output "" }
+ f (&alpha, &beta, &alpha, &alpha);
+ ^~~~~~ ~~~~~~ ~~~~~~
+ { dg-end-multiline-output "" } */
+}
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-Wrestrict" } */
+
+void f(int *x, int *__restrict y);
+
+void foo(int a)
+{
+ f (&a, &a); /* { dg-warning "passing argument 2 to restrict-qualified parameter aliases with argument 1" } */
+}
@@ -32,7 +32,7 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
ullong ull, unsigned int *un, const int *cn, signed char *ss,
unsigned char *us, const signed char *css, unsigned int u1,
unsigned int u2, location_t *loc, tree t1, union tree_node *t2,
- tree *t3, tree t4[])
+ tree *t3, tree t4[], int *v, unsigned v_len)
{
/* Acceptable C90 specifiers, flags and modifiers. */
diag ("%%");
@@ -90,6 +90,10 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
cdiag ("%v%qv%#v", i, i, i);
cxxdiag ("%v%qv%#v", i, i, i);
+ tdiag ("%Z", v, v_len);
+ cdiag ("%Z", v, v_len);
+ cxxdiag ("%Z", v, v_len);
+
/* Bad stuff with extensions. */
diag ("%m", i); /* { dg-warning "format" "extra arg" } */
tdiag ("%m", i); /* { dg-warning "format" "extra arg" } */
@@ -133,6 +137,9 @@ foo (int i, int i1, int i2, unsigned int u, double d, char *s, void *p,
cdiag ("%v", t1); /* { dg-warning "format" "wrong arg" } */
cxxdiag ("%v", t1); /* { dg-warning "format" "wrong arg" } */
+ tdiag ("%Z"); /* { dg-warning "format" "missing arg" } */
+ tdiag ("%Z", t1); /* { dg-warning "format" "wrong arg" } */
+
/* Standard specifiers not accepted in the diagnostic framework. */
diag ("%X\n", u); /* { dg-warning "format" "HEX" } */
diag ("%f\n", d); /* { dg-warning "format" "float" } */