1 /* Test to verify that snprintf can determine the length of a dynamically
2    constructed string argument and fold the result into a constant.
3    { dg-do compile }
4    { dg-options "-O2 -Wall -fdump-tree-optimized" } */
5 
6 typedef __SIZE_TYPE__ size_t;
7 
8 char* strcpy (char * restrict, const char * restrict);
9 int sprintf (char * restrict, const char *restrict, ...);
10 int snprintf (char * restrict, size_t, const char *restrict, ...);
11 
12 
13 #define CONCAT(x, y) x ## y
14 #define CAT(x, y) CONCAT (x, y)
15 #define FAILNAME(name, counter)						\
16   CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter)
17 
18 #define FAIL(name, counter) do {			\
19     extern void FAILNAME (name, counter) (void);	\
20     FAILNAME (name, counter)();				\
21   } while (0)
22 
23 /* Macro to emit a call to funcation named
24    call_in_true_branch_not_eliminated_on_line_NNN()
25    for each call that's expected to be eliminated.  The dg-final
26    scan-tree-dump-time directive at the bottom of the test verifies
27    that no such call appears in output.  */
28 #define ELIM(expr)							\
29   if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0
30 
31 #define ARGS(...) __VA_ARGS__
32 
33 #define T(expect, init, fmt, ...)			\
34   do {							\
35     char a[] = init;					\
36     ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));	\
37   } while (0)
38 
39 /* Exercise a non-const local char array initialized by a string literal.  */
test_assign_string(void)40 void test_assign_string (void)
41 {
42   T (0, "", "%s", a);
43   T (1, "1", "%s", a);
44   T (4, "1234", "%s", a);
45   T (5, "123", "s=%s", a);
46   T (5, "1234", "s=%s", a + 1);
47   T (2, "1234", "s=%s", a + 4);
48   T (5, "12345", "s=%s", &a[2]);
49   T (5, "123456", "s=%.*s", 3, &a[2]);
50 }
51 
52 /* Exercise a non-const local char array initialized by an initializer
53    list.  */
test_assign_init_list(void)54 void test_assign_init_list (void)
55 {
56   T (0, ARGS ({ 0 }), "%s", a);
57   T (1, ARGS ({ 1, 0 }), "%s", a);
58   T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3 }), "%s", a);
59   T (3, ARGS ({ [3] = 0, [1] = 2, [0] = 1, [2] = 3, [4] = 0 }), "%s", a);
60   T (4, ARGS ({ 1, 2, 3, 4, 0 }), "%s", a);
61   T (5, ARGS ({ 1, 2, 3, 0 }), "s=%s", a);
62   T (5, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 1);
63   T (2, ARGS ({ 1, 2, 3, 4, 0 }), "s=%s", a + 4);
64   T (5, ARGS ({ 1, 2, 3, 4, 5, 0 }), "s=%s", &a[2]);
65   T (5, ARGS ({ 1, 2, 3, 4, 5, 6, 0 }), "s=%.*s", 3, &a[2]);
66 }
67 
68 #if __x86_64__
69 
70 /* Enabled only on x86_64 to work around PR 83543.  */
71 
72 #undef T
73 #define T(expect, init, fmt, ...)			\
74   do {							\
75     struct { int n; char a[sizeof init]; }		\
76     s = { sizeof init, init };				\
77     ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));	\
78   } while (0)
79 
80 /* Exercise a non-const local struct initialized by an initializer
81    list.  */
test_assign_aggregate(void)82 void test_assign_aggregate (void)
83 {
84   T (0, "", "%s", s.a);
85   T (1, "1", "%s", s.a);
86   T (4, "1234", "%s", s.a);
87   T (5, "123", "s=%s", s.a);
88   T (5, "1234", "s=%s", s.a + 1);
89   T (2, "1234", "s=%s", s.a + 4);
90   T (5, "12345", "s=%s", &s.a[2]);
91   T (5, "123456", "s=%.*s", 3, &s.a[2]);
92 }
93 
94 /* { dg-final { scan-tree-dump-times "Function test_assign_aggregate" 1 "optimized" { xfail { { ! x86_64-*-* } || { ilp32 } } } } } */
95 
96 #endif   /* x86_64 */
97 
98 #undef T
99 #define T(expect, init, fmt, ...)			\
100   do {							\
101     char a[sizeof init];				\
102     strcpy (a, init);					\
103     ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));	\
104   } while (0)
105 
106 /* Exercise a local char array initialized by a call to strcpy.  */
test_local_strcpy(void)107 void test_local_strcpy (void)
108 {
109   T (0, "", "%s", a);
110   T (1, "1", "%s", a);
111   T (2, "12", "%s", a);
112   T (3, "123", "%s", a);
113   T (4, "1234", "%s", a);
114   T (5, "123", "s=%s", a);
115   T (5, "1234", "s=%s", a + 1);
116   T (2, "1234", "s=%s", a + 4);
117   T (5, "12345", "s=%s", &a[2]);
118   T (5, "123456", "s=%.*s", 3, &a[2]);
119 }
120 
121 #undef T
122 #define T(expect, init, fmt, ...)			\
123   do {							\
124     char a[n];						\
125     strcpy (a, init);					\
126     ELIM (expect == snprintf (0, 0, fmt, __VA_ARGS__));	\
127   } while (0)
128 
129 /* Exercise a VLA initialized by a call to strcpy.  */
test_vla_strcpy(unsigned n)130 void test_vla_strcpy (unsigned n)
131 {
132   T (0, "", "%s", a);
133   T (1, "1", "%s", a);
134   T (2, "12", "%s", a);
135   T (3, "123", "%s", a);
136   T (4, "1234", "%s", a);
137   T (5, "123", "s=%s", a);
138   T (5, "1234", "s=%s", a + 1);
139   T (2, "1234", "s=%s", a + 4);
140   T (5, "12345", "s=%s", &a[2]);
141   T (5, "123456", "s=%.*s", 3, &a[2]);
142 }
143 
144 /* { dg-final { scan-tree-dump-times "printf" 0 "optimized" } }
145    { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
146    { dg-final { scan-tree-dump-times "not_eliminated" 0 "optimized" } } */
147