/* PR tree-optimization/84468 - Inconsistent -Wstringop-truncation warnings with -O2 { dg-do compile } { dg-options "-O2 -Wstringop-truncation -ftrack-macro-expansion=0 -g" } */ #define strncpy __builtin_strncpy struct A { char a[4]; }; void no_pred_succ_lit (struct A *p) { /* The following is folded early on, before the strncpy statement has a basic block. Verify that the case is handled gracefully (i.e., there's no assumption that the statement does have a basic block). */ strncpy (p->a, "1234", sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */ } /* Verify a strncpy call in a basic block with no predecessor or successor. */ void no_pred_succ (struct A *p, const struct A *q) { strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */ } /* Verify a strncpy call in a basic block with no successor. */ void no_succ (struct A *p, const struct A *q) { if (q->a) strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */ } /* Verify a strncpy call in a basic block with nul assignment in a successor block. */ void succ (struct A *p, const struct A *q) { /* Verify that the assignment suppresses the warning for the conditional strcnpy call. The conditional should be folded to true since the address of an array can never be null (see bug 84470). */ if (q->a) strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */ p->a[sizeof p->a - 1] = 0; } void succ_2 (struct A *p, const struct A *q, int i) { /* Same as above but with a conditional that cannot be eliminated. */ if (i < 0) strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */ p->a[sizeof p->a - 1] = 0; } /* Verify a strncpy call in a basic block with nul assignment in the next successor block. */ int next_succ (struct A *p, const struct A *q, int i, int j) { /* Same as above but with a nested conditionals with else clauses. */ if (i < 0) { if (j < 0) strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */ } else __builtin_strcpy (p->a, q->a); p->a[sizeof p->a - 1] = 0; return 0; } int next_succ_1 (struct A *p, const struct A *q, int i, int j) { /* Same as above but with a nested conditionals with else clauses. */ if (i < 0) { if (j < 0) strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */ else strncpy (p->a, q->a, sizeof p->a - 2); /* { dg-bogus "\\\[-Wstringop-truncation" } */ } p->a[sizeof p->a - 2] = 0; return 1; } int next_succ_2 (struct A *p, const struct A *q, int i, int j) { /* Same as above but with a nested conditionals with else clauses. */ if (i < 0) { if (j < 0) strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-bogus "\\\[-Wstringop-truncation" } */ else strncpy (p->a, q->a, sizeof p->a - 2); /* { dg-bogus "\\\[-Wstringop-truncation" } */ } else __builtin_strcpy (p->a, q->a); p->a[sizeof p->a - 2] = 0; return 2; } void cond_succ_warn (struct A *p, const struct A *q, int i) { /* Verify that a conditional assignment doesn't suppress the warning. */ strncpy (p->a, q->a, sizeof p->a - 1); /* { dg-warning "\\\[-Wstringop-truncation" } */ if (i < 0) p->a[sizeof p->a - 1] = 0; } void cond_succ_nowarn (struct A *p, const struct A *q) { /* Verify that distinct but provably equivalent conditionals are recognized and don't trigger the warning. */ if (p != q) strncpy (p->a, q->a, sizeof p->a - 1); if (p->a != q->a) p->a[sizeof p->a - 1] = 0; }