From 691eeb65a01dab3084b6ce381737adf097bd2e65 Mon Sep 17 00:00:00 2001
From: Jakub Jelinek <jakub@redhat.com>
Date: Wed, 29 Apr 2020 22:41:47 +0200
Subject: [PATCH] diagnostics: Add %{...%} pretty-format support for URLs and
 use it in -Wpsabi diagnostics

The following patch attempts to use the diagnostics URL support if available
to provide more information about the C++17 empty base and C++20
[[no_unique_address]] empty class ABI changes in -Wpsabi diagnostics.

in GCC 10.1 at the end of the diagnostics is then in some terminals
underlined with a dotted line and points to a (to be written) anchor in
gcc-10/changes.html which we need to write anyway.

2020-04-29  Jakub Jelinek  <jakub@redhat.com>

	* configure.ac (-with-changes-root-url): New configure option,
	defaulting to https://gcc.gnu.org/.
	* Makefile.in (CFLAGS-opts.o): Define CHANGES_ROOT_URL for
	opts.c.
	* pretty-print.c (get_end_url_string): New function.
	(pp_format): Handle %{ and %} for URLs.
	(pp_begin_url): Use pp_string instead of pp_printf.
	(pp_end_url): Use get_end_url_string.
	* opts.h (get_changes_url): Declare.
	* opts.c (get_changes_url): New function.
	* config/rs6000/rs6000-call.c: Include opts.h.
	(rs6000_discover_homogeneous_aggregate): Use %{in GCC 10.1%} instead
	of just in GCC 10.1 in diagnostics and add URL.
	* config/arm/arm.c (aapcs_vfp_is_call_or_return_candidate): Likewise.
	* config/aarch64/aarch64.c (aarch64_vfp_is_call_or_return_candidate):
	Likewise.
	* config/s390/s390.c (s390_function_arg_vector,
	s390_function_arg_float): Likewise.
	* configure: Regenerated.

	* c-format.c (PP_FORMAT_CHAR_TABLE): Add %{ and %}.
---
 gcc/ChangeLog                   | 20 ++++++++
 gcc/Makefile.in                 |  1 +
 gcc/c-family/ChangeLog          |  4 ++
 gcc/c-family/c-format.c         |  2 +
 gcc/config/aarch64/aarch64.c    |  8 +++-
 gcc/config/arm/arm.c            |  8 +++-
 gcc/config/rs6000/rs6000-call.c |  8 +++-
 gcc/config/s390/s390.c          | 20 ++++----
 gcc/configure                   | 25 +++++++++-
 gcc/configure.ac                | 14 ++++++
 gcc/opts.c                      | 10 ++++
 gcc/opts.h                      |  1 +
 gcc/pretty-print.c              | 83 ++++++++++++++++++++++-----------
 13 files changed, 161 insertions(+), 43 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 60f9cd4ffdcf..fc15925aa56f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,25 @@
 2020-04-29  Jakub Jelinek  <jakub@redhat.com>
 
+	* configure.ac (-with-changes-root-url): New configure option,
+	defaulting to https://gcc.gnu.org/.
+	* Makefile.in (CFLAGS-opts.o): Define CHANGES_ROOT_URL for
+	opts.c.
+	* pretty-print.c (get_end_url_string): New function.
+	(pp_format): Handle %{ and %} for URLs.
+	(pp_begin_url): Use pp_string instead of pp_printf.
+	(pp_end_url): Use get_end_url_string.
+	* opts.h (get_changes_url): Declare.
+	* opts.c (get_changes_url): New function.
+	* config/rs6000/rs6000-call.c: Include opts.h.
+	(rs6000_discover_homogeneous_aggregate): Use %{in GCC 10.1%} instead
+	of just in GCC 10.1 in diagnostics and add URL.
+	* config/arm/arm.c (aapcs_vfp_is_call_or_return_candidate): Likewise.
+	* config/aarch64/aarch64.c (aarch64_vfp_is_call_or_return_candidate):
+	Likewise.
+	* config/s390/s390.c (s390_function_arg_vector,
+	s390_function_arg_float): Likewise.
+	* configure: Regenerated.
+
 	PR target/94704
 	* config/s390/s390.c (s390_function_arg_vector,
 	s390_function_arg_float): Use DECL_FIELD_ABI_IGNORED instead of
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fa9923bb2703..85f30bf03912 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2187,6 +2187,7 @@ lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS)
 	mv -f T$@ $@
 
 CFLAGS-opts.o += -DDOCUMENTATION_ROOT_URL=\"@DOCUMENTATION_ROOT_URL@\"
