--- /dev/null
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const arguments
+ Verify that -Wuninitialized and -Wmaybe-uninitialized trigger (or don't)
+ when passing uninitialized variables by reference to functions declared
+ with or without attribute access and with (or without) const qualified
+ arguments of array, VLA, or pointer types.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NONE /* none */
+#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
+#define X(...) __attribute__ ((access (none, __VA_ARGS__)))
+
+#define CONCAT(x, y) x ## y
+#define CAT(x, y) CONCAT (x, y)
+#define UNIQ(pfx) CAT (pfx, __LINE__)
+
+extern void sink (void*);
+
+
+#define T1(attr, name, type) \
+ void UNIQ (CAT (test_, name))(void) { \
+ extern attr void UNIQ (name)(type); \
+ int x; \
+ UNIQ (name)(&x); \
+ sink (&x); \
+ }
+
+#define T2(attr, name, types) \
+ void UNIQ (CAT (test_, name))(void) { \
+ extern attr void UNIQ (name)(types); \
+ int x; \
+ UNIQ (name)(1, &x); \
+ sink (&x); \
+ }
+
+
+typedef int IA_[];
+typedef const int CIA_[];
+
+T1 (NONE, fia_, IA_);
+T1 (NONE, fcia_, CIA_); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia_, IA_); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia_, IA_); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia_, IA_);
+T1 (X (1), fxia_, IA_);
+
+
+typedef int IA1[1];
+typedef const int CIA1[1];
+
+T1 (NONE, fia1, IA1);
+T1 (NONE, fcia1, CIA1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia1, IA1); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia1, IA1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia1, IA1);
+T1 (X (1), fxia1, IA1);
+
+
+#define IARS1 int[restrict static 1]
+#define CIARS1 const int[restrict static 1]
+
+T1 (NONE, fiars1, IARS1);
+T1 (NONE, fciars1, CIARS1);// { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiars1, IARS1); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiars1, IARS1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiars1, IARS1);
+T1 (X (1), fxiars1, IARS1);
+
+
+#define IAS1 int[static 1]
+#define CIAS1 const int[static 1]
+
+T1 (NONE, fias1, IAS1);
+T1 (NONE, fcias1, CIAS1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froias1, IAS1); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwias1, IAS1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoias1, IAS1);
+T1 (X (1), fxias1, IAS1);
+
+
+#define IAX int[*]
+#define CIAX const int[*]
+
+T1 (NONE, fiax, IAX);
+T1 (NONE, fciax, CIAX); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiax, IAX); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiax, IAX); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiax, IAX);
+T1 (X (1), fxiax, IAX);
+
+
+#define IAN int n, int[n]
+#define CIAN int n, const int[n]
+
+T2 (NONE, fian, IAN);
+T2 (NONE, fcian, CIAN); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (RO (2, 1), froian, IAN); // { dg-warning "\\\[-Wuninitialized" }
+T2 (RW (2, 1), frwian, IAN); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (WO (2, 1), fwoian, IAN);
+T2 (X (2, 1), fxian, IAN);
+
+
+typedef int* IP;
+typedef const int* CIP;
+
+T1 (NONE, fip, IP);
+T1 (NONE, fcip, CIP); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froip, IP); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwip, IP); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoip, IP);
+T1 (X (1), fxip, IP);
+
+
+/* Verify that the notes printed after the warning mention attribute
+ access only when the attribute is explicitly used in the declaration
+ and not otherwise. */
+
+void test_note_cst_restrict (void)
+{
+ extern void
+ fccar (const char[restrict]); // { dg-message "by argument 1 of type 'const char\\\[restrict]' to 'fccar'" "note" }
+
+ char a[1]; // { dg-message "'a' declared here" "note" }
+ fccar (a); // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_vla (int n)
+{
+ extern void
+ fccvla (const char[n]); // { dg-message "by argument 1 of type 'const char\\\[n]' to 'fccvla'" "note" }
+
+ char a[2]; // { dg-message "'a' declared here" "note" }
+ fccvla (a); // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_ro (void)
+{
+ extern RO (1) void
+ frocar (char[restrict]); // { dg-message "in a call to 'frocar' declared with attribute 'access \\\(read_only, 1\\\)'" "note" }
+
+ char a[3]; // { dg-message "'a' declared here" "note" }
+ frocar (a); // { dg-warning "'a' is used uninitialized" }
+}
+
+void test_note_rw (void)
+{
+ extern RW (1) void
+ frwcar (char[restrict]); // { dg-message "in a call to 'frwcar' declared with attribute 'access \\\(read_write, 1\\\)'" "note" }
+
+ char a[4]; // { dg-message "'a' declared here" "note" }
+ frwcar (a); // { dg-warning "'a' may be used uninitialized" }
+}
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+#define INCLUDE_STRING
#include "config.h"
#include "system.h"
#include "coretypes.h"
read_only. */
const bool save_always_executed = wlims.always_executed;
- /* Map of attribute access specifications for function arguments. */
+ /* Initialize a map of attribute access specifications for arguments
+ to the function function call. */
rdwr_map rdwr_idx;
init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
continue;
tree access_size = NULL_TREE;
- attr_access *access = rdwr_idx.get (argno - 1);
+ const attr_access* access = rdwr_idx.get (argno - 1);
if (access)
{
if (access->mode == access_none
|| access->mode == access_write_only)
continue;
+
+ if (access->mode == access_deferred
+ && !TYPE_READONLY (TREE_TYPE (argtype)))
+ continue;
+
if (save_always_executed && access->mode == access_read_only)
/* Attribute read_only arguments imply read access. */
wlims.always_executed = true;
if (!argbase)
continue;
- if (access)
+ if (access && access->mode != access_deferred)
{
- const char* const mode = (access->mode == access_read_only
- ? "read_only" : "read_write");
- char attrstr[80];
- int n = sprintf (attrstr, "access (%s, %u", mode, argno);
- if (access->sizarg < UINT_MAX)
- sprintf (attrstr + n, ", %u)", access->sizarg);
- else
- strcpy (attrstr + n, ")");
+ const char* const access_str =
+ TREE_STRING_POINTER (access->to_external_string ());
if (fndecl)
{
location_t loc = DECL_SOURCE_LOCATION (fndecl);
- inform (loc, "in a call to %qD declared "
- "with attribute %<access (%s, %u)%> here",
- fndecl, mode, argno);
+ inform (loc, "in a call to %qD declared with "
+ "attribute %<%s%> here", fndecl, access_str);
}
else
{
/* Handle calls through function pointers. */
location_t loc = gimple_location (stmt);
inform (loc, "in a call to %qT declared with "
- "attribute %<access (%s, %u)%>",
- fntype, mode, argno);
+ "attribute %<%s%>", fntype, access_str);
}
}
- else if (fndecl)
- {
- location_t loc = DECL_SOURCE_LOCATION (fndecl);
- inform (loc, "by argument %u of type %qT to %qD declared here",
- argno, argtype, fndecl);
- }
else
{
- /* Handle calls through function pointers. */
- location_t loc = gimple_location (stmt);
- inform (loc, "by argument %u of type %qT to %qT",
- argno, argtype, fntype);
+ /* For a declaration with no relevant attribute access create
+ a dummy object and use the formatting function to avoid
+ having to complicate things here. */
+ attr_access ptr_access = { };
+ if (!access)
+ access = &ptr_access;
+ const std::string argtypestr = access->array_as_string (argtype);
+ if (fndecl)
+ {
+ location_t loc (DECL_SOURCE_LOCATION (fndecl));
+ inform (loc, "by argument %u of type %<%s%> to %qD "
+ "declared here",
+ argno, argtypestr.c_str (), fndecl);
+ }
+ else
+ {
+ /* Handle calls through function pointers. */
+ location_t loc (gimple_location (stmt));
+ inform (loc, "by argument %u of type %<%s%> to %qT",
+ argno, argtypestr.c_str (), fntype);
+ }
}
if (DECL_P (argbase))