RFC: bash completion

Martin Liška mliska@suse.cz
Wed Jun 20 11:55:00 GMT 2018


PING^1 (for the whole series).

On 05/14/2018 02:41 PM, Martin Liška wrote:
> On 04/26/2018 01:13 AM, David Malcolm wrote:
>> [moving from gcc to gcc-patches mailing list]
>>
>> On Wed, 2018-04-25 at 15:12 +0200, Martin Liška wrote:
>>> On 04/24/2018 06:27 PM, David Malcolm wrote:
>>>> On Tue, 2018-04-24 at 16:45 +0200, Martin Liška wrote:
>>>>> Hi.
>>>>>
>>>>> Some time ago, I investigated quite new feature of clang which
>>>>> is support of --autocomplete argument. That can be run from bash
>>>>> completion
>>>>> script and one gets more precise completion hints:
>>>>>
>>>>> http://blog.llvm.org/2017/09/clang-bash-better-auto-completion-is
>>>>> .htm
>>>>> l
>>>>> https://www.youtube.com/watch?v=zLPwPdZBpSY
>>>>>
>>>>> I like the idea and I would describe how is that better to
>>>>> current
>>>>> GCC completion
>>>>> script sitting here:
>>>>> https://github.com/scop/bash-completion/blob/master/completions/g
>>>>> cc
>>>>>
>>>>> 1) gcc -fsanitize=^ - no support for option enum values
>>>>> 2) gcc -fno-sa^ - no support for negative options
>>>>> 3) gcc --param=^ - no support for param names
>>>>>
>>>>> These are main limitations I see. I'm attaching working
>>>>> prototype,
>>>>> which you
>>>>> can test by installed GCC, setting it on $PATH and doing:
>>>>> $ source gcc.sh
>>>>>
>>>>> Then bash completion is provided via the newly added option. Some
>>>>> examples:
>>>>>
>>>>> 1)
>>>>> $ gcc -fsanitize=
>>>>> address                    bounds                     enum       
>>>>>     
>>>>>             integer-divide-by-zero     nonnull-
>>>>> attribute          pointer-
>>>>> compare            return                     shift-
>>>>> base                 thread                     vla-bound
>>>>> alignment                  bounds-strict              float-cast-
>>>>> overflow        kernel-
>>>>> address             null                       pointer-
>>>>> overflow           returns-nonnull-attribute  shift-
>>>>> exponent             undefined                  vptr
>>>>> bool                       builtin                    float-
>>>>> divide-
>>>>> by-zero       leak                       object-
>>>>> size                pointer-
>>>>> subtract           shift                      signed-integer-
>>>>> overflow    unreachable                
>>>>>
>>>>> 2)
>>>>> $ gcc -fno-ipa-
>>>>> -fno-ipa-bit-cp         -fno-ipa-cp-alignment   -fno-ipa-
>>>>> icf            -fno-ipa-icf-variables  -fno-ipa-profile        -
>>>>> fno-
>>>>> ipa-pure-const     -fno-ipa-reference      -fno-ipa-struct-
>>>>> reorg   
>>>>> -fno-ipa-cp             -fno-ipa-cp-clone       -fno-ipa-icf-
>>>>> functions  -fno-ipa-matrix-reorg   -fno-ipa-pta            -fno-
>>>>> ipa-
>>>>> ra             -fno-ipa-sra            -fno-ipa-vrp            
>>>>>
>>>>> 3)
>>>>> $ gcc --param=lto-
>>>>> lto-max-partition  lto-min-partition  lto-partitions    
>>>>>
>>>>> 4)
>>>>> gcc --param lto-
>>>>> lto-max-partition  lto-min-partition  lto-partitions     
>>>>>
>>>>> The patch is quite lean and if people like, I will prepare a
>>>>> proper
>>>>> patch submission. I know about some limitations that can be then
>>>>> handled incrementally.
>>>>>
>>>>> Thoughts?
>>>>> Martin
>>>>
>>>> Overall, looks good (albeit with various nits).  I like how you're
>>>> reusing the m_option_suggestions machinery from the misspelled
>>>> options
>>>> code.  There are some awkward issues e.g. arch-specific
>>>> completions,
>>>> lang-specific completions, custom option-handling etc, but given
>>>> that
>>>> as-is this patch seems to be an improvement over the status quo,
>>>> I'd
>>>> prefer to tackle those later.
>>>
>>> I'm sending second version of the patch. I did isolation of
>>> m_option_suggestions machinery
>>> to a separate file. Mainly due to selftests that are linked with cc1.
>>>
>>>>
>>>> The patch doesn't have tests.  There would need to be some way to
>>>> achieve test coverage for the completion code (especially as we
>>>> start
>>>> to tackle the more interesting cases).  I wonder what the best way
>>>> to
>>>> do that is; perhaps a combination of selftest and DejaGnu?  (e.g.
>>>> what
>>>> about arch-specific completions? what about the interaction with
>>>> bash?
>>>> etc)
>>>
>>> For now I come up with quite some selftests. Integration with
>>> bash&DejaGNU
>>> would be challenging.
>>>
>>>>
>>>> A few nits:
>>>> * Do we want to hardcode that logging path in gcc.sh?
>>>
>>> Sure, that needs to be purged. Crucial question here is where the
>>> gcc.sh script
>>> should live. Note that clang has it in: ./tools/clang/utils/bash-
>>> autocomplete.sh
>>> and:
>>>
>>> head -n1 ./tools/clang/utils/bash-autocomplete.sh
>>> # Please add "source /path/to/bash-autocomplete.sh" to your .bashrc
>>> to use this.
>>>
>>> Which is not ideal. I would prefer to integrate the script into:
>>> https://github.com/scop/bash-completion/blob/master/completions/gcc
>>>
>>> Thoughts?
> 
> Hi David.
> 
> Thanks a lot for so detailed review feedback. If not said otherwise I adapted
> all your suggestions.
> 
>>
>> Maybe our goal should be to update that upstream bash-completion script
>> so that it uses "--completion" if it exists (for newer GCCs), falling
>> back to their existing implementation if it doesn't?
> 
> Yes, I will work on that as soon as GCC's part is ready.
> 
>>
>>>>
>>>> * Looks like m_option_suggestions isn't needed for handling the "-
>>>> param" case, so maybe put the param-handling case before the
>>>> "Lazily
>>>> populate m_option_suggestions" code.
>>>>
>>>> * You use "l" ("ell") as a variable name in two places, which I
>>>> don't
>>>> like, as IMHO it's too close to "1" (one) in some fonts.
>>>
>>> Fixed both notes.
>>> Thanks for fast review.
>>
>> Here's a review of/suggested improvements for the updated patch
>> (technically I'm not a reviewer for this code, although I am the author
>> for the existing options-spellchecking code).
>>
>> Missing ChangeLog, though I get that it was a proof-of-concept.
> 
> Will do that once we'll make a conclusion about the patches.
> 
>>
>> Is it possible to split the moves of the existing code out from the
>> rest of the patch as a preliminary patch?
>>
>>> diff --git a/gcc.sh b/gcc.sh
>>> new file mode 100644
>>> index 00000000000..06b16b3152b
>>> --- /dev/null
>>> +++ b/gcc.sh
>>
>> (I won't attempt to review the bash script for now; I'm not a bash expert)
>>
>>> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
>>> index 20bee0494b1..26fa3dd17df 100644
>>> --- a/gcc/Makefile.in
>>> +++ b/gcc/Makefile.in
>>> @@ -1617,7 +1617,7 @@ OBJS-libcommon = diagnostic.o diagnostic-color.o diagnostic-show-locus.o \
>>>  # compiler and containing target-dependent code.
>>>  OBJS-libcommon-target = $(common_out_object_file) prefix.o params.o \
>>>  	opts.o opts-common.o options.o vec.o hooks.o common/common-targhooks.o \
>>> -	hash-table.o file-find.o spellcheck.o selftest.o
>>> +	hash-table.o file-find.o spellcheck.o selftest.o opt-proposer.o
>>
>> I don't love the "opt-proposer" name; maybe "opt-suggestions.o"?  (not sure)
> 
> Done.
> 
>>
>>>  # This lists all host objects for the front ends.
>>>  ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
>>> diff --git a/gcc/c-family/cppspec.c b/gcc/c-family/cppspec.c
>>> index 1e0a8bcd294..794b3ced529 100644
>>> --- a/gcc/c-family/cppspec.c
>>> +++ b/gcc/c-family/cppspec.c
>>> @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
>>>  #include "system.h"
>>>  #include "coretypes.h"
>>>  #include "tm.h"
>>> +#include "opt-proposer.h"
>>>  #include "gcc.h"
>>>  #include "opts.h"
>>
>> I think I'd prefer "opt-suggestions.h" here.  Not sure.
>>
>> I don't understand our policies for how me manage #include files - if
>> gcc.h needs a header to compile, isn't it simpler to add that to gcc.h
>> itself?  (encoding that dependency in one place, rather than in
>> everything that uses gcc.h)
> 
> Now it's very bad, due to flat header files one needs to do the explicit inclusion
> of prerequisites for a header file. Don't ask me why..
> 
>>
>>>  
>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>> index d6ef85928f3..9b4ba28f287 100644
>>> --- a/gcc/common.opt
>>> +++ b/gcc/common.opt
>>> @@ -254,6 +254,10 @@ Driver Alias(S)
>>>  -compile
>>>  Driver Alias(c)
>>>  
>>> +-completion=
>>> +Common Driver Joined Undocumented
>>> +--param Bash completion.
>>> +
>>
>> Is this description correct?  This is for much more than just "--param", isn't it?> 
>>>  -coverage
>>>  Driver Alias(coverage)
>>>  
>>> diff --git a/gcc/fortran/gfortranspec.c b/gcc/fortran/gfortranspec.c
>>> index fe1ec0447b3..b95c8810d0f 100644
>>> --- a/gcc/fortran/gfortranspec.c
>>> +++ b/gcc/fortran/gfortranspec.c
>>> @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
>>>  #include "config.h"
>>>  #include "system.h"
>>>  #include "coretypes.h"
>>> +#include "opt-proposer.h"
>>>  #include "gcc.h"
>>>  #include "opts.h"
>>>  
>>> diff --git a/gcc/gcc-main.c b/gcc/gcc-main.c
>>> index 9e6de743adc..3cfdfdc57fa 100644
>>> --- a/gcc/gcc-main.c
>>> +++ b/gcc/gcc-main.c
>>> @@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
>>>  #include "obstack.h"
>>>  #include "intl.h"
>>>  #include "prefix.h"
>>> +#include "opt-proposer.h"
>>>  #include "gcc.h"
>>>  
>>>  /* Implement the top-level "main" within the driver in terms of
>>> diff --git a/gcc/gcc.c b/gcc/gcc.c
>>> index a716f708259..e9207bb9823 100644
>>> --- a/gcc/gcc.c
>>> +++ b/gcc/gcc.c
>>> @@ -36,6 +36,7 @@ compilation is specified by a string called a "spec".  */
>>>  #include "obstack.h"
>>>  #include "intl.h"
>>>  #include "prefix.h"
>>> +#include "opt-proposer.h"
>>>  #include "gcc.h"
>>>  #include "diagnostic.h"
>>>  #include "flags.h"
>>> @@ -220,6 +221,8 @@ static int print_help_list;
>>>  
>>>  static int print_version;
>>>  
>>> +static const char *completion = NULL;
>>> +
>>
>> Please give this variable a descriptive comment.
>>
>>>  /* Flag indicating whether we should ONLY print the command and
>>>     arguments (like verbose_flag) without executing the command.
>>>     Displayed arguments are quoted so that the generated command
>>> @@ -3818,6 +3821,11 @@ driver_handle_option (struct gcc_options *opts,
>>>        add_linker_option ("--version", strlen ("--version"));
>>>        break;
>>>  
>>> +    case OPT__completion_:
>>> +      validated = true;
>>> +      completion = decoded->arg;
>>> +      break;
>>> +
>>>      case OPT__help:
>>>        print_help_list = 1;
>>>  
>>> @@ -7262,8 +7270,7 @@ compare_files (char *cmpfile[])
>>>  
>>>  driver::driver (bool can_finalize, bool debug) :
>>>    explicit_link_files (NULL),
>>> -  decoded_options (NULL),
>>> -  m_option_suggestions (NULL)
>>> +  decoded_options (NULL)
>>>  {
>>>    env.init (can_finalize, debug);
>>>  }
>>> @@ -7272,14 +7279,6 @@ driver::~driver ()
>>>  {
>>>    XDELETEVEC (explicit_link_files);
>>>    XDELETEVEC (decoded_options);
>>> -  if (m_option_suggestions)
>>> -    {
>>> -      int i;
>>> -      char *str;
>>> -      FOR_EACH_VEC_ELT (*m_option_suggestions, i, str)
>>> -	free (str);
>>> -      delete m_option_suggestions;
>>> -    }
>>>  }
>>>  
>>>  /* driver::main is implemented as a series of driver:: method calls.  */
>>> @@ -7300,6 +7299,12 @@ driver::main (int argc, char **argv)
>>>    maybe_putenv_OFFLOAD_TARGETS ();
>>>    handle_unrecognized_options ();
>>>  
>>> +  if (completion)
>>> +    {
>>> +      m_option_proposer.suggest_completion (completion);
>>> +      return 0;
>>> +    }
>>> +
>>>    if (!maybe_print_and_exit ())
>>>      return 0;
>>>  
>>> @@ -7768,106 +7773,6 @@ driver::maybe_putenv_OFFLOAD_TARGETS () const
>>>    offload_targets = NULL;
>>>  }
>>>  
>>> -/* Helper function for driver::suggest_option.  Populate
>>> -   m_option_suggestions with candidate strings for misspelled options.
>>> -   The strings will be freed by the driver's dtor.  */
>>> -
>>> -void
>>> -driver::build_option_suggestions (void)
>>> -{
>>> -  gcc_assert (m_option_suggestions == NULL);
>>> -  m_option_suggestions = new auto_vec <char *> ();
>>> -
>>> -  /* We build a vec of m_option_suggestions, using add_misspelling_candidates
>>> -     to add copies of strings, without a leading dash.  */
>>> -
>>> -  for (unsigned int i = 0; i < cl_options_count; i++)
>>> -    {
>>> -      const struct cl_option *option = &cl_options[i];
>>> -      const char *opt_text = option->opt_text;
>>> -      switch (i)
>>> -	{
>>> -	default:
>>> -	  if (option->var_type == CLVC_ENUM)
>>> -	    {
>>> -	      const struct cl_enum *e = &cl_enums[option->var_enum];
>>> -	      for (unsigned j = 0; e->values[j].arg != NULL; j++)
>>> -		{
>>> -		  char *with_arg = concat (opt_text, e->values[j].arg, NULL);
>>> -		  add_misspelling_candidates (m_option_suggestions, option,
>>> -					      with_arg);
>>> -		  free (with_arg);
>>> -		}
>>> -	    }
>>> -	  else
>>> -	    add_misspelling_candidates (m_option_suggestions, option,
>>> -					opt_text);
>>> -	  break;
>>> -
>>> -	case OPT_fsanitize_:
>>> -	case OPT_fsanitize_recover_:
>>> -	  /* -fsanitize= and -fsanitize-recover= can take
>>> -	     a comma-separated list of arguments.  Given that combinations
>>> -	     are supported, we can't add all potential candidates to the
>>> -	     vec, but if we at least add them individually without commas,
>>> -	     we should do a better job e.g. correcting
>>> -	       "-sanitize=address"
>>> -	     to
>>> -	       "-fsanitize=address"
>>> -	     rather than to "-Wframe-address" (PR driver/69265).  */
>>> -	  {
>>> -	    for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
>>> -	      {
>>> -		struct cl_option optb;
>>> -		/* -fsanitize=all is not valid, only -fno-sanitize=all.
>>> -		   So don't register the positive misspelling candidates
>>> -		   for it.  */
>>> -		if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
>>> -		  {
>>> -		    optb = *option;
>>> -		    optb.opt_text = opt_text = "-fno-sanitize=";
>>> -		    optb.cl_reject_negative = true;
>>> -		    option = &optb;
>>> -		  }
>>> -		/* Get one arg at a time e.g. "-fsanitize=address".  */
>>> -		char *with_arg = concat (opt_text,
>>> -					 sanitizer_opts[j].name,
>>> -					 NULL);
>>> -		/* Add with_arg and all of its variant spellings e.g.
>>> -		   "-fno-sanitize=address" to candidates (albeit without
>>> -		   leading dashes).  */
>>> -		add_misspelling_candidates (m_option_suggestions, option,
>>> -					    with_arg);
>>> -		free (with_arg);
>>> -	      }
>>> -	  }
>>> -	  break;
>>> -	}
>>> -    }
>>> -}
>>> -
>>> -/* Helper function for driver::handle_unrecognized_options.
>>> -
>>> -   Given an unrecognized option BAD_OPT (without the leading dash),
>>> -   locate the closest reasonable matching option (again, without the
>>> -   leading dash), or NULL.
>>> -
>>> -   The returned string is owned by the driver instance.  */
>>> -
>>> -const char *
>>> -driver::suggest_option (const char *bad_opt)
>>> -{
>>> -  /* Lazily populate m_option_suggestions.  */
>>> -  if (!m_option_suggestions)
>>> -    build_option_suggestions ();
>>> -  gcc_assert (m_option_suggestions);
>>> -
>>> -  /* "m_option_suggestions" is now populated.  Use it.  */
>>> -  return find_closest_string
>>> -    (bad_opt,
>>> -     (auto_vec <const char *> *) m_option_suggestions);
>>> -}
>>> -
>>>  /* Reject switches that no pass was interested in.  */
>>>  
>>>  void
>>> @@ -7876,7 +7781,7 @@ driver::handle_unrecognized_options ()
>>>    for (size_t i = 0; (int) i < n_switches; i++)
>>>      if (! switches[i].validated)
>>>        {
>>> -	const char *hint = suggest_option (switches[i].part1);
>>> +	const char *hint = m_option_proposer.suggest_option (switches[i].part1);
>>>  	if (hint)
>>>  	  error ("unrecognized command line option %<-%s%>;"
>>>  		 " did you mean %<-%s%>?",
>>> diff --git a/gcc/gcc.h b/gcc/gcc.h
>>> index ddbf42f78ea..a7606183393 100644
>>> --- a/gcc/gcc.h
>>> +++ b/gcc/gcc.h
>>> @@ -45,8 +45,6 @@ class driver
>>>    void putenv_COLLECT_GCC (const char *argv0) const;
>>>    void maybe_putenv_COLLECT_LTO_WRAPPER () const;
>>>    void maybe_putenv_OFFLOAD_TARGETS () const;
>>> -  void build_option_suggestions (void);
>>> -  const char *suggest_option (const char *bad_opt);
>>>    void handle_unrecognized_options ();
>>>    int maybe_print_and_exit () const;
>>>    bool prepare_infiles ();
>>> @@ -59,7 +57,7 @@ class driver
>>>    char *explicit_link_files;
>>>    struct cl_decoded_option *decoded_options;
>>>    unsigned int decoded_options_count;
>>> -  auto_vec <char *> *m_option_suggestions;
>>> +  option_proposer m_option_proposer;
>>
>> FWIW I'd prefer:
>>
>>   option_suggestions m_option_suggestions;
>>
>> but proposer is a better fit, I guess.
>>
>>>  };
>>>  
>>>  /* The mapping of a spec function name to the C function that
>>> diff --git a/gcc/opt-proposer.c b/gcc/opt-proposer.c
>>> new file mode 100644
>>> index 00000000000..08379f0b631
>>> --- /dev/null
>>> +++ b/gcc/opt-proposer.c
>>> @@ -0,0 +1,420 @@
>>> +/* Provide option suggestion for --complete option and a misspelled
>>> +   used by a user.
>>
>> Maybe reword to:
>>
>> /* Provide suggestions to handle misspelled options, and implement the
>>    --complete option for auto-completing options from a prefix.  */
>>
>> or somesuch.
>>
>>> +   Copyright (C) 2018 Free Software Foundation, Inc.
>>
>> This new file contains older material that was in gcc.c; I believe the
>> earliest such material that you're copying and pasting is from r233382,
>> which was from 2016, so the copyright date should be the range 2016-2018,
>> if I understand our policies here correctly.
>>
>>> +This file is part of GCC.
>>> +
>>> +GCC is free software; you can redistribute it and/or modify it under
>>> +the terms of the GNU General Public License as published by the Free
>>> +Software Foundation; either version 3, or (at your option) any later
>>> +version.
>>> +
>>> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
>>> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>> +for more details.
>>> +
>>> +You should have received a copy of the GNU General Public License
>>> +along with GCC; see the file COPYING3.  If not see
>>> +<http://www.gnu.org/licenses/>.  */
>>> +
>>> +#include "config.h"
>>> +#include "system.h"
>>> +#include "coretypes.h"
>>> +#include "tm.h"
>>> +#include "opts.h"
>>> +#include "params.h"
>>> +#include "spellcheck.h"
>>> +#include "opt-proposer.h"
>>> +#include "selftest.h"
>>> +
>>> +option_proposer::~option_proposer ()
>>
>> Needs a leading descriptive comment; maybe just use:
>>
>> /* option_proposer's dtor.  */
>>
>>> +{
>>> +  if (m_option_suggestions)
>>> +    {
>>> +      int i;
>>> +      char *str;
>>> +      FOR_EACH_VEC_ELT (*m_option_suggestions, i, str)
>>> +       free (str);
>>> +      delete m_option_suggestions;
>>> +    }
>>> +
>>> +  release_completion_results ();
>>
>> Presumably you're stashing the results to avoid having to deal with lifetime
>> issues of the strings when running the selftests?
>> Or is it due to the misspellings code expecting an implicit leading "-",
>> whereas the completion code doesn't have an implicit leading "--"?
>>
>> It seems like it would be simpler to have a class that's a managed vec of
>> strings: we already nearly have one for m_option_suggestion?  (auto_string_vec
>> or somesuch?  See class auto_argvec in jit/jit-playback.c).
>>
>> If so, then the option_proposer's data would simply be two instance of
>> this managed vec; the cleanup logic would be in auto_string_vec's dtor.
>>
>> Alternatively, it seems a bit weird to have the option_proposer own the
>> results.  Maybe have the caller pass in an auto_string_vec& to be
>> populated, and thus have the caller manage the lifetime of the results:
>>
>> void
>> option_proposer::get_completions (const char *option_prefix,
>>                                   auto_string_vec &out)
>>
>> (Better would be to return an auto_string_vec, but given that we're
>> stuck on C++98 it seems safest to pass it in by reference as an out-var).
>>
>>> +}
>>>
>>> +const char *
>>> +option_proposer::suggest_option (const char *bad_opt)
>>> +{
>>
>> Needs a leading descriptive comment; maybe use:
>>
>> /* Given an unrecognized option BAD_OPT (without the leading dash),
>>    locate the closest reasonable matching option (again, without the
>>    leading dash), or NULL.
>>
>>    The returned string is owned by the option_proposer instance.  */
>>
>> (I adapted this from the older code; is it still true?)
>>
>>> +  /* Lazily populate m_option_suggestions.  */
>>> +  if (!m_option_suggestions)
>>> +    build_option_suggestions ();
>>> +  gcc_assert (m_option_suggestions);
>>> +
>>> +  /* "m_option_suggestions" is now populated.  Use it.  */
>>> +  return find_closest_string
>>> +    (bad_opt,
>>> +     (auto_vec <const char *> *) m_option_suggestions);
>>> +}
>>
>>
>>> +void
>>> +option_proposer::build_completions (const char *starting)
>>> +{
>>
>> Needs a leading descriptive comment.
>>
>> Maybe "option_prefix" rather than "starting"?
>>
>>> +  release_completion_results ();
>>> +
>>> +  /* Bail out for an invalid input.  */
>>> +  if (starting == NULL || starting[0] == '\0')
>>> +    return;
>>> +
>>> +  if (starting[0] == '-')
>>> +    starting++;
>>
>> What's the purpose of the above logic?  (a genuine question)
>> Maybe it warrants a comment?
>>
>>> +
>>> +  size_t length = strlen (starting);
>>> +
>>> +  /* Handle parameters.  */
>>> +  const char *prefix = "-param";
>>> +  if (length >= strlen (prefix) && strstr (starting, prefix) == starting)
>>> +    {
>>> +      /* We support both '-param-xyz=123' and '-param xyz=123' */
>>> +      starting += strlen (prefix);
>>> +      char separator = starting[0];
>>> +      starting++;
>>> +      if (separator == ' ' || separator == '=')
>>> +	find_param_completions (separator, starting);
>>> +    }
>>> +  else
>>> +    {
>>> +      /* Lazily populate m_option_suggestions.  */
>>> +      if (!m_option_suggestions)
>>> +	build_option_suggestions ();
>>> +      gcc_assert (m_option_suggestions);
>>> +
>>> +      for (unsigned i = 0; i < m_option_suggestions->length (); i++)
>>> +	{
>>> +	  char *candidate = (*m_option_suggestions)[i];
>>> +	  if (strlen (candidate) >= length
>>> +	      && strstr (candidate, starting) == candidate)
>>> +	    m_completion_results.safe_push (concat ("-", candidate, NULL));
>>> +	}
>>> +    }
>>> +}
>>> +
>>> +void
>>> +option_proposer::suggest_completion (const char *starting)
>>
>> Needs a leading descriptive comment.
>>
>>> +{
>>> +  build_completions (starting);
>>> +  print_completion_results ();
>>> +  release_completion_results ();
>>> +}
>>> +
>>> +auto_vec <char *> *
>>> +option_proposer::get_completion_suggestions (const char *starting)
>>
>> Needs a leading descriptive comment.  Presumably this purely exists for
>> the selftests, right?  Can it be a "const"?
>>
>>> +{
>>> +  build_completions (starting);
>>> +  return &m_completion_results;
>>> +}
>>> +
>>> +void
>>> +option_proposer::build_option_suggestions (void)
>>
>> Needs a leading descriptive comment; possibly something like:
>>
>> /* Populate m_option_suggestions with candidate strings for misspelled options.
>>    The strings will be freed by the driver's dtor.  */
>>
>> or somesuch (adapted from the older code).
>>
>>> +{
>>> +  gcc_assert (m_option_suggestions == NULL);
>>> +  m_option_suggestions = new auto_vec <char *> ();
>>> +
>>> +  /* We build a vec of m_option_suggestions, using add_misspelling_candidates
>>> +     to add copies of strings, without a leading dash.  */
>>> +
>>> +  for (unsigned int i = 0; i < cl_options_count; i++)
>>> +    {
>>> +      const struct cl_option *option = &cl_options[i];
>>> +      const char *opt_text = option->opt_text;
>>> +      switch (i)
>>> +	{
>>> +	default:
>>> +	  if (option->var_type == CLVC_ENUM)
>>> +	    {
>>> +	      const struct cl_enum *e = &cl_enums[option->var_enum];
>>> +	      for (unsigned j = 0; e->values[j].arg != NULL; j++)
>>> +		{
>>> +		  char *with_arg = concat (opt_text, e->values[j].arg, NULL);
>>> +		  add_misspelling_candidates (m_option_suggestions, option,
>>> +					      with_arg);
>>> +		  free (with_arg);
>>> +		}
>>> +	    }
>>> +	  else
>>> +	    add_misspelling_candidates (m_option_suggestions, option,
>>> +					opt_text);
>>> +	  break;
>>> +
>>> +	case OPT_fsanitize_:
>>> +	case OPT_fsanitize_recover_:
>>> +	  /* -fsanitize= and -fsanitize-recover= can take
>>> +	     a comma-separated list of arguments.  Given that combinations
>>> +	     are supported, we can't add all potential candidates to the
>>> +	     vec, but if we at least add them individually without commas,
>>> +	     we should do a better job e.g. correcting
>>> +	       "-sanitize=address"
>>> +	     to
>>> +	       "-fsanitize=address"
>>> +	     rather than to "-Wframe-address" (PR driver/69265).  */
>>> +	  {
>>> +	    for (int j = 0; sanitizer_opts[j].name != NULL; ++j)
>>> +	      {
>>> +		struct cl_option optb;
>>> +		/* -fsanitize=all is not valid, only -fno-sanitize=all.
>>> +		   So don't register the positive misspelling candidates
>>> +		   for it.  */
>>> +		if (sanitizer_opts[j].flag == ~0U && i == OPT_fsanitize_)
>>> +		  {
>>> +		    optb = *option;
>>> +		    optb.opt_text = opt_text = "-fno-sanitize=";
>>> +		    optb.cl_reject_negative = true;
>>> +		    option = &optb;
>>> +		  }
>>> +		/* Get one arg at a time e.g. "-fsanitize=address".  */
>>> +		char *with_arg = concat (opt_text,
>>> +					 sanitizer_opts[j].name,
>>> +					 NULL);
>>> +		/* Add with_arg and all of its variant spellings e.g.
>>> +		   "-fno-sanitize=address" to candidates (albeit without
>>> +		   leading dashes).  */
>>> +		add_misspelling_candidates (m_option_suggestions, option,
>>> +					    with_arg);
>>> +		free (with_arg);
>>> +	      }
>>> +	  }
>>> +	  break;
>>> +	}
>>> +    }
>>> +}
>>> +
>>> +void
>>> +option_proposer::find_param_completions (const char separator,
>>> +					 const char *starting)
>>> +{
>>
>> Needs a leading descriptive comment.
>>
>>> +  char separator_str[] {separator, '\0'};
>>> +  size_t length = strlen (starting);
>>> +  for (unsigned i = 0; i < get_num_compiler_params (); ++i)
>>> +    {
>>> +      const char *candidate = compiler_params[i].option;
>>> +      if (strlen (candidate) >= length
>>> +	  && strstr (candidate, starting) == candidate)
>>> +	m_completion_results.safe_push (concat ("--param", separator_str,
>>> +						candidate, NULL));
>>> +    }
>>> +}
>>> +
>>> +void
>>> +option_proposer::print_completion_results ()
>>> +{
>>
>> Needs a leading descriptive comment.
>>
>>> +  for (unsigned i = 0; i < m_completion_results.length (); i++)
>>> +    printf ("%s\n", m_completion_results[i]);
>>> +}
>>> +
>>> +void
>>> +option_proposer::release_completion_results ()
>>> +{
>>
>> Needs a leading descriptive comment.
> 
> There are multiple situations where I have comment in header file (opt-suggestions.h).
> Is it needed to copy it to implementation? I consider it a duplicate information.
> 
> I'll send 3 patches that are split from the original one afterwards.
> 
> Thanks a lot,
> Martin
> 
>>
>>> +  for (unsigned i = 0; i < m_completion_results.length (); i++)
>>> +    free (m_completion_results[i]);
>>> +
>>> +  m_completion_results.truncate (0);
>>> +}
>>> +
>>> +#if CHECKING_P
>>> +
>>> +namespace selftest {
>>> +
>>> +static void
>>> +test_valid_option (option_proposer &proposer, const char *option)
>>
>> Needs a leading descriptive comment.  Maybe rename option to "starting",
>> or to "option_prefix".
>>
>> /* Verify that PROPOSER generate sane auto-completion suggestions for STARTING. */
>>
>> Maybe rename the function e.g. to verify_autocompletions or somesuch.
>>
>>> +{
>>> +  auto_vec <char *> *suggestions = proposer.get_completion_suggestions (option);
>>> +  ASSERT_GT (suggestions->length (), 0);
>>> +
>>> +  for (unsigned i = 0; i < suggestions->length (); i++)
>>> +    ASSERT_STR_STARTSWITH ((*suggestions)[i], option);
>>> +}
>>> +
>>> +/* Verify that valid options works correctly.  */
>>
>> How about:
>>
>> /* Verify that valid options are auto-completed correctly.  */
>>
>>> +
>>> +static void
>>> +test_completion_valid_options (option_proposer &proposer)
>>> +{
>>> +  const char *needles[]
>>
>> I like the use of "needle" and "haystack" as param names for arbitrary
>> string searches, but I don't like them for the prefix-based search
>> we're doing here.
>>
>> How about "starting_strs" here, or "option_prefixes"?
>>
>>> +  {
>>> +    "-fno-var-tracking-assignments-toggle",
>>> +    "-fpredictive-commoning",
>>> +    "--param=stack-clash-protection-guard-size",
>>> +    "--param=max-predicted-iterations",
>>> +    "-ftree-loop-distribute-patterns",
>>> +    "-fno-var-tracking",
>>> +    "-Walloc-zero",
>>> +    "--param=ipa-cp-value-list-size",
>>> +    "-Wsync-nand",
>>> +    "-Wno-attributes",
>>> +    "--param=tracer-dynamic-coverage-feedback",
>>> +    "-Wno-format-contains-nul",
>>> +    "-Wnamespaces",
>>> +    "-fisolate-erroneous-paths-attribute",
>>> +    "-Wno-underflow",
>>> +    "-Wtarget-lifetime",
>>> +    "--param=asan-globals",
>>> +    "-Wno-empty-body",
>>> +    "-Wno-odr",
>>> +    "-Wformat-zero-length",
>>> +    "-Wstringop-truncation",
>>> +    "-fno-ipa-vrp",
>>> +    "-fmath-errno",
>>> +    "-Warray-temporaries",
>>> +    "-Wno-unused-label",
>>> +    "-Wreturn-local-addr",
>>> +    "--param=sms-dfa-history",
>>> +    "--param=asan-instrument-reads",
>>> +    "-Wreturn-type",
>>> +    "-Wc++17-compat",
>>> +    "-Wno-effc++",
>>> +    "--param=max-fields-for-field-sensitive",
>>> +    "-fisolate-erroneous-paths-dereference",
>>> +    "-fno-defer-pop",
>>> +    "-Wcast-align=strict",
>>> +    "-foptimize-strlen",
>>> +    "-Wpacked-not-aligned",
>>> +    "-funroll-loops",
>>> +    "-fif-conversion2",
>>> +    "-Wdesignated-init",
>>> +    "--param=max-iterations-computation-cost",
>>> +    "-Wmultiple-inheritance",
>>> +    "-fno-sel-sched-reschedule-pipelined",
>>> +    "-Wassign-intercept",
>>> +    "-Wno-format-security",
>>> +    "-fno-sched-stalled-insns",
>>> +    "-fbtr-bb-exclusive",
>>> +    "-fno-tree-tail-merge",
>>> +    "-Wlong-long",
>>> +    "-Wno-unused-but-set-parameter",
>>> +    NULL
>>> +  };
>>> +
>>> +  for (const char **ptr = needles; *ptr != NULL; ptr++)
>>> +    test_valid_option (proposer, *ptr);
>>> +}
>>> +
>>> +/* Verify that valid parameter works correctly.  */
>>
>> Maybe:
>>
>> /* Verify that valid parameters are auto-completed correctly,
>>    both with the "--param=PARAM" form and the "--param PARAM" form.  */
>>
>>> +
>>> +static void
>>> +test_completion_valid_params (option_proposer &proposer)
>>> +{
>>> +  const char *needles[]
>>
>> "starting_strs" or "option_prefixes" rather than "needles".
>>
>>> +  {
>>> +    "--param=sched-state-edge-prob-cutoff",
>>> +    "--param=iv-consider-all-candidates-bound",
>>> +    "--param=align-threshold",
>>> +    "--param=prefetch-min-insn-to-mem-ratio",
>>> +    "--param=max-unrolled-insns",
>>> +    "--param=max-early-inliner-iterations",
>>> +    "--param=max-vartrack-reverse-op-size",
>>> +    "--param=ipa-cp-loop-hint-bonus",
>>> +    "--param=tracer-min-branch-ratio",
>>> +    "--param=graphite-max-arrays-per-scop",
>>> +    "--param=sink-frequency-threshold",
>>> +    "--param=max-cse-path-length",
>>> +    "--param=sra-max-scalarization-size-Osize",
>>> +    "--param=prefetch-latency",
>>> +    "--param=dse-max-object-size",
>>> +    "--param=asan-globals",
>>> +    "--param=max-vartrack-size",
>>> +    "--param=case-values-threshold",
>>> +    "--param=max-slsr-cand-scan",
>>> +    "--param=min-insn-to-prefetch-ratio",
>>> +    "--param=tracer-min-branch-probability",
>>> +    "--param sink-frequency-threshold",
>>> +    "--param max-cse-path-length",
>>> +    "--param sra-max-scalarization-size-Osize",
>>> +    "--param prefetch-latency",
>>> +    "--param dse-max-object-size",
>>> +    "--param asan-globals",
>>> +    "--param max-vartrack-size",
>>> +    NULL
>>> +  };
>>> +
>>> +  for (const char **ptr = needles; *ptr != NULL; ptr++)
>>> +    test_valid_option (proposer, *ptr);
>>> +}
>>> +
>>> +/* Return true when EXPECTED is one of completions for OPTION string.  */
>>
>> Maybe rename "option" to "option_prefix"?
>>
>>> +
>>> +static bool
>>> +in_completion_p (option_proposer &proposer, const char *option,
>>> +		 const char *expected)
>>> +{
>>> +  auto_vec <char *> *suggestions = proposer.get_completion_suggestions (option);
>>> +
>>> +  for (unsigned i = 0; i < suggestions->length (); i++)
>>> +    {
>>> +      char *r = (*suggestions)[i];
>>> +      if (strcmp (r, expected) == 0)
>>> +	return true;
>>> +    }
>>> +
>>> +  return false;
>>> +}
>>
>> Going with the above ideas on ownership, passing in an auto_string_vec &,
>> this might look like:
>>
>> static bool
>> in_completion_p (option_proposer &proposer, const char *option_prefix,
>> 		 const char *expected)
>> {
>>   auto_string_vec suggestions;
>>   proposer.get_completion_suggestions (suggestions, option_prefix);
>>
>>   for (unsigned i = 0; i < suggestions->length (); i++)
>>     {
>>       char *r = (*suggestions)[i];
>>       if (strcmp (r, expected) == 0)
>> 	return true;
>>     }
>>
>>   return false;
>> }
>>
>>
>>> +static bool
>>> +empty_completion_p (option_proposer &proposer, const char *option)
>>> +{
>>
>> Needs leading comment; maybe rename to "option_prefix".
>>
>>> +  auto_vec <char *> *suggestions = proposer.get_completion_suggestions (option);
>>> +  return suggestions->is_empty ();
>>> +}
>>
>> With ownership ideas above, might look like:
>>
>> static bool
>> empty_completion_p (option_proposer &proposer, const char *option_prefix)
>> {
>>   auto_string_vec suggestions;
>>   proposer.get_completion_suggestions (suggestions, option_prefix);
>>   return suggestions->is_empty ();
>> }
>>
>>> +/* Verify partial completions.  */
>>
>> Maybe:
>>
>> /* Verify autocompletions of partially-complete options.  */
>>
>>> +
>>> +static void
>>> +test_completion_partial_match (option_proposer &proposer)
>>> +{
>>> +  ASSERT_TRUE (in_completion_p (proposer, "-fsani", "-fsanitize=address"));
>>> +  ASSERT_TRUE (in_completion_p (proposer, "-fsani",
>>> +				"-fsanitize-address-use-after-scope"));
>>> +  ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf-functions"));
>>> +  ASSERT_TRUE (in_completion_p (proposer, "-fipa-icf", "-fipa-icf"));
>>> +  ASSERT_TRUE (in_completion_p (proposer, "--param=",
>>> +				"--param=max-vartrack-reverse-op-size"));
>>> +  ASSERT_TRUE (in_completion_p (proposer, "--param ",
>>> +				"--param max-vartrack-reverse-op-size"));
>>> +
>>> +  ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf", "-fipa"));
>>> +  ASSERT_FALSE (in_completion_p (proposer, "-fipa-icf-functions", "-fipa-icf"));
>>> +}
>>> +
>>> +/* Verify that a garbage does not return a completion match.  */
>>
>> Maybe:
>>
>> /* Verify that autocompletion does not return any match for garbage inputs.  */
>>
>>> +static void
>>> +test_completion_garbage (option_proposer &proposer)
>>> +{
>>> +  ASSERT_TRUE (empty_completion_p (proposer, NULL));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, ""));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, "- "));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, "123456789"));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, "---------"));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, "#########"));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, "- - - - - -"));
>>> +  ASSERT_TRUE (empty_completion_p (proposer, "-fsanitize=address2"));
>>> +
>>> +  ASSERT_FALSE (empty_completion_p (proposer, "-"));
>>> +  ASSERT_FALSE (empty_completion_p (proposer, "-fipa"));
>>> +  ASSERT_FALSE (empty_completion_p (proposer, "--par"));
>>
>> Maybe move these ASSERT_FALSE cases to test_completion_partial_match?
>>
>>> +}
>>> +
>>> +/* Run all of the selftests within this file.  */
>>> +
>>> +void
>>> +opt_proposer_c_tests ()
>>> +{
>>> +  option_proposer proposer;
>>> +
>>> +  test_completion_valid_options (proposer);
>>> +  test_completion_valid_params (proposer);
>>> +  test_completion_partial_match (proposer);
>>> +  test_completion_garbage (proposer);
>>> +}
>>> +
>>> +} // namespace selftest
>>> +
>>> +#endif /* #if CHECKING_P */
>>> diff --git a/gcc/opt-proposer.h b/gcc/opt-proposer.h
>>> new file mode 100644
>>> index 00000000000..b673f02dc70
>>> --- /dev/null
>>> +++ b/gcc/opt-proposer.h
>>> @@ -0,0 +1,84 @@
>>> +/* Provide option suggestion for --complete option and a misspelled
>>> +   used by a user.
>>
>> Maybe reword as per opt-proposer.c above.
>>
>>> +   Copyright (C) 2018 Free Software Foundation, Inc.
>>
>> 2016-2018, I think.
>>
>>> +
>>> +This file is part of GCC.
>>> +
>>> +GCC is free software; you can redistribute it and/or modify it under
>>> +the terms of the GNU General Public License as published by the Free
>>> +Software Foundation; either version 3, or (at your option) any later
>>> +version.
>>> +
>>> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
>>> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
>>> +for more details.
>>> +
>>> +You should have received a copy of the GNU General Public License
>>> +along with GCC; see the file COPYING3.  If not see
>>> +<http://www.gnu.org/licenses/>.  */
>>> +
>>> +#ifndef GCC_OPT_PROPOSER_H
>>> +#define GCC_OPT_PROPOSER_H
>>> +
>>> +/* Option proposer is class used by driver in order to provide hints
>>> +   for wrong options provided.  And it's used by --complete option that's
>>> +   intended to be invoked by BASH in order to provide better option
>>> +   completion support.  */
>>> +
>>> +class option_proposer
>>> +{
>>> +public:
>>> +  /* Default constructor.  */
>>> +  option_proposer (): m_option_suggestions (NULL), m_completion_results ()
>>> +  {}
>>> +
>>> +  /* Default destructor.  */
>>> +  ~option_proposer ();
>>> +
>>> +  /* Helper function for driver::handle_unrecognized_options.
>>> +
>>> +     Given an unrecognized option BAD_OPT (without the leading dash),
>>> +     locate the closest reasonable matching option (again, without the
>>> +     leading dash), or NULL.
>>> +
>>> +     The returned string is owned by the option_proposer instance.  */
>>> +  const char *suggest_option (const char *bad_opt);
>>> +
>>> +  /* Print to stdout all options that start with STARTING.  */
>>> +  void suggest_completion (const char *starting);
>>> +
>>> +  /* Return vector with completion suggestions that start with STARTING.
>>> +
>>> +     The returned strings are owned by the option_proposer instance.  */
>>> +  auto_vec <char *> *get_completion_suggestions (const char *starting);
>>> +
>>> +private:
>>> +  /* Helper function for option_proposer::suggest_option.  Populate
>>> +     m_option_suggestions with candidate strings for misspelled options.
>>> +     The strings will be freed by the option_proposer's dtor.  */
>>> +  void build_option_suggestions ();
>>> +
>>> +  /* Build completions that start with STARTING and save them
>>> +     into m_completion_results vector.  */
>>> +  void build_completions (const char *starting);
>>> +
>>> +  /* Find parameter completions for --param format with SEPARATOR.
>>> +     Again, save the completions into m_completion_results.  */
>>> +  void find_param_completions (const char separator, const char *starting);
>>> +
>>> +  /* Print found completions in m_completion_results to stdout.  */
>>> +  void print_completion_results ();
>>> +
>>> +  /* Free content of m_completion_results.  */
>>> +  void release_completion_results ();
>>> +
>>> +private:
>>> +  /* Cache with all suggestions.  */
>>> +  auto_vec <char *> *m_option_suggestions;
>>> +
>>> +  /* Completion cache.  */
>>> +  auto_vec <char *> m_completion_results;
>>> +};
>>> +
>>> +#endif  /* GCC_OPT_PROPOSER_H */
>>> diff --git a/gcc/opts.c b/gcc/opts.c
>>> index 33efcc0d6e7..ed102c05c22 100644
>>> --- a/gcc/opts.c
>>> +++ b/gcc/opts.c
>>> @@ -1982,6 +1982,9 @@ common_handle_option (struct gcc_options *opts,
>>>        opts->x_exit_after_options = true;
>>>        break;
>>>  
>>> +    case OPT__completion_:
>>> +      break;
>>> +
>>>      case OPT_fsanitize_:
>>>        opts->x_flag_sanitize
>>>  	= parse_sanitizer_options (arg, loc, code,
>>> diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
>>> index fe221ff8946..0b45c479192 100644
>>> --- a/gcc/selftest-run-tests.c
>>> +++ b/gcc/selftest-run-tests.c
>>> @@ -70,6 +70,7 @@ selftest::run_tests ()
>>>    fibonacci_heap_c_tests ();
>>>    typed_splay_tree_c_tests ();
>>>    unique_ptr_tests_cc_tests ();
>>> +  opt_proposer_c_tests ();
>>>  
>>>    /* Mid-level data structures.  */
>>>    input_c_tests ();
>>> diff --git a/gcc/selftest.c b/gcc/selftest.c
>>> index 5709110c291..4cff89d2909 100644
>>> --- a/gcc/selftest.c
>>> +++ b/gcc/selftest.c
>>> @@ -118,6 +118,39 @@ assert_str_contains (const location &loc,
>>>  	 desc_haystack, desc_needle, val_haystack, val_needle);
>>>  }
>>>  
>>> +/* Implementation detail of ASSERT_STR_STARTSWITH.
>>> +   Use strstr to determine if val_haystack starts with val_needle.
>>> +   ::selftest::pass if it starts.
>>> +   ::selftest::fail if it does not start.  */
>>> +
>>> +void
>>> +assert_str_startswith (const location &loc,
>>> +		       const char *desc_haystack,
>>> +		       const char *desc_needle,
>>> +		       const char *val_haystack,
>>> +		       const char *val_needle)
>>
>> I don't think we should use "haystack" and "needle" for prefix-based
>> string searches.
>>
>> Maybe rename "haystack" to "str" and "needle" to "prefix".
>>
>>> +{
>>> +  /* If val_haystack is NULL, fail with a custom error message.  */
>>> +  if (val_haystack == NULL)
>>> +    fail_formatted (loc, "ASSERT_STR_STARTSWITH (%s, %s) haystack=NULL",
>>> +		    desc_haystack, desc_needle);
>>> +
>>> +  /* If val_needle is NULL, fail with a custom error message.  */
>>> +  if (val_needle == NULL)
>>> +    fail_formatted (loc,
>>> +		    "ASSERT_STR_STARTSWITH (%s, %s) haystack=\"%s\" needle=NULL",
>>> +		    desc_haystack, desc_needle, val_haystack);
>>> +
>>> +  const char *test = strstr (val_haystack, val_needle);
>>> +  if (test == val_haystack)
>>> +    pass (loc, "ASSERT_STR_STARTSWITH");
>>> +  else
>>> +    fail_formatted
>>> +	(loc, "ASSERT_STR_STARTSWITH (%s, %s) haystack=\"%s\" needle=\"%s\"",
>>> +	 desc_haystack, desc_needle, val_haystack, val_needle);
>>> +}
>>> +
>>> +
>>>  /* Constructor.  Generate a name for the file.  */
>>>  
>>>  named_temp_file::named_temp_file (const char *suffix)
>>> diff --git a/gcc/selftest.h b/gcc/selftest.h
>>> index e3117c6bfc4..b5d7eeef86e 100644
>>> --- a/gcc/selftest.h
>>> +++ b/gcc/selftest.h
>>> @@ -78,6 +78,15 @@ extern void assert_str_contains (const location &loc,
>>>  				 const char *val_haystack,
>>>  				 const char *val_needle);
>>>  
>>> +/* Implementation detail of ASSERT_STR_STARTSWITH.  */
>>> +
>>> +extern void assert_str_startswith (const location &loc,
>>> +				   const char *desc_expected,
>>> +				   const char *desc_actual,
>>> +				   const char *val_expected,
>>> +				   const char *val_actual);
>>
>> Rename params for consistency with the above.
>>
>>> +
>>>  /* A named temporary file for use in selftests.
>>>     Usable for writing out files, and as the base class for
>>>     temp_source_file.
>>> @@ -216,6 +225,7 @@ extern void wide_int_cc_tests ();
>>>  extern void predict_c_tests ();
>>>  extern void simplify_rtx_c_tests ();
>>>  extern void vec_perm_indices_c_tests ();
>>> +extern void opt_proposer_c_tests ();
>>>  
>>>  extern int num_passes;
>>>  
>>> @@ -401,6 +411,17 @@ extern int num_passes;
>>>  				   (HAYSTACK), (NEEDLE));		\
>>>    SELFTEST_END_STMT
>>>  
>>> +/* Evaluate HAYSTACK and NEEDLE and use strstr to determine if HAYSTACK
>>> +   starts with NEEDLE.
>>> +   ::selftest::pass if starts.
>>> +   ::selftest::fail if does not start.  */
>>> +
>>> +#define ASSERT_STR_STARTSWITH(HAYSTACK, NEEDLE)				    \
>>> +  SELFTEST_BEGIN_STMT							    \
>>> +  ::selftest::assert_str_startswith (SELFTEST_LOCATION, #HAYSTACK, #NEEDLE, \
>>> +				     (HAYSTACK), (NEEDLE));		    \
>>> +  SELFTEST_END_STMT
>>
>> Likewise.
>>
>>>  /* Evaluate PRED1 (VAL1), calling ::selftest::pass if it is true,
>>>     ::selftest::fail if it is false.  */
>>
>> Hope this is constructive
>> Dave
>>
> 
> 



More information about the Gcc-patches mailing list