Re: [PATCH 1/3] c-family: add name_hint/deferred_diagnostic

2017-08-03 Thread Jeff Law
On 07/03/2017 11:32 AM, David Malcolm wrote:
> On Mon, 2017-07-03 at 10:25 -0600, Jeff Law wrote:
>> On 05/05/2017 11:51 AM, David Malcolm wrote:
>>> In various places we use lookup_name_fuzzy to provide a hint,
>>> and can report messages of the form:
>>>   error: unknown foo named 'bar'
>>> or:
>>>   error: unknown foo named 'bar'; did you mean 'SUGGESTION?
>>>
>>> This patch provides a way for lookup_name_fuzzy to provide
>>> both the suggestion above, and (optionally) additional hints
>>> that can be printed e.g.
>>>
>>>   note: did you forget to include ?
>>>
>>> This patch provides the mechanism and ports existing users
>>> of lookup_name_fuzzy to the new return type.
>>> There are no uses of such hints in this patch, but followup
>>> patches provide various front-end specific uses of this.
>>>
>>> gcc/c-family/ChangeLog:
>>> * c-common.h (class deferred_diagnostic): New class.
>>> (class name_hint): New class.
>>> (lookup_name_fuzzy): Convert return type from const char *
>>> to name_hint.  Add location_t param.
>>>
>>> gcc/c/ChangeLog:
>>> * c-decl.c (implicit_decl_warning): Convert "hint" from
>>> const char * to name_hint.  Pass location to
>>> lookup_name_fuzzy.  Suppress any deferred diagnostic if the
>>> warning was not printed.
>>> (undeclared_variable): Likewise for "guessed_id".
>>> (lookup_name_fuzzy): Convert return type from const char *
>>> to name_hint.  Add location_t param.
>>> * c-parser.c (c_parser_declaration_or_fndef): Convert "hint"
>>> from
>>> const char * to name_hint.  Pass location to lookup_name_fuzzy.
>>> (c_parser_parameter_declaration): Pass location to
>>> lookup_name_fuzzy.
>>>
>>> gcc/cp/ChangeLog:
>>> * name-lookup.c (suggest_alternatives_for): Convert
>>> "fuzzy_name" from
>>> const char * to name_hint, and rename to "hint".  Pass location
>>> to
>>> lookup_name_fuzzy.
>>> (lookup_name_fuzzy): Convert return type from const char *
>>> to name_hint.  Add location_t param.
>>> * parser.c (cp_parser_diagnose_invalid_type_name): Convert
>>> "suggestion" from const char * to name_hint, and rename to
>>> "hint".
>>> Pass location to lookup_name_fuzzy.
>>
>>> ---
>>>  gcc/c-family/c-common.h | 121
>>> +++-
>>>  gcc/c/c-decl.c  |  35 +++---
>>>  gcc/c/c-parser.c|  16 ---
>>>  gcc/cp/name-lookup.c|  17 +++
>>>  gcc/cp/parser.c |  12 ++---
>>>  5 files changed, 163 insertions(+), 38 deletions(-)
>>>
>>> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
>>> index 138a0a6..83c1a68 100644
>>> --- a/gcc/c-family/c-common.h
>>> +++ b/gcc/c-family/c-common.h
>>> @@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind {
>>>/* Any name.  */
>>>FUZZY_LOOKUP_NAME
>>>  };
>>> -extern const char *lookup_name_fuzzy (tree, enum
>>> lookup_name_fuzzy_kind);
>>> +
>>> +/* A deferred_diagnostic is a wrapper around optional extra
>>> diagnostics
>>> +   that we may want to bundle into a name_hint.
>>> +
>>> +   The emit method is called when no name_hint instances reference
>>> +   the deferred_diagnostic.  In the simple case this is when the
>>> name_hint
>>> +   goes out of scope, but a reference-counting scheme is used to
>>> allow
>>> +   name_hint instances to be copied.  */
>>> +
>>> +class deferred_diagnostic
>>> +{
>>> + public:
>>> +  virtual ~deferred_diagnostic () {}
>>> +  virtual void emit () = 0;
>>> +
>>> +  void incref () { m_refcnt++; }
>>> +  void decref ()
>>> +  {
>>> +if (--m_refcnt == 0)
>>> +  {
>>> +   if (!m_suppress)
>>> + emit ();
>>> +   delete this;
>>> +  }
>>> +  }
>>> +
>>> +  location_t get_location () const { return m_loc; }
>>> +
>>> +  /* Call this if the corresponding warning was not emitted,
>>> + in which case we should also not emit the
>>> deferred_diagnostic.  */
>>> +  void suppress ()
>>> +  {
>>> +m_suppress = true;
>>> +  }
>>> +
>>> + protected:
>>> +  deferred_diagnostic (location_t loc)
>>> +  : m_refcnt (0), m_loc (loc), m_suppress (false) {}
>>> +
>>> + private:
>>> +  int m_refcnt;
>>> +  location_t m_loc;
>>> +  bool m_suppress;
>>> +};
>> So what stands out here is "delete this" and the need for explicit
>> reference counting.  Also doesn't that imply that deferred_diagnostic
>> objects must be allocated on the heap?  Is there another way to get
>> the
>> behavior you want without resorting to something like this?
>>
> 
> Thanks for looking at this.
> 
> Yes: deferred_diagnostic instances are heap-allocated.  This is because
> it's an abstract base class; each concrete subclass is an
> implementation detail within the frontends, for isolating the special
> -case logic for each different kind of hint, and thus these concrete
> subclasses are hidden within the FE code.
> 
> My initial implementation of the above had the name_hint class directly
> "own" the deferred_diagnostic ptr, with a:
>   delete m_deferred;
> within 

