This patch adds metadata to some C++ diagnostics,
referencing a specific section/anchor within a draft
of the C++ standard.  For example, this adds
a [depr.volatile.type] tag:

standard-ref-1.C:1:12: warning: ‘volatile’-qualified parameter
is deprecated [depr.volatile.type] [-Wvolatile]
    1 | void test (volatile int);
      |            ^~~~~~~~~~~~

where in a sufficiently capable terminal the [depr.volatile.type] has
URL:
  https://eelis.net/c++draft/depr.volatile.type#3

Arguably cppreference would be a better thing to link
people to from a UX perspective.

Thoughts?

gcc/cp/ChangeLog:
        * decl.cc: Include "diagnostic-metadata.h".
        (class cp_standard_ref): New.
        (duplicate_decls): Add link to dcl.attr.noreturn
        to mismatched [[noreturn]].
        (grokparms): Add link to depr.volatile.type to
        violation of [dcl.fct] "A parameter with volatile-qualified
        type is deprecated.

gcc/testsuite/ChangeLog:
        * g++.dg/diagnostic/standard-ref-1.C: New test.
        * g++.dg/diagnostic/standard-ref-2.C: New test.

Signed-off-by: David Malcolm <dmalc...@redhat.com>
---
 gcc/cp/decl.cc                                | 62 +++++++++++++++++--
 .../g++.dg/diagnostic/standard-ref-1.C        |  1 +
 .../g++.dg/diagnostic/standard-ref-2.C        |  4 ++
 3 files changed, 62 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/standard-ref-1.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/standard-ref-2.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 10c2b2e3ad10..2bef065173eb 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coroutines.h"
 #include "diagnostic-highlight-colors.h"
 #include "pretty-print-markup.h"
+#include "diagnostic-metadata.h"
 
 /* Possible cases of bad specifiers type used by bad_specifiers. */
 enum bad_spec_place {
@@ -268,6 +269,48 @@ struct GTY(()) incomplete_var {
 
 static GTY(()) vec<incomplete_var, va_gc> *incomplete_vars;
 
+
+/* A diagnostic_metadata instance that adds a reference to a particular
+   section of the (draft) C++ standard, at a given anchor.  */
+
+class cp_standard_ref : public diagnostic_metadata
+{
+public:
+  cp_standard_ref (const char *section, const char *anchor)
+  : m_rule (section, anchor)
+  {
+    add_rule (m_rule);
+  }
+
+private:
+  class std_rule : public rule
+  {
+  public:
+    std_rule (const char *section, const char *anchor)
+    : m_section (section),
+      m_anchor (anchor)
+    {}
+
+    char *make_description () const final override
+    {
+      return xstrdup (m_section);
+    }
+
+    char *make_url () const  final override
+    {
+      return concat ("https://eelis.net/c++draft/";,
+                    m_section,
+                    "#",
+                    m_anchor,
+                    nullptr);
+    }
+
+  private:
+    const char *m_section;
+    const char *m_anchor;
+  } m_rule;
+};
+
 /* Returns the kind of template specialization we are currently
    processing, given that it's declaration contained N_CLASS_SCOPES
    explicit scope qualifications.  */
@@ -2358,8 +2401,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
              && get_attribute_namespace (a) == NULL_TREE)
            {
              auto_diagnostic_group d;
-             error_at (newdecl_loc, "function %qD declared %<[[noreturn]]%> "
-                       "but its first declaration was not", newdecl);
+             gcc_rich_location richloc (newdecl_loc);
+             error_meta (&richloc,
+                         cp_standard_ref ("dcl.attr.noreturn", "1"),
+                         "function %qD declared %<[[noreturn]]%> "
+                         "but its first declaration was not",
+                         newdecl);
              inform (olddecl_loc, "previous declaration of %qD", olddecl);
            }
        }
@@ -15795,9 +15842,14 @@ grokparms (tree parmlist, tree *parms)
          /* [dcl.fct] "A parameter with volatile-qualified type is
             deprecated."  */
          if (CP_TYPE_VOLATILE_P (type))
-           warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wvolatile,
-                       "%<volatile%>-qualified parameter is "
-                       "deprecated");
+           {
+             gcc_rich_location richloc (DECL_SOURCE_LOCATION (decl));
+             warning_meta (&richloc,
+                           cp_standard_ref ("depr.volatile.type", "3"),
+                           OPT_Wvolatile,
+                           "%<volatile%>-qualified parameter is "
+                           "deprecated");
+           }
 
          /* Top-level qualifiers on the parameters are
             ignored for function types.  */
diff --git a/gcc/testsuite/g++.dg/diagnostic/standard-ref-1.C 
b/gcc/testsuite/g++.dg/diagnostic/standard-ref-1.C
new file mode 100644
index 000000000000..819c6b90e70f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/standard-ref-1.C
@@ -0,0 +1 @@
+void test (volatile int); // { dg-warning "'volatile'-qualified parameter is 
deprecated \\\[depr.volatile.type\\\] \\\[-Wvolatile\\]" "" { target c++20 } }
diff --git a/gcc/testsuite/g++.dg/diagnostic/standard-ref-2.C 
b/gcc/testsuite/g++.dg/diagnostic/standard-ref-2.C
new file mode 100644
index 000000000000..a5407cefde5e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/standard-ref-2.C
@@ -0,0 +1,4 @@
+// { dg-do compile { target c++11 } }
+
+void my_exit (); // { dg-message "previous declaration" }
+[[noreturn]] void my_exit (); // { dg-error "function 'void my_exit\\\(\\\)' 
declared '\\\[\\\[noreturn\\\]\\\]' but its first declaration was not 
\\\[dcl.attr.noreturn\\\]" }
-- 
2.26.3

Reply via email to