summaryrefslogtreecommitdiff
path: root/tests/t0058-variadic-macros.sh
blob: 584e9802d9bf322634fcacd25aa92af4ffa30063 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/bin/sh
set -eu
base="${TMPDIR-/tmp}/mcpu-cpp-variadic-$$"
mkdir -p "$base"
trap 'rm -rf "$base"' EXIT HUP INT TERM

cat > "$base/main.c" <<'EOT'
#define A 7
#define SUM(X, Y) X + Y
#define V(...) <__VA_ARGS__>
#define F(first, ...) first | __VA_ARGS__
#define STRV(...) #__VA_ARGS__
#define LEFT(...) pre ## __VA_ARGS__
#define RIGHT(...) __VA_ARGS__ ## post
#define CALL(FN, ...) FN(__VA_ARGS__)
#define WRAP(...) V(__VA_ARGS__)
#define ID(X) X
#define РУССКИЙ(первый, ...) первый : __VA_ARGS__

V(alpha, beta, gamma)
V()
F(one, two, three)
F(one)
F(one,)
F(A, SUM(1, 2))
STRV(A, b   +   c)
LEFT(fix)
LEFT()
RIGHT(fix)
RIGHT()
CALL(ID, A)
WRAP(A, SUM(3, 4))
РУССКИЙ(один, два, три)
EOT

"$MCPU_CPP" --no-config "$base/main.c" -o "$base/out"

grep -Fx '<alpha, beta, gamma>' "$base/out" >/dev/null
grep -Fx '<>' "$base/out" >/dev/null
grep -Fx 'one | two, three' "$base/out" >/dev/null
# Both an omitted variadic tail and an explicitly empty one expand to no tokens.
test "$(grep -Fxc 'one | ' "$base/out")" -eq 2
grep -Fx '7 | 1 + 2' "$base/out" >/dev/null
grep -Fx '"A, b + c"' "$base/out" >/dev/null
grep -Fx 'prefix' "$base/out" >/dev/null
grep -Fx 'pre' "$base/out" >/dev/null
grep -Fx 'fixpost' "$base/out" >/dev/null
grep -Fx 'post' "$base/out" >/dev/null
grep -Fx '7' "$base/out" >/dev/null
grep -Fx '<7, 3 + 4>' "$base/out" >/dev/null
grep -Fx 'один : два, три' "$base/out" >/dev/null

# The variable argument is preserved as such when macro definitions are dumped.
"$MCPU_CPP" --no-config -dM "$base/main.c" > "$base/dump"
grep -Fx '#define V(...) <__VA_ARGS__>' "$base/dump" >/dev/null
grep -Fx '#define F(first,...) first | __VA_ARGS__' "$base/dump" >/dev/null
grep -Fx '#define STRV(...) #__VA_ARGS__' "$base/dump" >/dev/null
grep -Fx '#define РУССКИЙ(первый,...) первый : __VA_ARGS__' "$base/dump" >/dev/null


# Variadic-ness is part of a macro definition.  Repeating the same variadic
# definition is harmless, while changing a non-variadic definition into a
# variadic one is a real redefinition and therefore participates in -Werror.
cat > "$base/redefine-same.c" <<'EOT'
#define SAME(x, ...) x | __VA_ARGS__
#define SAME(x, ...) x | __VA_ARGS__
SAME(1, 2)
EOT
"$MCPU_CPP" --no-config "$base/redefine-same.c" \
  -o "$base/redefine-same.out" 2>"$base/redefine-same.err"
test ! -s "$base/redefine-same.err"
grep -Fx '1 | 2' "$base/redefine-same.out" >/dev/null

cat > "$base/redefine-kind.c" <<'EOT'
#define CHANGE(x) x
#define CHANGE(x, ...) x | __VA_ARGS__
EOT
if "$MCPU_CPP" --no-config -Werror "$base/redefine-kind.c" \
     -o "$base/redefine-kind.out" 2>"$base/redefine-kind.err"; then
  echo 'variadic/non-variadic redefinition escaped -Werror' >&2
  exit 1
fi
grep "error: macro 'CHANGE' redefined" "$base/redefine-kind.err" >/dev/null

# A variadic macro may have fixed parameters, but those fixed parameters are
# still required.  An empty spelling counts as an argument, just as it does
# for ordinary function-like macros.
cat > "$base/few.c" <<'EOT'
#define NEEDS_TWO(a, b, ...) a + b + __VA_ARGS__
NEEDS_TWO(1)
EOT
if "$MCPU_CPP" --no-config "$base/few.c" -o "$base/few.out" 2>"$base/few.err"; then
  echo 'variadic macro accepted too few fixed arguments' >&2
  exit 1
fi
grep "macro 'NEEDS_TWO' used with too few arguments" "$base/few.err" >/dev/null

# The old GNU named variadic form is deliberately outside the 0.0.46
# contract.  Only the C99-style ... + __VA_ARGS__ form is accepted.
cat > "$base/named.c" <<'EOT'
#define OLD(args...) args
EOT
if "$MCPU_CPP" --no-config "$base/named.c" -o "$base/named.out" 2>"$base/named.err"; then
  echo 'GNU named variadic macro form unexpectedly accepted' >&2
  exit 1
fi
grep 'badly punctuated parameter list in #define' "$base/named.err" >/dev/null

cat > "$base/malformed.c" <<'EOT'
#define BAD(..., x) x
EOT
if "$MCPU_CPP" --no-config "$base/malformed.c" -o "$base/malformed.out" 2>"$base/malformed.err"; then
  echo 'parameters after ... unexpectedly accepted' >&2
  exit 1
fi
grep 'badly punctuated parameter list in #define' "$base/malformed.err" >/dev/null

cat > "$base/reserved.c" <<'EOT'
#define BAD(__VA_ARGS__) __VA_ARGS__
EOT
if "$MCPU_CPP" --no-config "$base/reserved.c" -o "$base/reserved.out" 2>"$base/reserved.err"; then
  echo '__VA_ARGS__ unexpectedly accepted as an ordinary parameter name' >&2
  exit 1
fi
grep "'__VA_ARGS__' cannot be used as a macro parameter name" "$base/reserved.err" >/dev/null

# A replacement using #__VA_ARGS__ is valid only for a variadic macro.
cat > "$base/not-variadic.c" <<'EOT'
#define BAD(x) #__VA_ARGS__
EOT
if "$MCPU_CPP" --no-config "$base/not-variadic.c" -o "$base/not-variadic.out" 2>"$base/not-variadic.err"; then
  echo '#__VA_ARGS__ unexpectedly accepted in a non-variadic macro' >&2
  exit 1
fi
grep "'#' operator should be followed by a macro argument name" "$base/not-variadic.err" >/dev/null