Re: [PATCH 1/3] c-family: add name_hint/deferred_diagnostic

2017-07-10 Thread Trevor Saunders
On Mon, Jul 03, 2017 at 01:32:46PM -0400, David Malcolm wrote:
> On Mon, 2017-07-03 at 10:25 -0600, Jeff Law wrote:
> > On 05/05/2017 11:51 AM, David Malcolm wrote:
> > > In various places we use lookup_name_fuzzy to provide a hint,
> > > and can report messages of the form:
> > >   error: unknown foo named 'bar'
> > > or:
> > >   error: unknown foo named 'bar'; did you mean 'SUGGESTION?
> > > 
> > > This patch provides a way for lookup_name_fuzzy to provide
> > > both the suggestion above, and (optionally) additional hints
> > > that can be printed e.g.
> > > 
> > >   note: did you forget to include ?
> > > 
> > > This patch provides the mechanism and ports existing users
> > > of lookup_name_fuzzy to the new return type.
> > > There are no uses of such hints in this patch, but followup
> > > patches provide various front-end specific uses of this.
> > > 
> > > gcc/c-family/ChangeLog:
> > >   * c-common.h (class deferred_diagnostic): New class.
> > >   (class name_hint): New class.
> > >   (lookup_name_fuzzy): Convert return type from const char *
> > >   to name_hint.  Add location_t param.
> > > 
> > > gcc/c/ChangeLog:
> > >   * c-decl.c (implicit_decl_warning): Convert "hint" from
> > >   const char * to name_hint.  Pass location to
> > >   lookup_name_fuzzy.  Suppress any deferred diagnostic if the
> > >   warning was not printed.
> > >   (undeclared_variable): Likewise for "guessed_id".
> > >   (lookup_name_fuzzy): Convert return type from const char *
> > >   to name_hint.  Add location_t param.
> > >   * c-parser.c (c_parser_declaration_or_fndef): Convert "hint"
> > > from
> > >   const char * to name_hint.  Pass location to lookup_name_fuzzy.
> > >   (c_parser_parameter_declaration): Pass location to
> > >   lookup_name_fuzzy.
> > > 
> > > gcc/cp/ChangeLog:
> > >   * name-lookup.c (suggest_alternatives_for): Convert
> > > "fuzzy_name" from
> > >   const char * to name_hint, and rename to "hint".  Pass location
> > > to
> > >   lookup_name_fuzzy.
> > >   (lookup_name_fuzzy): Convert return type from const char *
> > >   to name_hint.  Add location_t param.
> > >   * parser.c (cp_parser_diagnose_invalid_type_name): Convert
> > >   "suggestion" from const char * to name_hint, and rename to
> > > "hint".
> > >   Pass location to lookup_name_fuzzy.
> > 
> > > ---
> > >  gcc/c-family/c-common.h | 121
> > > +++-
> > >  gcc/c/c-decl.c  |  35 +++---
> > >  gcc/c/c-parser.c|  16 ---
> > >  gcc/cp/name-lookup.c|  17 +++
> > >  gcc/cp/parser.c |  12 ++---
> > >  5 files changed, 163 insertions(+), 38 deletions(-)
> > > 
> > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > > index 138a0a6..83c1a68 100644
> > > --- a/gcc/c-family/c-common.h
> > > +++ b/gcc/c-family/c-common.h
> > > @@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind {
> > >/* Any name.  */
> > >FUZZY_LOOKUP_NAME
> > >  };
> > > -extern const char *lookup_name_fuzzy (tree, enum
> > > lookup_name_fuzzy_kind);
> > > +
> > > +/* A deferred_diagnostic is a wrapper around optional extra
> > > diagnostics
> > > +   that we may want to bundle into a name_hint.
> > > +
> > > +   The emit method is called when no name_hint instances reference
> > > +   the deferred_diagnostic.  In the simple case this is when the
> > > name_hint
> > > +   goes out of scope, but a reference-counting scheme is used to
> > > allow
> > > +   name_hint instances to be copied.  */
> > > +
> > > +class deferred_diagnostic
> > > +{
> > > + public:
> > > +  virtual ~deferred_diagnostic () {}
> > > +  virtual void emit () = 0;
> > > +
> > > +  void incref () { m_refcnt++; }
> > > +  void decref ()
> > > +  {
> > > +if (--m_refcnt == 0)
> > > +  {
> > > + if (!m_suppress)
> > > +   emit ();
> > > + delete this;
> > > +  }
> > > +  }
> > > +
> > > +  location_t get_location () const { return m_loc; }
> > > +
> > > +  /* Call this if the corresponding warning was not emitted,
> > > + in which case we should also not emit the
> > > deferred_diagnostic.  */
> > > +  void suppress ()
> > > +  {
> > > +m_suppress = true;
> > > +  }
> > > +
> > > + protected:
> > > +  deferred_diagnostic (location_t loc)
> > > +  : m_refcnt (0), m_loc (loc), m_suppress (false) {}
> > > +
> > > + private:
> > > +  int m_refcnt;
> > > +  location_t m_loc;
> > > +  bool m_suppress;
> > > +};
> > So what stands out here is "delete this" and the need for explicit
> > reference counting.  Also doesn't that imply that deferred_diagnostic
> > objects must be allocated on the heap?  Is there another way to get
> > the
> > behavior you want without resorting to something like this?
> > 
> 
> Thanks for looking at this.
> 
> Yes: deferred_diagnostic instances are heap-allocated.  This is because
> it's an abstract base class; each concrete subclass is an
> implementation detail within the frontends, for isolating the special
> -case logic for each different kind of hint, and thus 

