blob: df0e6b7d19c89f96f30c909487b502ccf0202746 [file] [log] [blame]
/* Test to verify that snprintf can determine the length of a dynamically
constructed string argument and fold the result into a constant.
{ dg-do compile }
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
typedef __SIZE_TYPE__ size_t;
char* strcpy (char * restrict, const char * restrict);
int sprintf (char * restrict, const char *restrict, ...);
int snprintf (char * restrict, size_t, const char *restrict, ...);
#define CONCAT(x, y) x ## y
#define CAT(x, y) CONCAT (x, y)
#define FAILNAME(name, counter) \
CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter)
#define FAIL(name, counter) do { \
extern void FAILNAME (name, counter) (void); \
FAILNAME (name, counter)(); \
} while (0)
/* Macro to emit a call to funcation named
call_in_true_branch_not_eliminated_on_line_NNN()
for each call that's expected to be eliminated. The dg-final
scan-tree-dump-time directive at the bottom of the test verifies
that no such call appears in output. */
#define ELIM(expr) \
if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0
#define ARGS(...) __VA_ARGS__
#define T(expect, init, fmt, ...) \
do { \
char a[] = init; \
ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \
} while (0)
/* Exercise a non-const local char array initialized by a string literal. */
void test_assign_string (void)
{
T (0, "", "%s", a);
T (1, "1", "%s", a);
T (4, "1234", "%s", a);
T (5, "123", "s=%s", a);
T (5, "1234", "s=%s", a + 1);
T (2, "1234", "s=%s", a + 4);
T (5, "12345", "s=%s", &a[2]);
T (5, "123456", "s=%.*s", 3, &a[2]);
}
/* Exercise a non-const local char array initialized by an initializer
list. */
void test_assign_init_list (void)
{
T (0, ARGS ({ 0 }), "%s", a);
T (1, ARGS ({ 1, 0 }), "%s", a);
T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3 }), "%s", a);
T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3, [4] = 0 }), "%s", a);
T (4, ARGS ({ 1, 2, 3, 4, 0 }), "%s", a);
T (5, ARGS ({ 1, 2, 3, 0 }), "s=%s", a);
T (5, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 1);
T (2, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 4);
T (5, ARGS ({ 1, 2, 3, 4, 5, 0 }), "s=%s", &a[2]);
T (5, ARGS ({ 1, 2, 3, 4, 5, 6, 0 }), "s=%.*s", 3, &a[2]);
}
#if __x86_64__
/* Enabled only on x86_64 to work around PR 83543. */
#undef T
#define T(expect, init, fmt, ...) \
do { \
struct { int n; char a[sizeof init]; } \
s = { sizeof init, init }; \
ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \
} while (0)
/* Exercise a non-const local struct initialized by an initializer
list. */
void test_assign_aggregate (void)
{
T (0, "", "%s", s.a);
T (1, "1", "%s", s.a);
T (4, "1234", "%s", s.a);
T (5, "123", "s=%s", s.a);
T (5, "1234", "s=%s", s.a + 1);
T (2, "1234", "s=%s", s.a + 4);
T (5, "12345", "s=%s", &s.a[2]);
T (5, "123456", "s=%.*s", 3, &s.a[2]);
}
/* { dg-final { scan-tree-dump-times "Function test_assign_aggregate" 1 "optimized" { xfail { { ! x86_64-*-* } || { ilp32 } } } } } */
#endif /* x86_64 */
#undef T
#define T(expect, init, fmt, ...) \
do { \
char a[sizeof init]; \
strcpy (a, init); \
ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \
} while (0)
/* Exercise a local char array initialized by a call to strcpy. */
void test_local_strcpy (void)
{
T (0, "", "%s", a);
T (1, "1", "%s", a);
T (2, "12", "%s", a);
T (3, "123", "%s", a);
T (4, "1234", "%s", a);
T (5, "123", "s=%s", a);
T (5, "1234", "s=%s", a + 1);
T (2, "1234", "s=%s", a + 4);
T (5, "12345", "s=%s", &a[2]);
T (5, "123456", "s=%.*s", 3, &a[2]);
}
#undef T
#define T(expect, init, fmt, ...) \
do { \
char a[n]; \
strcpy (a, init); \
ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__)); \
} while (0)
/* Exercise a VLA initialized by a call to strcpy. */
void test_vla_strcpy (unsigned n)
{
T (0, "", "%s", a);
T (1, "1", "%s", a);
T (2, "12", "%s", a);
T (3, "123", "%s", a);
T (4, "1234", "%s", a);
T (5, "123", "s=%s", a);
T (5, "1234", "s=%s", a + 1);
T (2, "1234", "s=%s", a + 4);
T (5, "12345", "s=%s", &a[2]);
T (5, "123456", "s=%.*s", 3, &a[2]);
}
/* { dg-final { scan-tree-dump-times "printf" 0 "optimized" } }
{ dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
{ dg-final { scan-tree-dump-times "not_eliminated" 0 "optimized" } } */