[SV 20513] Un-escaped # are not comments in function invocations

* NEWS: Document the change, as a backward-incompatible change.
* main.c (main): Add 'nocomment' to the .FEATURES variable.
* read.c (remove_comments): Skip variable references during remove.
(find_char_unquote): Fix comments for new STOPMAP support.
* tests/scripts/features/escape: Test new escape syntax.
* tests/scripts/functions/guile: Ditto.
* tests/scripts/functions/shell: Ditto.
diff --git a/NEWS b/NEWS
index d3059ae..0dab2ee 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,20 @@
 
 http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=108&set=custom
 
+* WARNING: Backward-incompatibility!
+  Number signs (#) appearing inside a macro reference or function invocation
+  no longer introduce comments and should not be escaped with backslashes:
+  thus a call such as:
+    foo := $(shell echo '#')
+  is legal.  Previously the number sign needed to be escaped, for example:
+    foo := $(shell echo '\#')
+  Now this latter will resolve to "\#".  If you want to write makefiles
+  portable to both versions, assign the number sign to a variable:
+    C := \#
+    foo := $(shell echo '$C')
+  This was claimed to be fixed in 3.81, but wasn't, for some reason.
+  To detect this change search for 'nocomment' in the .FEATURES variable.
+
 * The previous limit of 63 jobs under -jN on MS-Windows is now
   increased to 4095.  That limit includes the subprocess started by
   the $(shell) function.
diff --git a/main.c b/main.c
index 80c17da..aa3d80d 100644
--- a/main.c
+++ b/main.c
@@ -1321,7 +1321,7 @@
      some compilers (MSVC) don't like conditionals in macros.  */
   {
     const char *features = "target-specific order-only second-expansion"
-                           " else-if shortest-stem undefine oneshell"
+                           " else-if shortest-stem undefine oneshell nocomment"
 #ifndef NO_ARCHIVES
                            " archives"
 #endif
diff --git a/read.c b/read.c
index e8b505d..26ba6f9 100644
--- a/read.c
+++ b/read.c
@@ -1398,14 +1398,15 @@
 
 
 /* Remove comments from LINE.
-   This is done by copying the text at LINE onto itself.  */
+   This will also remove backslashes that escape things.
+   It ignores comment characters that appear inside variable references.  */
 
 static void
 remove_comments (char *line)
 {
   char *comment;
 
-  comment = find_char_unquote (line, MAP_COMMENT);
+  comment = find_char_unquote (line, MAP_COMMENT|MAP_VARIABLE);
 
   if (comment != 0)
     /* Cut off the line at the #.  */
@@ -2224,27 +2225,27 @@
     }
 }
 
-/* Search STRING for an unquoted STOPCHAR or blank (if BLANK is nonzero).
-   Backslashes quote STOPCHAR, blanks if BLANK is nonzero, and backslash.
-   Quoting backslashes are removed from STRING by compacting it into
-   itself.  Returns a pointer to the first unquoted STOPCHAR if there is
-   one, or nil if there are none.  STOPCHARs inside variable references are
-   ignored if IGNOREVARS is true.
+/* Search STRING for an unquoted STOPMAP.
+   Backslashes quote elements from STOPMAP and backslash.
+   Quoting backslashes are removed from STRING by compacting it into itself.
+   Returns a pointer to the first unquoted STOPCHAR if there is one, or nil if
+   there are none.
 
-   STOPCHAR _cannot_ be '$' if IGNOREVARS is true.  */
+   If MAP_VARIABLE is set, then the complete contents of variable references
+   are skipped, even if the contain STOPMAP characters.  */
 
 static char *
-find_char_unquote (char *string, int map)
+find_char_unquote (char *string, int stopmap)
 {
   unsigned int string_len = 0;
   char *p = string;
 
   /* Always stop on NUL.  */
-  map |= MAP_NUL;
+  stopmap |= MAP_NUL;
 
   while (1)
     {
-      while (! STOP_SET (*p, map))
+      while (! STOP_SET (*p, stopmap))
         ++p;
 
       if (*p == '\0')
diff --git a/tests/scripts/features/escape b/tests/scripts/features/escape
index bf069df..de0ef48 100644
--- a/tests/scripts/features/escape
+++ b/tests/scripts/features/escape
@@ -70,5 +70,23 @@
 !,
               '', ": '..\\foo'\n");
 
+# Test escaped comments in variable assignments
+run_make_test(q!
+self = $1
+foo := $(call self,#foo#)#foo
+bar := $(call self,\#bar\#)#bar
+all:;@echo '$(foo) $(bar)'
+!,
+               '',"#foo# \\#bar\\#");
+
+# Test escaped comments in variable assignments in a variable
+run_make_test(q!
+C = \#
+self = $1
+foo := $(call self,$Cfoo$C)#foo
+all:;@echo '$(foo)'
+!,
+               '',"#foo#");
+
 # This tells the test driver that the perl test script executed properly.
 1;
diff --git a/tests/scripts/functions/guile b/tests/scripts/functions/guile
index c63bec9..415827a 100644
--- a/tests/scripts/functions/guile
+++ b/tests/scripts/functions/guile
@@ -36,6 +36,20 @@
 !,
               '', "\n#t\nc\n1234\nfoo\nbar\na b\na b c d 1 2 3");
 
+# Verify guile functions in variables -- SV 43378
+run_make_test(q!
+res := $(guile #f) \
+       $(guile #t) \
+       $(guile #\c) \
+       $(guile 1234) \
+       $(guile 'foo) \
+       $(guile "bar") \
+       $(guile (cons 'a 'b)) \
+       $(guile '(a b (c . d) 1 (2) 3))
+x:;@echo '$(res)'
+!,
+              '', " #t c 1234 foo bar a b a b c d 1 2 3");
+
 # Verify the gmk-expand function
 run_make_test(q!
 VAR = $(guile (gmk-expand "$(shell echo hi)"))
diff --git a/tests/scripts/functions/shell b/tests/scripts/functions/shell
index 809c77f..0a549a7 100644
--- a/tests/scripts/functions/shell
+++ b/tests/scripts/functions/shell
@@ -27,13 +27,11 @@
 
 
 # Test unescaped comment characters in shells.  Savannah bug #20513
-if ($all_tests) {
-    run_make_test(q!
+run_make_test(q!
 FOO := $(shell echo '#')
 foo: ; echo '$(FOO)'
 !,
-              '', "#\n");
-}
+              '', "echo '#'\n#\n");
 
 # Test shells inside exported environment variables.
 # This is the test that fails if we try to put make exported variables into