Re: [PATCH 1/3] c-family: add name_hint/deferred_diagnostic

2017-07-03 Thread David Malcolm
On Mon, 2017-07-03 at 10:25 -0600, Jeff Law wrote:
> On 05/05/2017 11:51 AM, David Malcolm wrote:
> > In various places we use lookup_name_fuzzy to provide a hint,
> > and can report messages of the form:
> >   error: unknown foo named 'bar'
> > or:
> >   error: unknown foo named 'bar'; did you mean 'SUGGESTION?
> > 
> > This patch provides a way for lookup_name_fuzzy to provide
> > both the suggestion above, and (optionally) additional hints
> > that can be printed e.g.
> > 
> >   note: did you forget to include ?
> > 
> > This patch provides the mechanism and ports existing users
> > of lookup_name_fuzzy to the new return type.
> > There are no uses of such hints in this patch, but followup
> > patches provide various front-end specific uses of this.
> > 
> > gcc/c-family/ChangeLog:
> > * c-common.h (class deferred_diagnostic): New class.
> > (class name_hint): New class.
> > (lookup_name_fuzzy): Convert return type from const char *
> > to name_hint.  Add location_t param.
> > 
> > gcc/c/ChangeLog:
> > * c-decl.c (implicit_decl_warning): Convert "hint" from
> > const char * to name_hint.  Pass location to
> > lookup_name_fuzzy.  Suppress any deferred diagnostic if the
> > warning was not printed.
> > (undeclared_variable): Likewise for "guessed_id".
> > (lookup_name_fuzzy): Convert return type from const char *
> > to name_hint.  Add location_t param.
> > * c-parser.c (c_parser_declaration_or_fndef): Convert "hint"
> > from
> > const char * to name_hint.  Pass location to lookup_name_fuzzy.
> > (c_parser_parameter_declaration): Pass location to
> > lookup_name_fuzzy.
> > 
> > gcc/cp/ChangeLog:
> > * name-lookup.c (suggest_alternatives_for): Convert
> > "fuzzy_name" from
> > const char * to name_hint, and rename to "hint".  Pass location
> > to
> > lookup_name_fuzzy.
> > (lookup_name_fuzzy): Convert return type from const char *
> > to name_hint.  Add location_t param.
> > * parser.c (cp_parser_diagnose_invalid_type_name): Convert
> > "suggestion" from const char * to name_hint, and rename to
> > "hint".
> > Pass location to lookup_name_fuzzy.
> 
> > ---
> >  gcc/c-family/c-common.h | 121
> > +++-
> >  gcc/c/c-decl.c  |  35 +++---
> >  gcc/c/c-parser.c|  16 ---
> >  gcc/cp/name-lookup.c|  17 +++
> >  gcc/cp/parser.c |  12 ++---
> >  5 files changed, 163 insertions(+), 38 deletions(-)
> > 
> > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> > index 138a0a6..83c1a68 100644
> > --- a/gcc/c-family/c-common.h
> > +++ b/gcc/c-family/c-common.h
> > @@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind {
> >/* Any name.  */
> >FUZZY_LOOKUP_NAME
> >  };
> > -extern const char *lookup_name_fuzzy (tree, enum
> > lookup_name_fuzzy_kind);
> > +
> > +/* A deferred_diagnostic is a wrapper around optional extra
> > diagnostics
> > +   that we may want to bundle into a name_hint.
> > +
> > +   The emit method is called when no name_hint instances reference
> > +   the deferred_diagnostic.  In the simple case this is when the
> > name_hint
> > +   goes out of scope, but a reference-counting scheme is used to
> > allow
> > +   name_hint instances to be copied.  */
> > +
> > +class deferred_diagnostic
> > +{
> > + public:
> > +  virtual ~deferred_diagnostic () {}
> > +  virtual void emit () = 0;
> > +
> > +  void incref () { m_refcnt++; }
> > +  void decref ()
> > +  {
> > +if (--m_refcnt == 0)
> > +  {
> > +   if (!m_suppress)
> > + emit ();
> > +   delete this;
> > +  }
> > +  }
> > +
> > +  location_t get_location () const { return m_loc; }
> > +
> > +  /* Call this if the corresponding warning was not emitted,
> > + in which case we should also not emit the
> > deferred_diagnostic.  */
> > +  void suppress ()
> > +  {
> > +m_suppress = true;
> > +  }
> > +
> > + protected:
> > +  deferred_diagnostic (location_t loc)
> > +  : m_refcnt (0), m_loc (loc), m_suppress (false) {}
> > +
> > + private:
> > +  int m_refcnt;
> > +  location_t m_loc;
> > +  bool m_suppress;
> > +};
> So what stands out here is "delete this" and the need for explicit
> reference counting.  Also doesn't that imply that deferred_diagnostic
> objects must be allocated on the heap?  Is there another way to get
> the
> behavior you want without resorting to something like this?
> 

