summaryrefslogtreecommitdiff
path: root/tests/t0058-variadic-macros.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tests/t0058-variadic-macros.sh')
-rwxr-xr-xtests/t0058-variadic-macros.sh135
1 files changed, 135 insertions, 0 deletions
diff --git a/tests/t0058-variadic-macros.sh b/tests/t0058-variadic-macros.sh
new file mode 100755
index 0000000..584e980
--- /dev/null
+++ b/tests/t0058-variadic-macros.sh
@@ -0,0 +1,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