diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 566772cc740fff7ea4efeb1b8b26b068f5e1a963..0a7c7e02b37c1eec096b2d97ca7793c0193b4cf6 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -186,7 +186,8 @@ typedef char *(*diagnostic_make_option_name_cb) (const diagnostic_context *, diagnostic_t, diagnostic_t); typedef char *(*diagnostic_make_option_url_cb) (const diagnostic_context *, - int); + int, + unsigned); class edit_context; namespace json { class value; } @@ -526,7 +527,8 @@ public: { if (!m_option_callbacks.m_make_option_url_cb) return nullptr; - return m_option_callbacks.m_make_option_url_cb (this, option_index); + return m_option_callbacks.m_make_option_url_cb (this, option_index, + get_lang_mask ()); } void diff --git a/gcc/gcc-urlifier.cc b/gcc/gcc-urlifier.cc index 877445c6f4098c3583a83139db0f2b9fddf79ab8..6bd176fc24834b4d3801a77601335b179dc4c198 100644 --- a/gcc/gcc-urlifier.cc +++ b/gcc/gcc-urlifier.cc @@ -24,6 +24,8 @@ along with GCC; see the file COPYING3. If not see #include "pretty-print.h" #include "pretty-print-urlifier.h" #include "gcc-urlifier.h" +#include "opts.h" +#include "options.h" #include "selftest.h" namespace { @@ -34,23 +36,34 @@ namespace { class gcc_urlifier : public urlifier { public: + gcc_urlifier (unsigned int lang_mask) + : m_lang_mask (lang_mask) + {} + char *get_url_for_quoted_text (const char *p, size_t sz) const final override; - const char *get_url_suffix_for_quoted_text (const char *p, size_t sz) const; + label_text get_url_suffix_for_quoted_text (const char *p, size_t sz) const; /* We use ATTRIBUTE_UNUSED as this helper is called only from ASSERTs. */ - const char *get_url_suffix_for_quoted_text (const char *p) const ATTRIBUTE_UNUSED; + label_text get_url_suffix_for_quoted_text (const char *p) const ATTRIBUTE_UNUSED; private: + label_text get_url_suffix_for_option (const char *p, size_t sz) const; + static char * make_doc_url (const char *doc_url_suffix); + + unsigned int m_lang_mask; }; /* class gcc_urlifier : public urlifier. */ +/* Manage a hard-coded mapping from quoted string to URL suffixes + in gcc-urlifier.def */ + #define DOC_URL(QUOTED_TEXT, URL_SUFFIX) \ { (QUOTED_TEXT), (URL_SUFFIX) } -const struct +static const struct { const char *quoted_text; const char *url_suffix; @@ -60,32 +73,53 @@ const struct }; +/* Implementation of urlifier::get_url_for_quoted_text vfunc for GCC + diagnostics. */ + char * gcc_urlifier::get_url_for_quoted_text (const char *p, size_t sz) const { - if (const char *url_suffix = get_url_suffix_for_quoted_text (p, sz)) - return make_doc_url (url_suffix); + label_text url_suffix = get_url_suffix_for_quoted_text (p, sz); + if (url_suffix.get ()) + return make_doc_url (url_suffix.get ()); return nullptr; } -const char * +/* Look for a URL for the quoted string (P, SZ). + Return the url suffix if found, or nullptr otherwise. */ + +label_text gcc_urlifier::get_url_suffix_for_quoted_text (const char *p, size_t sz) const { - /* Binary search. This assumes that the quoted_text fields of doc_urls + if (sz == 0) + return label_text (); + + /* If this is an option, look up the option and see if we have + a URL for it. */ + if (p[0] == '-') + { + label_text suffix = get_url_suffix_for_option (p, sz); + if (suffix.get ()) + return suffix; + } + + /* Otherwise, look within the hard-coded data table in gcc-urlifier.def. + + Binary search. This assumes that the quoted_text fields of doc_urls are in sorted order. */ int min = 0; int max = ARRAY_SIZE (doc_urls) - 1; while (true) { if (min > max) - return nullptr; + return label_text (); int midpoint = (min + max) / 2; gcc_assert ((size_t)midpoint < ARRAY_SIZE (doc_urls)); int cmp = strncmp (p, doc_urls[midpoint].quoted_text, sz); if (cmp == 0) { if (doc_urls[midpoint].quoted_text[sz] == '\0') - return doc_urls[midpoint].url_suffix; + return label_text::borrow (doc_urls[midpoint].url_suffix); else max = midpoint - 1; } @@ -94,15 +128,45 @@ gcc_urlifier::get_url_suffix_for_quoted_text (const char *p, size_t sz) const else min = midpoint + 1; } - return nullptr; + + /* Not found. */ + return label_text (); } -const char * +/* For use in selftests. */ + +label_text gcc_urlifier::get_url_suffix_for_quoted_text (const char *p) const { return get_url_suffix_for_quoted_text (p, strlen (p)); } +/* Look for a URL for the quoted string (P, SZ) that appears to be + an option. + Return the url suffix if found, or nullptr otherwise. */ + +label_text +gcc_urlifier::get_url_suffix_for_option (const char *p, size_t sz) const +{ + /* Look up this option + + find_opt does a binary search, taking a 0-terminated string, + and skipping the leading '-'. + + We have a (pointer,size) pair that doesn't necessarily have a + terminator, so create a 0-terminated clone of the string. */ + gcc_assert (sz > 0); + char *tmp = xstrndup (p + 1, sz - 1); // skip the leading '-' + size_t opt = find_opt (tmp, m_lang_mask); + free (tmp); + + if (opt >= N_OPTS) + /* Option not recognized. */ + return label_text (); + + return get_option_url_suffix (opt, m_lang_mask); +} + char * gcc_urlifier::make_doc_url (const char *doc_url_suffix) { @@ -115,9 +179,9 @@ gcc_urlifier::make_doc_url (const char *doc_url_suffix) } // anonymous namespace urlifier * -make_gcc_urlifier () +make_gcc_urlifier (unsigned int lang_mask) { - return new gcc_urlifier (); + return new gcc_urlifier (lang_mask); } #if CHECKING_P @@ -137,22 +201,26 @@ gcc_urlifier_cc_tests () doc_urls[idx].quoted_text) < 0); - gcc_urlifier u; + gcc_urlifier u (0); - ASSERT_EQ (u.get_url_suffix_for_quoted_text (""), nullptr); - ASSERT_EQ (u.get_url_suffix_for_quoted_text (")"), nullptr); + ASSERT_EQ (u.get_url_suffix_for_quoted_text ("").get (), nullptr); + ASSERT_EQ (u.get_url_suffix_for_quoted_text (")").get (), nullptr); - ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("#pragma message"), + ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("#pragma message").get (), "gcc/Diagnostic-Pragmas.html"); // Incomplete prefix of a quoted_text - ASSERT_EQ (u.get_url_suffix_for_quoted_text ("#pragma mess"), nullptr); + ASSERT_EQ (u.get_url_suffix_for_quoted_text ("#pragma mess").get (), nullptr); /* Check that every element is findable. */ for (size_t idx = 0; idx < ARRAY_SIZE (doc_urls); idx++) ASSERT_STREQ - (u.get_url_suffix_for_quoted_text (doc_urls[idx].quoted_text), + (u.get_url_suffix_for_quoted_text (doc_urls[idx].quoted_text).get (), doc_urls[idx].url_suffix); + + /* Check an option. */ + ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("-fpack-struct").get (), + "gcc/Code-Gen-Options.html#index-fpack-struct"); } } // namespace selftest diff --git a/gcc/gcc-urlifier.def b/gcc/gcc-urlifier.def index 360de930e9ec84cbb716b57ebed90b67823ba003..de6d9a3eb9624ffc972c5bb205ffe3e96fcd7235 100644 --- a/gcc/gcc-urlifier.def +++ b/gcc/gcc-urlifier.def @@ -16,5 +16,3 @@ DOC_URL ("#pragma pack", "gcc/Structure-Layout-Pragmas.html"), DOC_URL ("#pragma redefine_extname", "gcc/Symbol-Renaming-Pragmas.html"), DOC_URL ("#pragma scalar_storage_order", "gcc/Structure-Layout-Pragmas.html"), DOC_URL ("#pragma weak", "gcc/Weak-Pragmas.html"), -DOC_URL ("--version", "gcc/Overall-Options.html#index-version"), -DOC_URL ("-fpack-struct", "gcc/Code-Gen-Options.html#index-fpack-struct"), diff --git a/gcc/gcc-urlifier.h b/gcc/gcc-urlifier.h index 601cea5d0ce8c221f13ee5ddce4f3f5ee368ed1d..660d4f8828e7fde23964f9f04c4c4cee5f1e3d8f 100644 --- a/gcc/gcc-urlifier.h +++ b/gcc/gcc-urlifier.h @@ -21,6 +21,6 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_GCC_URLIFIER_H #define GCC_GCC_URLIFIER_H -extern urlifier *make_gcc_urlifier (); +extern urlifier *make_gcc_urlifier (unsigned int lang_mask); #endif /* GCC_GCC_URLIFIER_H */ diff --git a/gcc/gcc.cc b/gcc/gcc.cc index 76081b9970d22775c3e1a819ef359cc3b011b13e..588a0e970daab8b34f14af7631ab669a0c6567d4 100644 --- a/gcc/gcc.cc +++ b/gcc/gcc.cc @@ -8340,7 +8340,7 @@ driver::global_initializations () diagnostic_initialize (global_dc, 0); diagnostic_color_init (global_dc); diagnostic_urls_init (global_dc); - global_dc->set_urlifier (make_gcc_urlifier ()); + global_dc->set_urlifier (make_gcc_urlifier (0)); #ifdef GCC_DRIVER_HOST_INITIALIZATION /* Perform host dependent initialization when needed. */ diff --git a/gcc/opts-diagnostic.h b/gcc/opts-diagnostic.h index e8bb77e8594648db4ff1f03cb1410bc8141df07b..a18c4c17f6079e2e66e614738442d22a30bd078a 100644 --- a/gcc/opts-diagnostic.h +++ b/gcc/opts-diagnostic.h @@ -24,6 +24,7 @@ extern char *option_name (const diagnostic_context *context, int option_index, diagnostic_t orig_diag_kind, diagnostic_t diag_kind); extern char *get_option_url (const diagnostic_context *context, - int option_index); + int option_index, + unsigned lang_mask); #endif diff --git a/gcc/opts.cc b/gcc/opts.cc index da6d634ebcec1598b5f52562fec11b435ac4813c..3333600e0ea24bdfd0a097de3d74b94105831404 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -3710,14 +3710,6 @@ get_option_html_page (int option_index) { const cl_option *cl_opt = &cl_options[option_index]; - /* Analyzer options are on their own page. */ - if (strstr (cl_opt->opt_text, "analyzer-")) - return "gcc/Static-Analyzer-Options.html"; - - /* Handle -flto= option. */ - if (strstr (cl_opt->opt_text, "flto")) - return "gcc/Optimize-Options.html"; - #ifdef CL_Fortran if ((cl_opt->flags & CL_Fortran) != 0 /* If it is option common to both C/C++ and Fortran, it is documented @@ -3730,32 +3722,49 @@ get_option_html_page (int option_index) return "gfortran/Error-and-Warning-Options.html"; #endif - return "gcc/Warning-Options.html"; + return nullptr; +} + +/* Get the url within the documentation for this option, or NULL. */ + +label_text +get_option_url_suffix (int option_index, unsigned lang_mask) +{ + if (const char *url = get_opt_url_suffix (option_index, lang_mask)) + + return label_text::borrow (url); + + /* Fallback code for some options that aren't handled byt opt_url_suffixes + e.g. links below "gfortran/". */ + if (const char *html_page = get_option_html_page (option_index)) + return label_text::take + (concat (html_page, + /* Expect an anchor of the form "index-Wfoo" e.g. + <a name="index-Wformat"></a>, and thus an id within + the page of "#index-Wformat". */ + "#index", + cl_options[option_index].opt_text, + NULL)); + + return label_text (); } /* Return malloced memory for a URL describing the option OPTION_INDEX which enabled a diagnostic (context CONTEXT). */ char * -get_option_url (const diagnostic_context *, int option_index) +get_option_url (const diagnostic_context *, + int option_index, + unsigned lang_mask) { if (option_index) - return concat (/* DOCUMENTATION_ROOT_URL should be supplied via - #include "config.h" (see --with-documentation-root-url), - and should have a trailing slash. */ - DOCUMENTATION_ROOT_URL, - - /* get_option_html_page will return something like - "gcc/Warning-Options.html". */ - get_option_html_page (option_index), - - /* Expect an anchor of the form "index-Wfoo" e.g. - <a name="index-Wformat"></a>, and thus an id within - the URL of "#index-Wformat". */ - "#index", cl_options[option_index].opt_text, - NULL); - else - return NULL; + { + label_text url_suffix = get_option_url_suffix (option_index, lang_mask); + if (url_suffix.get ()) + return concat (DOCUMENTATION_ROOT_URL, url_suffix.get (), nullptr); + } + + return nullptr; } /* Return a heap allocated producer with command line options. */ @@ -3886,17 +3895,35 @@ gen_producer_string (const char *language_string, cl_decoded_option *options, namespace selftest { -/* Verify that get_option_html_page works as expected. */ +/* Verify that get_option_url_suffix works as expected. */ static void -test_get_option_html_page () +test_get_option_url_suffix () { - ASSERT_STREQ (get_option_html_page (OPT_Wcpp), "gcc/Warning-Options.html"); - ASSERT_STREQ (get_option_html_page (OPT_Wanalyzer_double_free), - "gcc/Static-Analyzer-Options.html"); + ASSERT_STREQ (get_option_url_suffix (OPT_Wcpp, 0).get (), + "gcc/Warning-Options.html#index-Wcpp"); + ASSERT_STREQ (get_option_url_suffix (OPT_Wanalyzer_double_free, 0).get (), + "gcc/Static-Analyzer-Options.html#index-Wanalyzer-double-free"); + + /* Test of a D-specific option. */ +#ifdef CL_D + ASSERT_EQ (get_option_url_suffix (OPT_fbounds_check_, 0).get (), nullptr); + ASSERT_STREQ (get_option_url_suffix (OPT_fbounds_check_, CL_D).get (), + "gdc/Runtime-Options.html#index-fbounds-check"); + + /* Test of a D-specific override to an option URL. */ + /* Generic URL. */ + ASSERT_STREQ (get_option_url_suffix (OPT_fmax_errors_, 0).get (), + "gcc/Warning-Options.html#index-fmax-errors"); + /* D-specific URL. */ + ASSERT_STREQ (get_option_url_suffix (OPT_fmax_errors_, CL_D).get (), + "gdc/Warnings.html#index-fmax-errors"); +#endif + #ifdef CL_Fortran - ASSERT_STREQ (get_option_html_page (OPT_Wline_truncation), - "gfortran/Error-and-Warning-Options.html"); + ASSERT_STREQ + (get_option_url_suffix (OPT_Wline_truncation, CL_Fortran).get (), + "gfortran/Error-and-Warning-Options.html#index-Wline-truncation"); #endif } @@ -3959,7 +3986,7 @@ test_enum_sets () void opts_cc_tests () { - test_get_option_html_page (); + test_get_option_url_suffix (); test_enum_sets (); } diff --git a/gcc/opts.h b/gcc/opts.h index 20419e4339daa8ecf53762c5cf42c9305c5e7c2a..64f94f63d20608fa147449c8e14b27b6dfc6fe0f 100644 --- a/gcc/opts.h +++ b/gcc/opts.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_OPTS_H #define GCC_OPTS_H +#include "rich-location.h" #include "obstack.h" /* Specifies how a switch's VAR_VALUE relates to its FLAG_VAR. */ @@ -569,4 +570,7 @@ struct switchstr bool ordering; }; +extern label_text +get_option_url_suffix (int option_index, unsigned lang_mask); + #endif diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp index d072d661fb548e51b42710f0e114838c1a1765a6..228c21d12071ff0a759eb827040b1760b97b93dd 100644 --- a/gcc/testsuite/lib/gcc-dg.exp +++ b/gcc/testsuite/lib/gcc-dg.exp @@ -46,6 +46,12 @@ if { [ishost "*-*-cygwin*"] } { setenv LANG C.ASCII } +# Set TERM to xterm to ensure that URL escapes are disabled. +# This avoids issues where a diagnostic which could embed a URL +# is emitted before -fdiagnostics-plain-output is handled, where +# otherwise the output could be affected by the environment. +setenv TERM xterm + # Avoid sporadic data-losses with expect match_max -d 10000 diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 8bc1b69f46ce7cc235eb063b2b091a02200a1050..0c2994e85a31e2abf22aa479f6c16dd7347cd4a6 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -1044,12 +1044,13 @@ general_init (const char *argv0, bool init_signals) global_dc->m_show_column = global_options_init.x_flag_show_column; global_dc->m_internal_error = internal_error_function; + const unsigned lang_mask = lang_hooks.option_lang_mask (); global_dc->set_option_hooks (option_enabled, &global_options, option_name, get_option_url, - lang_hooks.option_lang_mask ()); - global_dc->set_urlifier (make_gcc_urlifier ()); + lang_mask); + global_dc->set_urlifier (make_gcc_urlifier (lang_mask)); if (init_signals) {