Thanks for looking at this.

Yes: deferred_diagnostic instances are heap-allocated.  This is because
it's an abstract base class; each concrete subclass is an
implementation detail within the frontends, for isolating the special
-case logic for each different kind of hint, and thus these concrete
subclasses are hidden within the FE code.

My initial implementation of the above had the name_hint class directly
"own" the deferred_diagnostic ptr, with a:
  delete m_deferred;
within name_hint's dtor.

This worked OK, until I encountered places in the C and 

Re: [PATCH 1/3] c-family: add name_hint/deferred_diagnostic

2017-07-03 Thread Jeff Law
On 05/05/2017 11:51 AM, David Malcolm wrote:
> In various places we use lookup_name_fuzzy to provide a hint,
> and can report messages of the form:
>   error: unknown foo named 'bar'
> or:
>   error: unknown foo named 'bar'; did you mean 'SUGGESTION?
> 
> This patch provides a way for lookup_name_fuzzy to provide
> both the suggestion above, and (optionally) additional hints
> that can be printed e.g.
> 
>   note: did you forget to include ?
> 
> This patch provides the mechanism and ports existing users
> of lookup_name_fuzzy to the new return type.
> There are no uses of such hints in this patch, but followup
> patches provide various front-end specific uses of this.
> 
> gcc/c-family/ChangeLog:
>   * c-common.h (class deferred_diagnostic): New class.
>   (class name_hint): New class.
>   (lookup_name_fuzzy): Convert return type from const char *
>   to name_hint.  Add location_t param.
> 
> gcc/c/ChangeLog:
>   * c-decl.c (implicit_decl_warning): Convert "hint" from
>   const char * to name_hint.  Pass location to
>   lookup_name_fuzzy.  Suppress any deferred diagnostic if the
>   warning was not printed.
>   (undeclared_variable): Likewise for "guessed_id".
>   (lookup_name_fuzzy): Convert return type from const char *
>   to name_hint.  Add location_t param.
>   * c-parser.c (c_parser_declaration_or_fndef): Convert "hint" from
>   const char * to name_hint.  Pass location to lookup_name_fuzzy.
>   (c_parser_parameter_declaration): Pass location to
>   lookup_name_fuzzy.
> 
> gcc/cp/ChangeLog:
>   * name-lookup.c (suggest_alternatives_for): Convert "fuzzy_name" from
>   const char * to name_hint, and rename to "hint".  Pass location to
>   lookup_name_fuzzy.
>   (lookup_name_fuzzy): Convert return type from const char *
>   to name_hint.  Add location_t param.
>   * parser.c (cp_parser_diagnose_invalid_type_name): Convert
>   "suggestion" from const char * to name_hint, and rename to "hint".
>   Pass location to lookup_name_fuzzy.

