gcc_assert (TREE_CODE (cref) == COMPONENT_REF);
const tree base = TREE_OPERAND (cref, 0);
+ const tree field = TREE_OPERAND (cref, 1);
+ access_ref base_ref = *pref;
+
+ /* Unconditionally determine the size of the base object (it could
+ be smaller than the referenced member when the object is stored
+ in a buffer with an insufficient size). */
+ if (!compute_objsize_r (base, stmt, addr, 0, &base_ref, snlim, qry))
+ return false;
+
+ /* Add the offset of the member to the offset into the object computed
+ so far. */
+ tree offset = byte_position (field);
+ if (TREE_CODE (offset) == INTEGER_CST)
+ base_ref.add_offset (wi::to_offset (offset));
+ else
+ base_ref.add_max_offset ();
+
+ if (!base_ref.ref)
+ /* PREF->REF may have been already set to an SSA_NAME earlier
+ to provide better context for diagnostics. In that case,
+ leave it unchanged. */
+ base_ref.ref = base;
+
const tree base_type = TREE_TYPE (base);
if (TREE_CODE (base_type) == UNION_TYPE)
/* In accesses through union types consider the entire unions
rather than just their members. */
ostype = 0;
- tree field = TREE_OPERAND (cref, 1);
-
if (ostype == 0)
{
/* In OSTYPE zero (for raw memory functions like memcpy), use
the maximum size instead if the identity of the enclosing
object cannot be determined. */
- if (!compute_objsize_r (base, stmt, addr, ostype, pref, snlim, qry))
- return false;
-
- /* Otherwise, use the size of the enclosing object and add
- the offset of the member to the offset computed so far. */
- tree offset = byte_position (field);
- if (TREE_CODE (offset) == INTEGER_CST)
- pref->add_offset (wi::to_offset (offset));
- else
- pref->add_max_offset ();
-
- if (!pref->ref)
- /* PREF->REF may have been already set to an SSA_NAME earlier
- to provide better context for diagnostics. In that case,
- leave it unchanged. */
- pref->ref = base;
-
+ *pref = base_ref;
return true;
}
}
set_component_ref_size (cref, pref);
+
+ if (base_ref.size_remaining () < pref->size_remaining ())
+ /* Use the base object if it's smaller than the member. */
+ *pref = base_ref;
+
return true;
}
a larger scalar into a smaller array
Verify overflow by aggregate stores.
{ dg-do compile }
- { dg-options "-O2" } */
+ { dg-options "-O2 -fno-tree-vectorize" } */
#define A(N) (A ## N)
#define Ac1 (AC1){ 0 }
void warn_comp_lit (void)
{
- *(AC2*)a1 = Ac2; // { dg-warning "writing 2 bytes into a region of size 1" "pr101475" { target { vect_slp_v2qi_store_unalign } } }
- // After vectorization, below codes are optimized to
- // MEM <vector(4) char> [(char *)&a2] = { 0, 1, 2, 3 };
- // MEM <vector(4) char> [(char *)&a3] = { 0, 1, 2, 3 };
- // MEM <vector(8) char> [(char *)&a4] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- // MEM <vector(8) char> [(char *)&a7] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- // MEM <vector(16) char> [(char *)&a15] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
- // and warning should be expected, refer to PR102722.
- *(AC4*)a2 = Ac4; // { dg-warning "writing 4 bytes into a region of size 2" "pr101475" { xfail { ! { vect_slp_v4qi_store_unalign_1 } } } }
- *(AC4*)a3 = Ac4; // { dg-warning "writing 4 bytes into a region of size 3" "pr101475" { xfail { ! { vect_slp_v4qi_store_unalign_1 } } } }
- *(AC8*)a4 = Ac8; // { dg-warning "writing 8 bytes into a region of size 4" "pr101475" { xfail { ! { vect_slp_v8qi_store_unalign_1 } } } }
- *(AC8*)a7 = Ac8; // { dg-warning "writing 8 bytes into a region of size 7" "pr101475" { xfail { ! { vect_slp_v8qi_store_unalign_1 } } } }
- *(AC16*)a15 = Ac16; // { dg-warning "writing 16 bytes into a region of size 15" "pr101475" { xfail { ! { vect_slp_v16qi_store_unalign_1 } } } }
+ /* Ideally only one warning would be issued for each of the stores
+ mentioning the size of the rest of the source being assigned to
+ the destination that doesn't fit. But without vectorization
+ the assignment is a series of one-character stores, except in
+ the first instance multiple warnings end up being issued for
+ each assignment, each saying "writing 1 byte into a region of
+ size 0". That's suboptimal and should be improved. See also
+ PR 92110. */
+ *(AC2*)a1 = Ac2; // { dg-warning "writing (2 bytes|1 byte) into a region of size (1|0)" "pr101475" }
+ *(AC4*)a2 = Ac4; // { dg-warning "writing (4 bytes|1 byte) into a region of size (2|0)" "pr101475" }
+ *(AC4*)a3 = Ac4; // { dg-warning "writing (4 bytes|1 byte) into a region of size (3|0)" "pr101475" }
+ *(AC8*)a4 = Ac8; // { dg-warning "writing (8 bytes|1 byte) into a region of size (4|0)" "pr101475" }
+ *(AC8*)a7 = Ac8; // { dg-warning "writing (8 bytes|1 byte) into a region of size (7|0)" "pr101475" }
+ *(AC16*)a15 = Ac16; // { dg-warning "writing (16 bytes|1 byte) into a region of size (15|0)" "pr101475" }
}
void warn_aggr_decl (void)
--- /dev/null
+/* PR middle-end/101475 - missing -Wstringop-overflow storing a compound
+ literal
+ { dg-do compile }
+ { dg-options "-O2 -fno-tree-vectorize" } */
+
+extern char ea1[1], ea2[2], ea3[3], ea4[4];
+
+/* The trailing A member of all of Sx, S0, and S1 is treated the same:
+ as a flexible array member. */
+struct Sx { char n, a[]; };
+struct S0 { char n, a[0]; };
+struct S1 { char n, a[1]; };
+/* The trailing A member in both S2 and S3 is treated as an ordinary
+ array with exactly two elements and accesses to elements beyond
+ the last are diagnosed regardless of whether they are within
+ the bounds the enclosing object. */
+struct S2 { char n, a[2]; };
+struct S3 { char n, a[3]; };
+
+
+void fx_ea1 (void)
+{
+ struct Sx *p = (struct Sx*)ea1;
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f0_ea1 (void)
+{
+ struct S0 *p = (struct S0*)ea1;
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f1_ea1 (void)
+{
+ struct S1 *p = (struct S1*)ea1;
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f2_ea1 (void)
+{
+ struct S2 *p = (struct S2*)ea1;
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f3_ea1 (void)
+{
+ struct S3 *p = (struct S3*)ea1;
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+
+void fx_ea1_p1 (void)
+{
+ struct Sx *p = (struct Sx*)(ea1 + 1);
+ p->n = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f0_ea1_p1 (void)
+{
+ struct S0 *p = (struct S0*)(ea1 + 1);
+ p->n = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f1_ea1_p1 (void)
+{
+ struct S1 *p = (struct S1*)(ea1 + 1);
+ p->n = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f2_ea1_p1 (void)
+{
+ struct S2 *p = (struct S2*)(ea1 + 1);
+ p->n = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f3_ea1_p1 (void)
+{
+ struct S3 *p = (struct S3*)(ea1 + 1);
+ p->n = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+
+void fx_ea2 (void)
+{
+ struct Sx *p = (struct Sx*)ea2;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f0_ea2 (void)
+{
+ struct S0 *p = (struct S0*)ea2;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f1_ea2 (void)
+{
+ struct S1 *p = (struct S1*)ea2;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f2_ea2 (void)
+{
+ struct S2 *p = (struct S2*)ea2;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f3_ea2 (void)
+{
+ struct S3 *p = (struct S3*)ea2;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+
+void fx_ea2_p1 (void)
+{
+ struct Sx *p = (struct Sx*)(ea2 + 1);
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f0_ea2_p1 (void)
+{
+ struct S0 *p = (struct S0*)(ea2 + 1);
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f1_ea2_p1 (void)
+{
+ struct S1 *p = (struct S1*)(ea2 + 1);
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f2_ea2_p1 (void)
+{
+ struct S2 *p = (struct S2*)(ea2 + 1);
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f3_ea2_p1 (void)
+{
+ struct S3 *p = (struct S3*)(ea2 + 1);
+ p->n = 0;
+ p->a[0] = 0; // { dg-warning "-Wstringop-overflow" }
+ p->a[1] = 1; // { dg-warning "-Wstringop-overflow" }
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+
+void fx_ea3 (void)
+{
+ struct Sx *p = (struct Sx*)ea3;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f0_ea3 (void)
+{
+ struct S0 *p = (struct S0*)ea3;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f1_ea3 (void)
+{
+ struct S1 *p = (struct S1*)ea3;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f2_ea3 (void)
+{
+ struct S2 *p = (struct S2*)ea3;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f3_ea3 (void)
+{
+ struct S3 *p = (struct S3*)ea3;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+
+void fx_ea4 (void)
+{
+ struct Sx *p = (struct Sx*)ea4;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2;
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f0_ea4 (void)
+{
+ struct S0 *p = (struct S0*)ea4;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2;
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f1_ea4 (void)
+{
+ struct S1 *p = (struct S1*)ea4;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2;
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f2_ea4 (void)
+{
+ struct S2 *p = (struct S2*)ea4;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ /* Even though the offset of p->a[2] is within the bounds of EA4
+ the warning triggers because it only considers trailing arrays
+ of at mnost one element as "poor man's flexible arrays." */
+ p->a[2] = 2; // { dg-warning "-Wstringop-overflow" }
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}
+
+void f3_ea4 (void)
+{
+ struct S3 *p = (struct S3*)ea4;
+ p->n = 0;
+ p->a[0] = 0;
+ p->a[1] = 1;
+ p->a[2] = 2;
+ p->a[3] = 3; // { dg-warning "-Wstringop-overflow" }
+}