From b580949ae0981cc2ecd466ad1dacb42f2f4a9f7d Mon Sep 17 00:00:00 2001
From: Dmitry Goncharov <dgoncharov@users.sf.net>
Date: Sat, 29 May 2021 19:03:07 -0400
Subject: [PATCH] [SV 60659] Set $$< properly in second expansion

Set the $$< automatic variable as best we can during secondary
expansion of prerequisites.

* src/commands.c (set_file_variables): Don't break without setting
'less' if secondary expansion is enabled.
* tests/scripts/features/se_explicit: Test secondary expansion results.
* tests/scripts/features/se_implicit: Test secondary expansion results.
---
 src/commands.c                     |  5 +-
 tests/scripts/features/se_explicit | 92 ++++++++++++++++++++++++++++
 tests/scripts/features/se_implicit | 98 ++++++++++++++++++++++++++++++
 3 files changed, 192 insertions(+), 3 deletions(-)

diff --git a/src/commands.c b/src/commands.c
index dd179998..8a483bdd 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -133,10 +133,9 @@ set_file_variables (struct file *file)
   /* $< is the first not order-only dependency.  */
   less = "";
   for (d = file->deps; d != 0; d = d->next)
-    if (!d->ignore_mtime && !d->ignore_automatic_vars)
+    if (!d->ignore_mtime && !d->ignore_automatic_vars && !d->need_2nd_expansion)
       {
-        if (!d->need_2nd_expansion)
-          less = dep_name (d);
+        less = dep_name (d);
         break;
       }
 
diff --git a/tests/scripts/features/se_explicit b/tests/scripts/features/se_explicit
index c28641c1..450aaf7f 100644
--- a/tests/scripts/features/se_explicit
+++ b/tests/scripts/features/se_explicit
@@ -200,4 +200,96 @@ biz: $$(info $$<)
 !,
               '', "baz\n#MAKE#: Nothing to be done for 'biz'.\n");
 
+
+# sv 60659. Second expansion of automatic variables inside a function in the
+# prerequisite list.
+# $$@ expands to the target in the 1st and following rules.
+# $$<,$$^,$$+,$$|,$$?,$$*,$$% expand to the empty string in the prerequisite
+# list of the 1st rule.
+# $$<,$$^,$$+,$$|,$$?,$$*,$$% in the prerequisite list of the 2nd (and
+# following) rule expand to the values from the 1st rule.
+
+
+# subtest 1. Explicit rules. 1st rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+2.x: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=,%=
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 2. Explicit rules. 2nd rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x 1.x
+2.x: 5.z 6.z 5.z | 7.z 7.z 8.z
+1.x: 1.z 2.z 2.z | 3.z 4.z
+2.x 1.x: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ;
+%.z: ;
+!, '',
+"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=,%=
+@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=,%=
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 3. Grouped targets in explicit rules. 1st rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+2.x 1.x&: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=,%=
+@=1.x,<=,^=,+=,|=,?=,*=,%=
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 4. Grouped targets in explicit rules. 2nd rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x 1.x
+2.x: 5.z 6.z 5.z | 7.z 7.z 8.z
+1.x: 1.z 2.z 2.z | 3.z 4.z
+2.x 1.x&: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ;
+%.z: ;
+!, '',
+"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=,%=
+@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=,%=
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# Double colon rules.
+# Because each double colon rule is independent of the other double colon rules
+# for the same target, each automatic variable in the prerequisite list, other
+# than $$@, second expands to the empty string in any rule, 1st, 2nd or later.
+
+# subtest 5. 1st double colon rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+2.x:: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=,%=
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 6. 2nd double colon rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x 1.x
+2.x:: 5.z 6.z 5.z | 7.z 7.z 8.z ;
+1.x:: 1.z 2.z 2.z | 3.z 4.z ;
+2.x 1.x:: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*,%=$$%) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=,%=
+@=1.x,<=,^=,+=,|=,?=,*=,%=
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+
 1;
diff --git a/tests/scripts/features/se_implicit b/tests/scripts/features/se_implicit
index 07ce8023..db6e1683 100644
--- a/tests/scripts/features/se_implicit
+++ b/tests/scripts/features/se_implicit
@@ -325,5 +325,103 @@ unlink('hello.x');
 unlink('hello.tsk');
 
 
+# sv 60659. Second expansion of automatic variables inside a function in the
+# prerequisite list.
+# $$@ expands to the target in the 1st and following rules.
+# $$* expands to the stem in the 1st and following rules.
+# $$<,$$^,$$+,$$|,$$?,$$% expand to the empty string in the prerequisite list
+# of the 1st rule.
+# $$<,$$^,$$+,$$|,$$?,$$% in the prerequisite list of the 2nd (and following)
+# rule expand to the values from the 1st rule.
+# $$% cannot be used in prerequisites, because in pattern rules % is
+# substituted for stem.
+
+
+# subtest 1. Pattern rules. 1st rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+%.x: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=2
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 2. Pattern rules. 2nd rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x 1.x
+2.x: 5.z 6.z 5.z | 7.z 7.z 8.z
+1.x: 1.z 2.z 2.z | 3.z 4.z
+%.x: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+%.z: ;
+!, '',
+"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=2
+@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=1
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 3. Static pattern rules. 1st rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+2.x: %.x: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=2
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 4. Static pattern rules. 2nd rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x 1.x
+2.x: 5.z 6.z 5.z | 7.z 7.z 8.z
+1.x: 1.z 2.z 2.z | 3.z 4.z
+2.x 1.x: %.x: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+%.z: ;
+!, '',
+"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=2
+@=1.x,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=1
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 5. Grouped targets in implicit rules. 1st rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+%.x %.xx&: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+%.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=2
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 6. Grouped targets in implicit rules. 2nd rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x 1.xx
+2.x: 5.z 6.z 5.z | 7.z 7.z 8.z
+1.xx: 1.z 2.z 2.z | 3.z 4.z
+%.x %.xx&: 9.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+%.z: ;
+!, '',
+"@=2.x,<=5.z,^=5.z 6.z,+=5.z 6.z 5.z,|=7.z 8.z,?=,*=2
+@=1.xx,<=1.z,^=1.z 2.z,+=1.z 2.z 2.z,|=3.z 4.z,?=,*=1
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
+# subtest 7. Double colon rule.
+run_make_test(q!
+.SECONDEXPANSION:
+all: 2.x
+%.x:: 5.z 6.z 5.z $$(info @=$$@,<=$$<,^=$$^,+=$$+,|=$$|,?=$$?,*=$$*) ;
+5.z 6.z: ;
+!, '',
+"@=2.x,<=,^=,+=,|=,?=,*=2
+#MAKE#: Nothing to be done for 'all'.\n");
+
+
 # This tells the test driver that the perl test script executed properly.
 1;