> ---
>  gcc/c-family/c-common.h | 121 
> +++-
>  gcc/c/c-decl.c  |  35 +++---
>  gcc/c/c-parser.c|  16 ---
>  gcc/cp/name-lookup.c|  17 +++
>  gcc/cp/parser.c |  12 ++---
>  5 files changed, 163 insertions(+), 38 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 138a0a6..83c1a68 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind {
>/* Any name.  */
>FUZZY_LOOKUP_NAME
>  };
> -extern const char *lookup_name_fuzzy (tree, enum lookup_name_fuzzy_kind);
> +
> +/* A deferred_diagnostic is a wrapper around optional extra diagnostics
> +   that we may want to bundle into a name_hint.
> +
> +   The emit method is called when no name_hint instances reference
> +   the deferred_diagnostic.  In the simple case this is when the name_hint
> +   goes out of scope, but a reference-counting scheme is used to allow
> +   name_hint instances to be copied.  */
> +
> +class deferred_diagnostic
> +{
> + public:
> +  virtual ~deferred_diagnostic () {}
> +  virtual void emit () = 0;
> +
> +  void incref () { m_refcnt++; }
> +  void decref ()
> +  {
> +if (--m_refcnt == 0)
> +  {
> + if (!m_suppress)
> +   emit ();
> + delete this;
> +  }
> +  }
> +
> +  location_t get_location () const { return m_loc; }
> +
> +  /* Call this if the corresponding warning was not emitted,
> + in which case we should also not emit the deferred_diagnostic.  */
> +  void suppress ()
> +  {
> +m_suppress = true;
> +  }
> +
> + protected:
> +  deferred_diagnostic (location_t loc)
> +  : m_refcnt (0), m_loc (loc), m_suppress (false) {}
> +
> + private:
> +  int m_refcnt;
> +  location_t m_loc;
> +  bool m_suppress;
> +};
So what stands out here is "delete this" and the need for explicit
reference counting.  Also doesn't that imply that deferred_diagnostic
objects must be allocated on the heap?  Is there another way to get the
behavior you want without resorting to something like this?

