As a prerequisite for (a corner case in) fixing PR target/40411, we need
the ability to escape special characters in specs.  Case at hand: we
want to match -std=iso9899:199409 which doesn't work right now.  The
option isn't an alias but the canonical form (though in theory one could
introduce -std=c94 and make the above an alias for that), so we can only
match it directly.  The goal is to have this work:

#define STARTFILE_ARCH_SPEC \
  "%{ansi|std=c90|std=iso9899\\:199409:values-Xc.o%s; :values-Xa.o%s} \
   %{std=c90|std=gnu90:values-xpg4.o%s; :values-xpg6.o%s}"

Jeff submitted a patch for this in the PR almost 8 years ago, and I've
just updated it slightly so it applies to mainline, and copied the docs
snippet to invoke.texi with the necessary markup.

Bootstrapped (together with the current proposed patch to fix the PR
above) on i386-pc-solaris2.12 and sparc-sun-solaris2.12.

I'm unsure if the patch is large enough to need a copyright assignment
(in which case it's almost certainly too late for GCC 7), and even if
not if it's appropriate at this point in the release cycle.

How should we deal with this?

Thanks.
        Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University


2017-01-10  Jeff Downs  <heydo...@somuchpressure.net>
            Rainer Orth  <r...@cebitec.uni-bielefeld.de>

        gcc:
        * gcc.c (handle_braces): Support escaping in switch matching
        text.
        * doc/invoke.texi (Spec Files): Document it.

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -26391,6 +26391,13 @@ be as many clauses as you need.  This ma
 
 @end table
 
+The switch matching text @code{S} in a %@{@code{S}@},
+%@{@code{S}:@code{X}@} or similar construct can use a backslash to
+ignore the special meaning of the character following it, thus allowing
+literal matching of a character that is otherwise specially treated.
+For example, %@{@code{std=iso9899\:1999}:@code{X}@} would substitute
+@code{X} if the @option{-std=iso9899:1999} option were given.
+
 The conditional text @code{X} in a %@{@code{S}:@code{X}@} or similar
 construct may contain other nested @samp{%} constructs or spaces, or
 even newlines.  They are processed as usual, as described above.
diff --git a/gcc/gcc.c b/gcc/gcc.c
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -583,6 +583,12 @@ or with constant text in a single argume
 
  %(Spec) processes a specification defined in a specs file as *Spec:
 
+The switch matching text S in a %{S}, %{S:X}, or similar construct can use a 
+backslash to ignore the special meaning of the character following it, thus
+allowing literal matching of a character that is otherwise specially treated.
+For example, %{std=iso9899\:1999:X} would substitute X if the
+-std=iso9899:1999 option were given.
+
 The conditional text X in a %{S:X} or similar construct may contain
 other nested % constructs or spaces, or even newlines.  They are
 processed as usual, as described above.  Trailing white space in X is
@@ -6228,6 +6234,8 @@ handle_braces (const char *p)
 {
   const char *atom, *end_atom;
   const char *d_atom = NULL, *d_end_atom = NULL;
+  char *esc_buf = NULL, *d_esc_buf = NULL;
+  int esc;
   const char *orig = p;
 
   bool a_is_suffix;
@@ -6278,11 +6286,41 @@ handle_braces (const char *p)
 	    p++, a_is_spectype = true;
 
 	  atom = p;
+	  esc = 0;
 	  while (ISIDNUM (*p) || *p == '-' || *p == '+' || *p == '='
-		 || *p == ',' || *p == '.' || *p == '@')
-	    p++;
+		 || *p == ',' || *p == '.' || *p == '@' || *p == '\\')
+	    {
+	      if (*p == '\\')
+		{
+		  p++;
+		  if (!*p)
+		    fatal_error (input_location,
+				 "braced spec %qs ends in escape", orig);
+		  esc++;
+		}
+	      p++;
+	    }
 	  end_atom = p;
 
+	  if (esc)
+	    {
+	      const char *ap;
+	      char *ep;
+	      if (esc_buf && esc_buf != d_esc_buf)
+		free(esc_buf);
+	      esc_buf = NULL;
+	      ep = esc_buf = (char *)xmalloc (end_atom - atom - esc + 1);
+	      for (ap = atom; ap != end_atom; ap++, ep++)
+		{
+		  if (*ap == '\\')
+		    ap++;
+		  *ep = *ap;
+		}
+	      *ep = '\0';
+	      atom = esc_buf;
+	      end_atom = ep;
+	    }
+
 	  if (*p == '*')
 	    p++, a_is_starred = 1;
 	}
@@ -6349,6 +6387,7 @@ handle_braces (const char *p)
 		      disj_matched = true;
 		      d_atom = atom;
 		      d_end_atom = end_atom;
+		      d_esc_buf = esc_buf;
 		    }
 		}
 	    }
@@ -6360,7 +6399,7 @@ handle_braces (const char *p)
 	      p = process_brace_body (p + 1, d_atom, d_end_atom, disj_starred,
 				      disj_matched && !n_way_matched);
 	      if (p == 0)
-		return 0;
+		goto done;
 
 	      /* If we have an N-way choice, reset state for the next
 		 disjunction.  */
@@ -6381,6 +6420,12 @@ handle_braces (const char *p)
     }
   while (*p++ != '}');
 
+ done:
+  if (d_esc_buf && d_esc_buf != esc_buf)
+    free(d_esc_buf);
+  if (esc_buf)
+    free(esc_buf);
+
   return p;
 
  invalid:

Reply via email to