+CFLAGS-opts.o += -DCHANGES_ROOT_URL=\"@CHANGES_ROOT_URL@\"
 
 # Files used by all variants of C or by the stand-alone pre-processor.
 
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 973dc701c2a4..c429b49e68c7 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,7 @@
+2020-04-29  Jakub Jelinek  <jakub@redhat.com>
+
+	* c-format.c (PP_FORMAT_CHAR_TABLE): Add %{ and %}.
+
 2020-04-27  Jakub Jelinek  <jakub@redhat.com>
 
 	PR c/94755
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 51fd31e4d972..33a5b6d3965b 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -757,6 +757,8 @@ static const format_char_info asm_fprintf_char_table[] =
   { "<",   0, STD_C89, NOARGUMENTS, "",      "<",   NULL }, \
   { ">",   0, STD_C89, NOARGUMENTS, "",      ">",   NULL }, \
   { "'" ,  0, STD_C89, NOARGUMENTS, "",      "",    NULL }, \
+  { "{",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",   "cR", NULL }, \
+  { "}",   0, STD_C89, NOARGUMENTS, "",      "",    NULL }, \
   { "R",   0, STD_C89, NOARGUMENTS, "",     "\\",   NULL }, \
   { "m",   0, STD_C89, NOARGUMENTS, "q",     "",   NULL }, \
   { "Z",   1, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",    "", &gcc_diag_char_table[0] }
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index e996fd120420..c1a050fbf2a0 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -16883,6 +16883,7 @@ aarch64_vfp_is_call_or_return_candidate (machine_mode mode,
 	      && ((alt = aapcs_vfp_sub_candidate (type, &new_mode, NULL))
 		  != ag_count))
 	    {
+	      char *url = get_changes_url ("gcc-10/changes.html#empty_base");
 	      gcc_assert (alt == -1);
 	      last_reported_type_uid = uid;
 	      /* Use TYPE_MAIN_VARIANT to strip any redundant const
@@ -16890,11 +16891,14 @@ aarch64_vfp_is_call_or_return_candidate (machine_mode mode,
 	      if (warn_psabi_flags & WARN_PSABI_NO_UNIQUE_ADDRESS)
 		inform (input_location, "parameter passing for argument of "
 			"type %qT with %<[[no_unique_address]]%> members "
-			"changed in GCC 10.1", TYPE_MAIN_VARIANT (type));
+			"changed %{in GCC 10.1%}",
+			TYPE_MAIN_VARIANT (type), url);
 	      else if (warn_psabi_flags & WARN_PSABI_EMPTY_CXX17_BASE)
 		inform (input_location, "parameter passing for argument of "
 			"type %qT when C++17 is enabled changed to match "
-			"C++14 in GCC 10.1", TYPE_MAIN_VARIANT (type));
+			"C++14 %{in GCC 10.1%}",
+			TYPE_MAIN_VARIANT (type), url);
+	      free (url);
 	    }
 
 	  if (is_ha != NULL) *is_ha = true;
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index dcaae7bf7aae..9087e6c2ab4d 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -6416,6 +6416,7 @@ aapcs_vfp_is_call_or_return_candidate (enum arm_pcs pcs_variant,
 	      && ((alt = aapcs_vfp_sub_candidate (type, &new_mode, NULL))
 		  != ag_count))
 	    {
+	      char *url = get_changes_url ("gcc-10/changes.html#empty_base");
 	      gcc_assert (alt == -1);
 	      last_reported_type_uid = uid;
 	      /* Use TYPE_MAIN_VARIANT to strip any redundant const
@@ -6423,11 +6424,14 @@ aapcs_vfp_is_call_or_return_candidate (enum arm_pcs pcs_variant,
 	      if (warn_psabi_flags & WARN_PSABI_NO_UNIQUE_ADDRESS)
 		inform (input_location, "parameter passing for argument of "
 			"type %qT with %<[[no_unique_address]]%> members "
-			"changed in GCC 10.1", TYPE_MAIN_VARIANT (type));
+			"changed %{in GCC 10.1%}",
+			TYPE_MAIN_VARIANT (type), url);
 	      else if (warn_psabi_flags & WARN_PSABI_EMPTY_CXX17_BASE)
 		inform (input_location, "parameter passing for argument of "
 			"type %qT when C++17 is enabled changed to match "
-			"C++14 in GCC 10.1", TYPE_MAIN_VARIANT (type));
+			"C++14 %{in GCC 10.1%}",
+			TYPE_MAIN_VARIANT (type), url);
+	      free (url);
 	    }
 	  *count = ag_count;
 	}
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 800ac2b5b5e1..4e6dd34f446e 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -68,6 +68,7 @@
 #include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "targhooks.h"
+#include "opts.h"
 
 #include "rs6000-internal.h"
 
@@ -5747,17 +5748,20 @@ rs6000_discover_homogeneous_aggregate (machine_mode mode, const_tree type,
 		  unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (type));
 		  if (uid != last_reported_type_uid)
 		    {
+		      char *url
+			= get_changes_url ("gcc-10/changes.html#empty_base");
 		      if (empty_base_seen & 1)
 			inform (input_location,
 				"parameter passing for argument of type %qT "
 				"when C++17 is enabled changed to match C++14 "
-				"in GCC 10.1", type);
+				"%{in GCC 10.1%}", type, url);
 		      else
 			inform (input_location,
 				"parameter passing for argument of type %qT "
 				"with %<[[no_unique_address]]%> members "
-				"changed in GCC 10.1", type);
+				"changed %{in GCC 10.1%}", type, url);
 		      last_reported_type_uid = uid;
+		      free (url);
 		    }
 		}
 	      return true;
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 74b490ad2152..40281e87254e 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -11960,17 +11960,19 @@ s390_function_arg_vector (machine_mode mode, const_tree type)
       unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (orig_type));
       if (uid != last_reported_type_uid)
 	{
+	  char *url = get_changes_url ("gcc-10/changes.html#empty_base");
 	  last_reported_type_uid = uid;
 	  if (empty_base_seen & 1)
 	    inform (input_location,
 		    "parameter passing for argument of type %qT when C++17 "
-		    "is enabled changed to match C++14 in GCC 10.1",
-		    orig_type);
+		    "is enabled changed to match C++14 %{in GCC 10.1%}",
+		    orig_type, url);
 	  else
 	    inform (input_location,
 		    "parameter passing for argument of type %qT with "
-		    "%<[[no_unique_address]]%> members changed in GCC 10.1",
-		    orig_type);
+		    "%<[[no_unique_address]]%> members changed "
+		    "%{in GCC 10.1%}", orig_type, url);
+	  free (url);
 	}
     }
   return true;
@@ -12036,17 +12038,19 @@ s390_function_arg_float (machine_mode mode, const_tree type)
       unsigned uid = TYPE_UID (TYPE_MAIN_VARIANT (orig_type));
       if (uid != last_reported_type_uid)
 	{
+	  char *url = get_changes_url ("gcc-10/changes.html#empty_base");
 	  last_reported_type_uid = uid;
 	  if (empty_base_seen & 1)
 	    inform (input_location,
 		    "parameter passing for argument of type %qT when C++17 "
-		    "is enabled changed to match C++14 in GCC 10.1",
-		    orig_type);
+		    "is enabled changed to match C++14 %{in GCC 10.1%}",
+		    orig_type, url);
 	  else
 	    inform (input_location,
 		    "parameter passing for argument of type %qT with "
-		    "%<[[no_unique_address]]%> members changed in GCC 10.1",
-		    orig_type);
+		    "%<[[no_unique_address]]%> members changed "
+		    "%{in GCC 10.1%}", orig_type, url);
+	  free (url);
 	}
     }
 
diff --git a/gcc/configure b/gcc/configure
index c7bf5d1fdc6b..c8fb7a8a7ac4 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -819,6 +819,7 @@ accel_dir_suffix
 real_target_noncanonical
 enable_as_accelerator
 gnat_install_lib
+CHANGES_ROOT_URL
 DOCUMENTATION_ROOT_URL
 REPORT_BUGS_TEXI
 REPORT_BUGS_TO
@@ -967,6 +968,7 @@ with_specs
 with_pkgversion
 with_bugurl
 with_documentation_root_url
+with_changes_root_url
 enable_languages
 with_multilib_list
 with_zstd
@@ -1803,6 +1805,8 @@ Optional Packages:
   --with-bugurl=URL       Direct users to URL to report a bug
   --with-documentation-root-url=URL
                           Root for documentation URLs
+  --with-changes-root-url=URL
+                          Root for GCC changes URLs
   --with-multilib-list    select multilibs (AArch64, SH and x86-64 only)
   --with-zstd=PATH        specify prefix directory for installed zstd library.
                           Equivalent to --with-zstd-include=PATH/include plus
@@ -7857,6 +7861,23 @@ fi
 
 
 
+# Allow overriding the default URL for GCC changes
+
+# Check whether --with-changes-root-url was given.
+if test "${with_changes_root_url+set}" = set; then :
+  withval=$with_changes_root_url; case "$withval" in
+      yes) as_fn_error $? "changes root URL not specified" "$LINENO" 5 ;;
+      no)  as_fn_error $? "changes root URL not specified" "$LINENO" 5 ;;
+      *)   CHANGES_ROOT_URL="$withval"
+	   ;;
+     esac
+else
+  CHANGES_ROOT_URL="https://gcc.gnu.org/"
+
+fi
+
+
+
 # Sanity check enable_languages in case someone does not run the toplevel
 # configure # script.
 # Check whether --enable-languages was given.
@@ -18988,7 +19009,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18991 "configure"
+#line 19012 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -19094,7 +19115,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19097 "configure"
+#line 19118 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 72f79f7ed322..330e3285dce4 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -986,6 +986,20 @@ AC_ARG_WITH(documentation-root-url,
 )
 AC_SUBST(DOCUMENTATION_ROOT_URL)
 
+# Allow overriding the default URL for GCC changes
+AC_ARG_WITH(changes-root-url,
+    AS_HELP_STRING([--with-changes-root-url=URL],
+                   [Root for GCC changes URLs]),
+    [case "$withval" in
+      yes) AC_MSG_ERROR([changes root URL not specified]) ;;
+      no)  AC_MSG_ERROR([changes root URL not specified]) ;;
+      *)   CHANGES_ROOT_URL="$withval"
+	   ;;
+     esac],
+     CHANGES_ROOT_URL="https://gcc.gnu.org/"
+)
+AC_SUBST(CHANGES_ROOT_URL)
+
 # Sanity check enable_languages in case someone does not run the toplevel
 # configure # script.
 AC_ARG_ENABLE(languages,
diff --git a/gcc/opts.c b/gcc/opts.c
index c212a1a57dcf..12c0098f6b8e 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -3190,6 +3190,16 @@ get_option_url (diagnostic_context *, int option_index)
     return NULL;
 }
 
+/* Given "gcc-10/changes.html#foobar", return that URL under
+   CHANGES_ROOT_URL (see --with-changes-root-url).
+   The caller is responsible for freeing the returned string.  */
+
+char *
+get_changes_url (const char *str)
+{
+  return concat (CHANGES_ROOT_URL, str, NULL);
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/opts.h b/gcc/opts.h
index 8f594b46e330..b9c535049d24 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -464,6 +464,7 @@ extern void parse_options_from_collect_gcc_options (const char *, obstack *,
 						    int *);
 
 extern void prepend_xassembler_to_collect_as_options (const char *, obstack *);
+extern char *get_changes_url (const char *);
 
 /* Set OPTION in OPTS to VALUE if the option is not set in OPTS_SET.  */
 
diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c
index dde138b05334..d0dd9cbd4165 100644
--- a/gcc/pretty-print.c
+++ b/gcc/pretty-print.c
@@ -1020,6 +1020,8 @@ pp_indent (pretty_printer *pp)
     pp_space (pp);
 }
 
+static const char *get_end_url_string (pretty_printer *);
+
 /* The following format specifiers are recognized as being client independent:
    %d, %i: (signed) integer in base ten.
    %u: unsigned integer in base ten.
@@ -1038,6 +1040,8 @@ pp_indent (pretty_printer *pp)
    %%: '%'.
    %<: opening quote.
    %>: closing quote.
+   %{: URL start.  Consumes a const char * argument for the URL.
+   %}: URL end.    Does not consume any arguments.
    %': apostrophe (should only be used in untranslated messages;
        translations should use appropriate punctuation directly).
    %@: diagnostic_event_id_ptr, for which event_id->known_p () must be true.
@@ -1051,7 +1055,7 @@ pp_indent (pretty_printer *pp)
    Arguments can be used sequentially, or through %N$ resp. *N$
    notation Nth argument after the format string.  If %N$ / *N$
    notation is used, it must be used for all arguments, except %m, %%,
-   %<, %> and %', which may not have a number, as they do not consume
+   %<, %>, %} and %', which may not have a number, as they do not consume
    an argument.  When %M$.*N$s is used, M must be N + 1.  (This may
    also be written %M$.*s, provided N is not otherwise used.)  The
    format string must have conversion specifiers with argument numbers
@@ -1084,7 +1088,7 @@ pp_format (pretty_printer *pp, text_info *text)
   /* Formatting phase 1: split up TEXT->format_spec into chunks in
      pp_buffer (PP)->args[].  Even-numbered chunks are to be output
      verbatim, odd-numbered chunks are format specifiers.
-     %m, %%, %<, %>, and %' are replaced with the appropriate text at
+     %m, %%, %<, %>, %} and %' are replaced with the appropriate text at
      this point.  */
 
   memset (formatters, 0, sizeof formatters);
@@ -1133,6 +1137,15 @@ pp_format (pretty_printer *pp, text_info *text)
 	  p++;
 	  continue;
 
+	case '}':
+	  {
+	    const char *endurlstr = get_end_url_string (pp);
+	    obstack_grow (&buffer->chunk_obstack, endurlstr,
+			  strlen (endurlstr));
+	  }
+	  p++;
+	  continue;
+
 	case 'R':
 	  {
 	    const char *colorstr = colorize_stop (pp_show_color (pp));
@@ -1445,6 +1458,10 @@ pp_format (pretty_printer *pp, text_info *text)
 	  }
 	  break;
 
+	case '{':
+	  pp_begin_url (pp, va_arg (*text->args_ptr, const char *));
+	  break;
+
 	default:
 	  {
 	    bool ok;
@@ -2172,18 +2189,41 @@ void
 pp_begin_url (pretty_printer *pp, const char *url)
 {
   switch (pp->url_format)
-  {
-  case URL_FORMAT_NONE:
-    break;
-  case URL_FORMAT_ST:
-    pp_printf (pp, "\33]8;;%s\33\\", url);
-    break;
-  case URL_FORMAT_BEL:
-    pp_printf (pp, "\33]8;;%s\a", url);
-    break;
-  default:
-    gcc_unreachable ();
-  }
+    {
+    case URL_FORMAT_NONE:
+      break;
+    case URL_FORMAT_ST:
+      pp_string (pp, "\33]8;;");
+      pp_string (pp, url);
+      pp_string (pp, "\33\\");
+      break;
+    case URL_FORMAT_BEL:
+      pp_string (pp, "\33]8;;");
+      pp_string (pp, url);
+      pp_string (pp, "\a");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Helper function for pp_end_url and pp_format, return the "close URL" escape
+   sequence string.  */
+
+static const char *
+get_end_url_string (pretty_printer *pp)
+{
+  switch (pp->url_format)
+    {
+    case URL_FORMAT_NONE:
+      return "";
+    case URL_FORMAT_ST:
+      return "\33]8;;\33\\";
+    case URL_FORMAT_BEL:
+      return "\33]8;;\a";
+    default:
+      gcc_unreachable ();
+    }
 }
 
 /* If URL-printing is enabled, write a "close URL" escape sequence to PP.  */
@@ -2191,19 +2231,8 @@ pp_begin_url (pretty_printer *pp, const char *url)
 void
 pp_end_url (pretty_printer *pp)
 {
-  switch (pp->url_format)
-  {
-  case URL_FORMAT_NONE:
-    break;
-  case URL_FORMAT_ST:
-    pp_string (pp, "\33]8;;\33\\");
-    break;
-  case URL_FORMAT_BEL:
-    pp_string (pp, "\33]8;;\a");
-    break;
-  default:
-    gcc_unreachable ();
-  }
+  if (pp->url_format != URL_FORMAT_NONE)
+    pp_string (pp, get_end_url_string (pp));
 }
 
 #if CHECKING_P
-- 
GitLab