Or is your argument that deferred_diagnostic is only used from within
class name_hint and thus the concerns around heap vs stack, explicit
counting, etc are all buried inside the name_hint class?  If so, is
there any reasonable way to restrict the use of deferred_disagnostic to
within the name_hint class?

The rest of the changes seem non-controversial, so I think if we can
sort out the issues with those classes then this will be fine to move
forward.

jeff



[PING] Re: [PATCH 1/3] c-family: add name_hint/deferred_diagnostic

2017-05-26 Thread David Malcolm
I'd like to ping the following patches:

  [PATCH 1/3] c-family: add name_hint/deferred_diagnostic
https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00439.html

  [PATCH 2/3] C++: provide macro used-before-defined hint (PR c++/72786).
https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00437.html

  [PATCH 3/3] C: hints for missing stdlib includes for macros and types
https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00438.html

On Fri, 2017-05-05 at 13:51 -0400, David Malcolm wrote:
> In various places we use lookup_name_fuzzy to provide a hint,
> and can report messages of the form:
>   error: unknown foo named 'bar'
> or:
>   error: unknown foo named 'bar'; did you mean 'SUGGESTION?
> 
> This patch provides a way for lookup_name_fuzzy to provide
> both the suggestion above, and (optionally) additional hints
> that can be printed e.g.
> 
>   note: did you forget to include ?
> 
> This patch provides the mechanism and ports existing users
> of lookup_name_fuzzy to the new return type.
> There are no uses of such hints in this patch, but followup
> patches provide various front-end specific uses of this.
> 
> gcc/c-family/ChangeLog:
>   * c-common.h (class deferred_diagnostic): New class.
>   (class name_hint): New class.
>   (lookup_name_fuzzy): Convert return type from const char *
>   to name_hint.  Add location_t param.
> 
> gcc/c/ChangeLog:
>   * c-decl.c (implicit_decl_warning): Convert "hint" from
>   const char * to name_hint.  Pass location to
>   lookup_name_fuzzy.  Suppress any deferred diagnostic if the
>   warning was not printed.
>   (undeclared_variable): Likewise for "guessed_id".
>   (lookup_name_fuzzy): Convert return type from const char *
>   to name_hint.  Add location_t param.
>   * c-parser.c (c_parser_declaration_or_fndef): Convert "hint"
> from
>   const char * to name_hint.  Pass location to lookup_name_fuzzy.
>   (c_parser_parameter_declaration): Pass location to
>   lookup_name_fuzzy.
> 
> gcc/cp/ChangeLog:
>   * name-lookup.c (suggest_alternatives_for): Convert
> "fuzzy_name" from
>   const char * to name_hint, and rename to "hint".  Pass location
> to
>   lookup_name_fuzzy.
>   (lookup_name_fuzzy): Convert return type from const char *
>   to name_hint.  Add location_t param.
>   * parser.c (cp_parser_diagnose_invalid_type_name): Convert
>   "suggestion" from const char * to name_hint, and rename to
> "hint".
>   Pass location to lookup_name_fuzzy.
> ---
>  gcc/c-family/c-common.h | 121
> +++-
>  gcc/c/c-decl.c  |  35 +++---
>  gcc/c/c-parser.c|  16 ---
>  gcc/cp/name-lookup.c|  17 +++
>  gcc/cp/parser.c |  12 ++---
>  5 files changed, 163 insertions(+), 38 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 138a0a6..83c1a68 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind {
>/* Any name.  */
>FUZZY_LOOKUP_NAME
>  };
> -extern const char *lookup_name_fuzzy (tree, enum
> lookup_name_fuzzy_kind);
> +
> +/* A deferred_diagnostic is a wrapper around optional extra
> diagnostics
> +   that we may want to bundle into a name_hint.
> +
> +   The emit method is called when no name_hint instances reference
> +   the deferred_diagnostic.  In the simple case this is when the
> name_hint
> +   goes out of scope, but a reference-counting scheme is used to
> allow
> +   name_hint instances to be copied.  */
> +
> +class deferred_diagnostic
> +{
> + public:
> +  virtual ~deferred_diagnostic () {}
> +  virtual void emit () = 0;
> +
> +  void incref () { m_refcnt++; }
> +  void decref ()
> +  {
> +if (--m_refcnt == 0)
> +  {
> + if (!m_suppress)
> +   emit ();
> + delete this;
> +  }
> +  }
> +
> +  location_t get_location () const { return m_loc; }
> +
> +  /* Call this if the corresponding warning was not emitted,
> + in which case we should also not emit the deferred_diagnostic. 
>  */
> +  void suppress ()
> +  {
> +m_suppress = true;
> +  }
> +
> + protected:
> +  deferred_diagnostic (location_t loc)
> +  : m_refcnt (0), m_loc (loc), m_suppress (false) {}
> +
> + private:
> +  int m_refcnt;
> +  location_t m_loc;
> +  bool m_suppress;
> +};
> +
> +/* A name_hint is an optional string suggestion, along with an
> +   optional deferred_diagnostic.
> +   For example:
> +
> +   error: unknown foo named 'bar'
> +
> +   if the SU

[PATCH 1/3] c-family: add name_hint/deferred_diagnostic

2017-05-05 Thread David Malcolm
In various places we use lookup_name_fuzzy to provide a hint,
and can report messages of the form:
  error: unknown foo named 'bar'
or:
  error: unknown foo named 'bar'; did you mean 'SUGGESTION?

This patch provides a way for lookup_name_fuzzy to provide
both the suggestion above, and (optionally) additional hints
that can be printed e.g.

  note: did you forget to include ?

This patch provides the mechanism and ports existing users
of lookup_name_fuzzy to the new return type.
There are no uses of such hints in this patch, but followup
patches provide various front-end specific uses of this.

gcc/c-family/ChangeLog:
* c-common.h (class deferred_diagnostic): New class.
(class name_hint): New class.
(lookup_name_fuzzy): Convert return type from const char *
to name_hint.  Add location_t param.

gcc/c/ChangeLog:
* c-decl.c (implicit_decl_warning): Convert "hint" from
const char * to name_hint.  Pass location to
lookup_name_fuzzy.  Suppress any deferred diagnostic if the
warning was not printed.
(undeclared_variable): Likewise for "guessed_id".
(lookup_name_fuzzy): Convert return type from const char *
to name_hint.  Add location_t param.
* c-parser.c (c_parser_declaration_or_fndef): Convert "hint" from
const char * to name_hint.  Pass location to lookup_name_fuzzy.
(c_parser_parameter_declaration): Pass location to
lookup_name_fuzzy.

gcc/cp/ChangeLog:
* name-lookup.c (suggest_alternatives_for): Convert "fuzzy_name" from
const char * to name_hint, and rename to "hint".  Pass location to
lookup_name_fuzzy.
(lookup_name_fuzzy): Convert return type from const char *
to name_hint.  Add location_t param.
* parser.c (cp_parser_diagnose_invalid_type_name): Convert
"suggestion" from const char * to name_hint, and rename to "hint".
Pass location to lookup_name_fuzzy.
---
 gcc/c-family/c-common.h | 121 +++-
 gcc/c/c-decl.c  |  35 +++---
 gcc/c/c-parser.c|  16 ---
 gcc/cp/name-lookup.c|  17 +++
 gcc/cp/parser.c |  12 ++---
 5 files changed, 163 insertions(+), 38 deletions(-)

diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 138a0a6..83c1a68 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind {
   /* Any name.  */
   FUZZY_LOOKUP_NAME
 };
-extern const char *lookup_name_fuzzy (tree, enum lookup_name_fuzzy_kind);
+
+/* A deferred_diagnostic is a wrapper around optional extra diagnostics
+   that we may want to bundle into a name_hint.
+
+   The emit method is called when no name_hint instances reference
+   the deferred_diagnostic.  In the simple case this is when the name_hint
+   goes out of scope, but a reference-counting scheme is used to allow
+   name_hint instances to be copied.  */
+
+class deferred_diagnostic
+{
+ public:
+  virtual ~deferred_diagnostic () {}
+  virtual void emit () = 0;
+
+  void incref () { m_refcnt++; }
+  void decref ()
+  {
+if (--m_refcnt == 0)
+  {
+   if (!m_suppress)
+ emit ();
+   delete this;
+  }
+  }
+
+  location_t get_location () const { return m_loc; }
+
+  /* Call this if the corresponding warning was not emitted,
+ in which case we should also not emit the deferred_diagnostic.  */
+  void suppress ()
+  {
+m_suppress = true;
+  }
+
+ protected:
+  deferred_diagnostic (location_t loc)
+  : m_refcnt (0), m_loc (loc), m_suppress (false) {}
+
+ private:
+  int m_refcnt;
+  location_t m_loc;
+  bool m_suppress;
+};
+
+/* A name_hint is an optional string suggestion, along with an
+   optional deferred_diagnostic.
+   For example:
+
+   error: unknown foo named 'bar'
+
+   if the SUGGESTION is "baz", then one might print:
+
+   error: unknown foo named 'bar'; did you mean 'baz'?
+
+   and the deferred_diagnostic allows for additional (optional)
+   diagnostics e.g.:
+
+   note: did you check behind the couch?
+
+   The deferred_diagnostic is emitted when no name_hint instances reference
+   the deferred_diagnostic.  In the simple case this is when the name_hint
+   goes out of scope, but a reference-counting scheme is used to allow
+   name_hint instances to be copied.  */
+
+class name_hint
+{
+public:
+  name_hint () : m_suggestion (NULL), m_deferred (NULL) {}
+
+  name_hint (const char *suggestion, deferred_diagnostic *deferred)
+  : m_suggestion (suggestion), m_deferred (deferred)
+  {
+if (m_deferred)
+  m_deferred->incref ();
+  }
+
+  name_hint (const name_hint )
+  : m_suggestion (other.m_suggestion), m_deferred (other.m_deferred)
+  {
+if (m_deferred)
+  m_deferred->incref ();
+  }
+
+  name_hint& operator= (const name_hint )
+  {
+m_suggestion = other.m_suggestion;
+if (other.m_deferred)
+  other.m_deferred->incref ();
+if (m_deferred)
+