2017-10-16 22:50:40 +02:00
|
|
|
/* gnu::unique_ptr, a simple std::unique_ptr replacement for C++03.
|
|
|
|
|
2021-01-04 10:26:59 +01:00
|
|
|
Copyright (C) 2007-2021 Free Software Foundation, Inc.
|
2017-10-16 22:50:40 +02:00
|
|
|
|
|
|
|
This file is part of GCC.
|
|
|
|
|
|
|
|
This program 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 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
/* gnu::unique_ptr defines a C++ owning smart pointer that exposes a
|
|
|
|
subset of the std::unique_ptr API.
|
|
|
|
|
|
|
|
In fact, when compiled with a C++11 compiler, gnu::unique_ptr
|
|
|
|
actually _is_ std::unique_ptr. When compiled with a C++03 compiler
|
|
|
|
OTOH, it's an hand coded std::unique_ptr emulation that assumes
|
|
|
|
code is correct and doesn't try to be too smart.
|
|
|
|
|
|
|
|
This supports custom deleters, but not _stateful_ deleters, so you
|
|
|
|
can't use those in C++11 mode either. Only the managed pointer is
|
|
|
|
stored in the smart pointer. That could be changed; it simply
|
|
|
|
wasn't found necessary.
|
|
|
|
|
|
|
|
At the end of the file you'll find a gnu::unique_ptr partial
|
|
|
|
specialization that uses a custom (stateless) deleter:
|
|
|
|
gnu::unique_xmalloc_ptr. That is used to manage pointers to
|
|
|
|
objects allocated with xmalloc.
|
|
|
|
|
|
|
|
The C++03 version was originally based on GCC 7.0's std::auto_ptr
|
|
|
|
and then heavily customized to behave more like C++11's
|
|
|
|
std::unique_ptr, but at this point, it no longer shares much at all
|
|
|
|
with the original file. But, that's the history and the reason for
|
|
|
|
the copyright's starting year.
|
|
|
|
|
|
|
|
The C++03 version lets you shoot yourself in the foot, since
|
|
|
|
similarly to std::auto_ptr, the copy constructor and assignment
|
|
|
|
operators actually move. Also, in the name of simplicity, no
|
|
|
|
effort is spent on using SFINAE to prevent invalid conversions,
|
|
|
|
etc. This is not really a problem, because the goal here is to
|
|
|
|
allow code that would be correct using std::unique_ptr to be
|
|
|
|
equally correct in C++03 mode, and, just as efficient. If client
|
|
|
|
code compiles correctly with a C++11 (or newer) compiler, we know
|
|
|
|
we're not doing anything invalid by mistake.
|
|
|
|
|
|
|
|
Usage notes:
|
|
|
|
|
|
|
|
- Putting gnu::unique_ptr in standard containers is not supported,
|
|
|
|
since C++03 containers are not move-aware (and our emulation
|
|
|
|
relies on copy actually moving).
|
|
|
|
|
|
|
|
- Since there's no nullptr in C++03, gnu::unique_ptr allows
|
|
|
|
implicit initialization and assignment from NULL instead.
|
|
|
|
|
|
|
|
- To check whether there's an associated managed object, all these
|
|
|
|
work as expected:
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
if (!ptr)
|
|
|
|
if (ptr != NULL)
|
|
|
|
if (ptr == NULL)
|
|
|
|
if (NULL != ptr)
|
|
|
|
if (NULL == ptr)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef GNU_UNIQUE_PTR_H
|
|
|
|
#define GNU_UNIQUE_PTR_H 1
|
|
|
|
|
2017-10-23 22:25:58 +02:00
|
|
|
#if __cplusplus >= 201103
|
|
|
|
# include <memory>
|
|
|
|
#endif
|
2017-10-16 22:50:40 +02:00
|
|
|
|
|
|
|
namespace gnu
|
|
|
|
{
|
|
|
|
|
|
|
|
#if __cplusplus >= 201103
|
|
|
|
|
|
|
|
/* In C++11 mode, all we need is import the standard
|
|
|
|
std::unique_ptr. */
|
|
|
|
template<typename T> using unique_ptr = std::unique_ptr<T>;
|
|
|
|
|
|
|
|
/* Pull in move as well. */
|
|
|
|
using std::move;
|
|
|
|
|
|
|
|
#else /* C++11 */
|
|
|
|
|
|
|
|
/* Default destruction policy used by gnu::unique_ptr when no deleter
|
|
|
|
is specified. Uses delete. */
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct default_delete
|
|
|
|
{
|
|
|
|
void operator () (T *ptr) const { delete ptr; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Specialization for arrays. Uses delete[]. */
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct default_delete<T[]>
|
|
|
|
{
|
|
|
|
void operator () (T *ptr) const { delete [] ptr; }
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
/* Type used to support implicit construction from NULL:
|
|
|
|
|
|
|
|
gnu::unique_ptr<foo> func (....)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
and assignment from NULL:
|
|
|
|
|
|
|
|
gnu::unique_ptr<foo> ptr (....);
|
|
|
|
...
|
|
|
|
ptr = NULL;
|
|
|
|
|
|
|
|
It is intentionally not defined anywhere. */
|
|
|
|
struct nullptr_t;
|
|
|
|
|
|
|
|
/* Base class of our unique_ptr emulation. Contains code common to
|
|
|
|
both unique_ptr<T, D> and unique_ptr<T[], D>. */
|
|
|
|
|
|
|
|
template<typename T, typename D>
|
|
|
|
class unique_ptr_base
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef T *pointer;
|
|
|
|
typedef T element_type;
|
|
|
|
typedef D deleter_type;
|
|
|
|
|
|
|
|
/* Takes ownership of a pointer. P is a pointer to an object of
|
|
|
|
element_type type. Defaults to NULL. */
|
|
|
|
explicit unique_ptr_base (element_type *p = NULL) throw () : m_ptr (p) {}
|
|
|
|
|
|
|
|
/* The "move" constructor. Really a copy constructor that actually
|
|
|
|
moves. Even though std::unique_ptr is not copyable, our little
|
|
|
|
simpler emulation allows it, because:
|
|
|
|
|
|
|
|
- There are no rvalue references in C++03. Our move emulation
|
|
|
|
instead relies on copy/assignment moving, like std::auto_ptr.
|
|
|
|
- RVO/NRVO requires an accessible copy constructor
|
|
|
|
*/
|
|
|
|
unique_ptr_base (const unique_ptr_base &other) throw ()
|
|
|
|
: m_ptr (const_cast<unique_ptr_base &> (other).release ()) {}
|
|
|
|
|
|
|
|
/* Converting "move" constructor. Really an lvalue ref converting
|
|
|
|
constructor that actually moves. This allows constructs such as:
|
|
|
|
|
|
|
|
unique_ptr<Derived> func_returning_unique_ptr (.....);
|
|
|
|
...
|
|
|
|
unique_ptr<Base> ptr = func_returning_unique_ptr (.....);
|
|
|
|
*/
|
|
|
|
template<typename T1, typename D1>
|
|
|
|
unique_ptr_base (const unique_ptr_base<T1, D1> &other) throw ()
|
|
|
|
: m_ptr (const_cast<unique_ptr_base<T1, D1> &> (other).release ()) {}
|
|
|
|
|
|
|
|
/* The "move" assignment operator. Really an lvalue ref copy
|
|
|
|
assignment operator that actually moves. See comments above. */
|
|
|
|
unique_ptr_base &operator= (const unique_ptr_base &other) throw ()
|
|
|
|
{
|
|
|
|
reset (const_cast<unique_ptr_base &> (other).release ());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Converting "move" assignment. Really an lvalue ref converting
|
|
|
|
copy assignment operator that moves. See comments above. */
|
|
|
|
template<typename T1, typename D1>
|
|
|
|
unique_ptr_base &operator= (const unique_ptr_base<T1, D1> &other) throw ()
|
|
|
|
{
|
|
|
|
reset (const_cast<unique_ptr_base<T1, D1> &> (other).release ());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* std::unique_ptr does not allow assignment, except from nullptr.
|
|
|
|
nullptr doesn't exist in C++03, so we allow assignment from NULL
|
|
|
|
instead [ptr = NULL;].
|
|
|
|
*/
|
|
|
|
unique_ptr_base &operator= (detail::nullptr_t *) throw ()
|
|
|
|
{
|
|
|
|
reset ();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
~unique_ptr_base () { call_deleter (); }
|
|
|
|
|
|
|
|
/* "explicit operator bool ()" emulation using the safe bool
|
|
|
|
idiom. */
|
|
|
|
private:
|
|
|
|
typedef void (unique_ptr_base::*explicit_operator_bool) () const;
|
|
|
|
void this_type_does_not_support_comparisons () const {}
|
|
|
|
|
|
|
|
public:
|
|
|
|
operator explicit_operator_bool () const
|
|
|
|
{
|
|
|
|
return (m_ptr != NULL
|
|
|
|
? &unique_ptr_base::this_type_does_not_support_comparisons
|
|
|
|
: 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
element_type *get () const throw () { return m_ptr; }
|
|
|
|
|
|
|
|
element_type *release () throw ()
|
|
|
|
{
|
|
|
|
pointer tmp = m_ptr;
|
|
|
|
m_ptr = NULL;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset (element_type *p = NULL) throw ()
|
|
|
|
{
|
|
|
|
if (p != m_ptr)
|
|
|
|
{
|
|
|
|
call_deleter ();
|
|
|
|
m_ptr = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/* Call the deleter. Note we assume the deleter is "stateless". */
|
|
|
|
void call_deleter ()
|
|
|
|
{
|
|
|
|
D d;
|
|
|
|
|
|
|
|
d (m_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
element_type *m_ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
} /* namespace detail */
|
|
|
|
|
|
|
|
/* Macro used to create a unique_ptr_base "partial specialization" --
|
|
|
|
a subclass that uses a specific deleter. Basically this re-defines
|
|
|
|
the necessary constructors. This is necessary because C++03
|
|
|
|
doesn't support inheriting constructors with "using". While at it,
|
|
|
|
we inherit the assignment operator. TYPE is the name of the type
|
|
|
|
being defined. Assumes that 'base_type' is a typedef of the
|
|
|
|
baseclass TYPE is inheriting from. */
|
|
|
|
#define DEFINE_GNU_UNIQUE_PTR(TYPE) \
|
|
|
|
public: \
|
|
|
|
explicit TYPE (T *p = NULL) throw () \
|
|
|
|
: base_type (p) {} \
|
|
|
|
\
|
|
|
|
TYPE (const TYPE &other) throw () : base_type (other) {} \
|
|
|
|
\
|
|
|
|
TYPE (detail::nullptr_t *) throw () : base_type (NULL) {} \
|
|
|
|
\
|
|
|
|
template<typename T1, typename D1> \
|
|
|
|
TYPE (const detail::unique_ptr_base<T1, D1> &other) throw () \
|
|
|
|
: base_type (other) {} \
|
|
|
|
\
|
|
|
|
using base_type::operator=;
|
|
|
|
|
|
|
|
/* Define single-object gnu::unique_ptr. */
|
|
|
|
|
|
|
|
template <typename T, typename D = default_delete<T> >
|
|
|
|
class unique_ptr : public detail::unique_ptr_base<T, D>
|
|
|
|
{
|
|
|
|
typedef detail::unique_ptr_base<T, D> base_type;
|
|
|
|
|
|
|
|
DEFINE_GNU_UNIQUE_PTR (unique_ptr)
|
|
|
|
|
|
|
|
public:
|
|
|
|
/* Dereferencing. */
|
|
|
|
T &operator* () const throw () { return *this->get (); }
|
|
|
|
T *operator-> () const throw () { return this->get (); }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Define gnu::unique_ptr specialization for T[]. */
|
|
|
|
|
|
|
|
template <typename T, typename D>
|
|
|
|
class unique_ptr<T[], D> : public detail::unique_ptr_base<T, D>
|
|
|
|
{
|
|
|
|
typedef detail::unique_ptr_base<T, D> base_type;
|
|
|
|
|
|
|
|
DEFINE_GNU_UNIQUE_PTR (unique_ptr)
|
|
|
|
|
|
|
|
public:
|
|
|
|
/* Indexing operator. */
|
|
|
|
T &operator[] (size_t i) const { return this->get ()[i]; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Comparison operators. */
|
|
|
|
|
|
|
|
template <typename T, typename D,
|
|
|
|
typename U, typename E>
|
|
|
|
inline bool
|
|
|
|
operator== (const detail::unique_ptr_base<T, D> &x,
|
|
|
|
const detail::unique_ptr_base<U, E> &y)
|
|
|
|
{ return x.get() == y.get(); }
|
|
|
|
|
|
|
|
template <typename T, typename D,
|
|
|
|
typename U, typename E>
|
|
|
|
inline bool
|
|
|
|
operator!= (const detail::unique_ptr_base<T, D> &x,
|
|
|
|
const detail::unique_ptr_base<U, E> &y)
|
|
|
|
{ return x.get() != y.get(); }
|
|
|
|
|
|
|
|
template<typename T, typename D,
|
|
|
|
typename U, typename E>
|
|
|
|
inline bool
|
|
|
|
operator< (const detail::unique_ptr_base<T, D> &x,
|
|
|
|
const detail::unique_ptr_base<U, E> &y)
|
|
|
|
{ return x.get() < y.get (); }
|
|
|
|
|
|
|
|
template<typename T, typename D,
|
|
|
|
typename U, typename E>
|
|
|
|
inline bool
|
|
|
|
operator<= (const detail::unique_ptr_base<T, D> &x,
|
|
|
|
const detail::unique_ptr_base<U, E> &y)
|
|
|
|
{ return !(y < x); }
|
|
|
|
|
|
|
|
template<typename T, typename D,
|
|
|
|
typename U, typename E>
|
|
|
|
inline bool
|
|
|
|
operator> (const detail::unique_ptr_base<T, D> &x,
|
|
|
|
const detail::unique_ptr_base<U, E> &y)
|
|
|
|
{ return y < x; }
|
|
|
|
|
|
|
|
template<typename T, typename D,
|
|
|
|
typename U, typename E>
|
|
|
|
inline bool
|
|
|
|
operator>= (const detail::unique_ptr_base<T, D> &x,
|
|
|
|
const detail::unique_ptr_base<U, E> &y)
|
|
|
|
{ return !(x < y); }
|
|
|
|
|
|
|
|
/* std::move "emulation". This is as simple as it can be -- no
|
C++: simplify output from suggest_alternatives_for
In the C++ FE, after emitting various errors about unrecognized names,
the parser can call
suggest_alternatives_for
and/or
suggest_alternative_in_explicit_scope.
These can issue zero or more suggestions for the unrecognized name,
or various other "note" diagnostics suggesting how to fix the problem.
For example, currently g++ emits:
t.cc:12:3: error: 'gtk_widget_showall' was not declared in this scope
12 | gtk_widget_showall (w);
| ^~~~~~~~~~~~~~~~~~
t.cc:12:3: note: suggested alternative: 'gtk_widget_show_all'
12 | gtk_widget_showall (w);
| ^~~~~~~~~~~~~~~~~~
| gtk_widget_show_all
This patch consolidates the common case when there is a single
candidate, so that the error can issue a fix-it hint directly.
This simplifies the above to:
t.cc:12:3: error: 'gtk_widget_showall' was not declared in this scope;
did you mean 'gtk_widget_show_all'?
12 | gtk_widget_showall (w);
| ^~~~~~~~~~~~~~~~~~
| gtk_widget_show_all
omitting the second "note" diagnostic.
Doing so requires changing the above "suggest_" functions so that
rather than being called after "error" and emitting a note directly,
they are called before the "error", and return a name_hint, which
can contain a suggestion and/or a deferred diagnostic. The "single
candidate" case is handled via a suggestion, and the "multiple
candidates" case via a new subclass of deferred_diagnostic.
There was some complication due to the fact that we don't always have
enough location information to issue a fix-it hint. Specifically,
for the case in qualified_name_lookup_error, the location is that of
the name, but the location of the qualifier prefix isn't reliably
available. For some hints, e.g. spell-corrections, the replacement
is of the name, and for others, e.g. parent namespaces, it's for the
qualified name. The patch addresses this by splitting this case out
into a new "suggest_alternatives_in_other_namespaces" function, for
which fix-it hints aren't issued.
Another complication is that of emitting a note when
--param cxx-max-namespaces-for-diagnostic-help
is reached. The patch emulates the existing behavior by emitting
the note from a deferred_diagnostic. This potentially needs to
co-exist with another deferred_diagnostic, so it works as a decorator
around any other such deferred_diagnostic. Doing so requires slightly
extending class name_hint.
On adding test coverage for the various cases, I discovered that
after emitting a "FOO is not a namespace-name" error, we also emit
a "expected namespace-name before" error. The patch removes this
second error for the case where it's redundant, simplifying this case
from e.g.:
spellcheck-ns.C:10:24: error: 'inner_ms' is not a namespace-name
10 | using namespace outer::inner_ms;
| ^~~~~~~~
spellcheck-ns.C:10:24: note: suggested alternative: 'inner_ns'
10 | using namespace outer::inner_ms;
| ^~~~~~~~
| inner_ns
spellcheck-ns.C:10:32: error: expected namespace-name before ';' token
10 | using namespace outer::inner_ms;
| ^
to:
spellcheck-ns.C:10:24: error: 'inner_ms' is not a namespace-name;
did you mean 'inner_ns'?
10 | using namespace outer::inner_ms;
| ^~~~~~~~
| inner_ns
include/ChangeLog:
* unique-ptr.h (gnu::move): Generalize so it applies to all
lvalue references, rather than just to unique_ptr values.
gcc/c-family/ChangeLog:
* name-hint.h (name_hint::take_deferred): New member function.
gcc/c/ChangeLog:
* c-decl.c (implicit_decl_warning): Update "is there a suggestion"
logic for change to name_hint::operator bool.
(undeclared_variable): Likewise.
* c-parser.c (c_parser_declaration_or_fndef): Likewise.
(c_parser_parameter_declaration): Likewise.
gcc/cp/ChangeLog:
* cp-name-hint.h: New file.
* cp-tree.h (expr_to_string): New decl.
(suggest_alternatives_for): Move to cp-name-hint.h, changing
return type from bool to name_hint.
(suggest_alternative_in_explicit_scope): Likewise.
* error.c: Define INCLUDE_UNIQUE_PTR. Include "cp-name-hint.h".
(expr_to_string): Make non-static.
(qualified_name_lookup_error): For the non-"::" case, take
responsibity for issuing any suggestion from
suggest_alternative_in_explicit_scope, as it changes from
returning a bool to returning a name_hint. Replace fallback call
to suggest_alternatives_for to a call to
suggest_alternatives_in_other_namespaces, capturing the fact that
we don't have enough location information to issue a fix-it hint
for this case. Update the error to support emitting a fix-it hint
where appropriate. For the "::" case, take responsibility for
issuing any suggestion from suggest_alternatives_for, supporting
emitting a fix-it hint.
* lex.c: Define INCLUDE_UNIQUE_PTR. Include "gcc-rich-location.h"
and "cp-name-hint.h".
(unqualified_name_lookup_error): Take responsibility for issuing
any suggestion from suggest_alternatives_for, supporting emitting
a fix-it hint.
* name-lookup.c (class namespace_limit_reached): New subclass of
deferred_diagnostic.
(class show_candidate_location): Likewise.
(class suggest_alternatives): Likewise.
(class namespace_hints): New class.
(suggest_alternatives_for): Convert return type from bool to
name_hint, replacing all direct diagnostic emission by setting
suggestions on the return value, or creating deferred diagnostics.
Specifically, split out initial traversal of namespaces into
namespace_hints' ctor, and maybe_decorate_with_limit, and move the
rest of the implementation to
namespace_hints::convert_candidates_to_name_hint and
suggest_alternatives_for_1.
(namespace_hints::namespace_hints): New ctor, adapted from
suggest_alternatives_for's initial namespace traversal, storing
location and name, and converting locals "candidates", "limited"
and "limit" into members.
(namespace_hints::convert_candidates_to_name_hint): New member
function.
(namespace_hints::maybe_decorate_with_limit): New member function.
(suggest_alternatives_for_1): New function, based on second half
of old implementation of suggest_alternatives_for, converting from
immediate emission of suggestions to using name_hint.
(suggest_alternatives_in_other_namespaces): New function.
(maybe_suggest_missing_std_header): Convert from immediate
emission of suggestions to using name_hint, moving emission
implementation to...
(class missing_std_header): New subclass of deferred_diagnostic.
(maybe_suggest_missing_header): Convert return type from bool to
name_hint.
(suggest_alternative_in_explicit_scope): Convert from immediate
emission of suggestions to using name_hint.
* parser.c: Replace include of "c-family/name-hint.h" with
"cp-name-hint.h".
(cp_parser_diagnose_invalid_type_name): Update
"is there a suggestion" logic for change to
name_hint::operator bool. Take responsibility for emitting
fix-it hints from suggest_alternative_in_explicit_scope.
(cp_parser_namespace_name): Take responsibility for emitting
fix-it hints from suggest_alternative_in_explicit_scope. Don't
emit the "expected namespace-name" error if we've already emitted
an "is not a namespace-name" error.
gcc/testsuite/ChangeLog:
* c-c++-common/spellcheck-reserved.c: Update expected output for
C++ for merger of "did you mean" suggestions into the error
message.
* g++.dg/ext/builtin3.C: Update expected output for merger of "did
you mean" suggestion into the error.
* g++.dg/lookup/error1.C: Likewise.
* g++.dg/lookup/pr77549.C: Likewise.
* g++.dg/lookup/pr80913.C: Likewise.
* g++.dg/lookup/suggestions1.C: Likewise.
* g++.dg/lookup/suggestions2.C: New test.
* g++.dg/overload/koenig1.C: Update expected output as above.
* g++.dg/spellcheck-identifiers-2.C: Likewise.
* g++.dg/spellcheck-identifiers.C: Likewise.
* g++.dg/spellcheck-ns.C: New test.
* g++.dg/spellcheck-pr77829.C: Update expected output as above.
* g++.dg/spellcheck-pr78656.C: Likewise.
* g++.dg/spellcheck-pr79298.C: Likewise, adding
-fdiagnostics-show-caret to options.
* g++.dg/spellcheck-pr80177.C: Likewise.
* g++.dg/spellcheck-single-vs-multiple.C: New test.
* g++.dg/spellcheck-typenames.C: Update expected output as above.
* g++.dg/template/static10.C: Likewise.
* g++.old-deja/g++.mike/ns5.C: Likewise.
* g++.old-deja/g++.mike/ns7.C: Likewise.
* g++.old-deja/g++.ns/koenig5.C: Likewise.
* g++.old-deja/g++.other/lineno5.C: Likewise.
libstdc++-v3/ChangeLog:
* testsuite/17_intro/using_namespace_std_exp_neg.cc: Remove
"expected namespace-name before" error.
* testsuite/17_intro/using_namespace_std_tr1_neg.cc: Likewise.
From-SVN: r265610
2018-10-30 00:53:50 +01:00
|
|
|
attempt is made to emulate rvalue references. This relies on T
|
|
|
|
having move semantics like std::auto_ptr.
|
|
|
|
I.e., copy/assignment actually moves. */
|
2017-10-16 22:50:40 +02:00
|
|
|
|
C++: simplify output from suggest_alternatives_for
In the C++ FE, after emitting various errors about unrecognized names,
the parser can call
suggest_alternatives_for
and/or
suggest_alternative_in_explicit_scope.
These can issue zero or more suggestions for the unrecognized name,
or various other "note" diagnostics suggesting how to fix the problem.
For example, currently g++ emits:
t.cc:12:3: error: 'gtk_widget_showall' was not declared in this scope
12 | gtk_widget_showall (w);
| ^~~~~~~~~~~~~~~~~~
t.cc:12:3: note: suggested alternative: 'gtk_widget_show_all'
12 | gtk_widget_showall (w);
| ^~~~~~~~~~~~~~~~~~
| gtk_widget_show_all
This patch consolidates the common case when there is a single
candidate, so that the error can issue a fix-it hint directly.
This simplifies the above to:
t.cc:12:3: error: 'gtk_widget_showall' was not declared in this scope;
did you mean 'gtk_widget_show_all'?
12 | gtk_widget_showall (w);
| ^~~~~~~~~~~~~~~~~~
| gtk_widget_show_all
omitting the second "note" diagnostic.
Doing so requires changing the above "suggest_" functions so that
rather than being called after "error" and emitting a note directly,
they are called before the "error", and return a name_hint, which
can contain a suggestion and/or a deferred diagnostic. The "single
candidate" case is handled via a suggestion, and the "multiple
candidates" case via a new subclass of deferred_diagnostic.
There was some complication due to the fact that we don't always have
enough location information to issue a fix-it hint. Specifically,
for the case in qualified_name_lookup_error, the location is that of
the name, but the location of the qualifier prefix isn't reliably
available. For some hints, e.g. spell-corrections, the replacement
is of the name, and for others, e.g. parent namespaces, it's for the
qualified name. The patch addresses this by splitting this case out
into a new "suggest_alternatives_in_other_namespaces" function, for
which fix-it hints aren't issued.
Another complication is that of emitting a note when
--param cxx-max-namespaces-for-diagnostic-help
is reached. The patch emulates the existing behavior by emitting
the note from a deferred_diagnostic. This potentially needs to
co-exist with another deferred_diagnostic, so it works as a decorator
around any other such deferred_diagnostic. Doing so requires slightly
extending class name_hint.
On adding test coverage for the various cases, I discovered that
after emitting a "FOO is not a namespace-name" error, we also emit
a "expected namespace-name before" error. The patch removes this
second error for the case where it's redundant, simplifying this case
from e.g.:
spellcheck-ns.C:10:24: error: 'inner_ms' is not a namespace-name
10 | using namespace outer::inner_ms;
| ^~~~~~~~
spellcheck-ns.C:10:24: note: suggested alternative: 'inner_ns'
10 | using namespace outer::inner_ms;
| ^~~~~~~~
| inner_ns
spellcheck-ns.C:10:32: error: expected namespace-name before ';' token
10 | using namespace outer::inner_ms;
| ^
to:
spellcheck-ns.C:10:24: error: 'inner_ms' is not a namespace-name;
did you mean 'inner_ns'?
10 | using namespace outer::inner_ms;
| ^~~~~~~~
| inner_ns
include/ChangeLog:
* unique-ptr.h (gnu::move): Generalize so it applies to all
lvalue references, rather than just to unique_ptr values.
gcc/c-family/ChangeLog:
* name-hint.h (name_hint::take_deferred): New member function.
gcc/c/ChangeLog:
* c-decl.c (implicit_decl_warning): Update "is there a suggestion"
logic for change to name_hint::operator bool.
(undeclared_variable): Likewise.
* c-parser.c (c_parser_declaration_or_fndef): Likewise.
(c_parser_parameter_declaration): Likewise.
gcc/cp/ChangeLog:
* cp-name-hint.h: New file.
* cp-tree.h (expr_to_string): New decl.
(suggest_alternatives_for): Move to cp-name-hint.h, changing
return type from bool to name_hint.
(suggest_alternative_in_explicit_scope): Likewise.
* error.c: Define INCLUDE_UNIQUE_PTR. Include "cp-name-hint.h".
(expr_to_string): Make non-static.
(qualified_name_lookup_error): For the non-"::" case, take
responsibity for issuing any suggestion from
suggest_alternative_in_explicit_scope, as it changes from
returning a bool to returning a name_hint. Replace fallback call
to suggest_alternatives_for to a call to
suggest_alternatives_in_other_namespaces, capturing the fact that
we don't have enough location information to issue a fix-it hint
for this case. Update the error to support emitting a fix-it hint
where appropriate. For the "::" case, take responsibility for
issuing any suggestion from suggest_alternatives_for, supporting
emitting a fix-it hint.
* lex.c: Define INCLUDE_UNIQUE_PTR. Include "gcc-rich-location.h"
and "cp-name-hint.h".
(unqualified_name_lookup_error): Take responsibility for issuing
any suggestion from suggest_alternatives_for, supporting emitting
a fix-it hint.
* name-lookup.c (class namespace_limit_reached): New subclass of
deferred_diagnostic.
(class show_candidate_location): Likewise.
(class suggest_alternatives): Likewise.
(class namespace_hints): New class.
(suggest_alternatives_for): Convert return type from bool to
name_hint, replacing all direct diagnostic emission by setting
suggestions on the return value, or creating deferred diagnostics.
Specifically, split out initial traversal of namespaces into
namespace_hints' ctor, and maybe_decorate_with_limit, and move the
rest of the implementation to
namespace_hints::convert_candidates_to_name_hint and
suggest_alternatives_for_1.
(namespace_hints::namespace_hints): New ctor, adapted from
suggest_alternatives_for's initial namespace traversal, storing
location and name, and converting locals "candidates", "limited"
and "limit" into members.
(namespace_hints::convert_candidates_to_name_hint): New member
function.
(namespace_hints::maybe_decorate_with_limit): New member function.
(suggest_alternatives_for_1): New function, based on second half
of old implementation of suggest_alternatives_for, converting from
immediate emission of suggestions to using name_hint.
(suggest_alternatives_in_other_namespaces): New function.
(maybe_suggest_missing_std_header): Convert from immediate
emission of suggestions to using name_hint, moving emission
implementation to...
(class missing_std_header): New subclass of deferred_diagnostic.
(maybe_suggest_missing_header): Convert return type from bool to
name_hint.
(suggest_alternative_in_explicit_scope): Convert from immediate
emission of suggestions to using name_hint.
* parser.c: Replace include of "c-family/name-hint.h" with
"cp-name-hint.h".
(cp_parser_diagnose_invalid_type_name): Update
"is there a suggestion" logic for change to
name_hint::operator bool. Take responsibility for emitting
fix-it hints from suggest_alternative_in_explicit_scope.
(cp_parser_namespace_name): Take responsibility for emitting
fix-it hints from suggest_alternative_in_explicit_scope. Don't
emit the "expected namespace-name" error if we've already emitted
an "is not a namespace-name" error.
gcc/testsuite/ChangeLog:
* c-c++-common/spellcheck-reserved.c: Update expected output for
C++ for merger of "did you mean" suggestions into the error
message.
* g++.dg/ext/builtin3.C: Update expected output for merger of "did
you mean" suggestion into the error.
* g++.dg/lookup/error1.C: Likewise.
* g++.dg/lookup/pr77549.C: Likewise.
* g++.dg/lookup/pr80913.C: Likewise.
* g++.dg/lookup/suggestions1.C: Likewise.
* g++.dg/lookup/suggestions2.C: New test.
* g++.dg/overload/koenig1.C: Update expected output as above.
* g++.dg/spellcheck-identifiers-2.C: Likewise.
* g++.dg/spellcheck-identifiers.C: Likewise.
* g++.dg/spellcheck-ns.C: New test.
* g++.dg/spellcheck-pr77829.C: Update expected output as above.
* g++.dg/spellcheck-pr78656.C: Likewise.
* g++.dg/spellcheck-pr79298.C: Likewise, adding
-fdiagnostics-show-caret to options.
* g++.dg/spellcheck-pr80177.C: Likewise.
* g++.dg/spellcheck-single-vs-multiple.C: New test.
* g++.dg/spellcheck-typenames.C: Update expected output as above.
* g++.dg/template/static10.C: Likewise.
* g++.old-deja/g++.mike/ns5.C: Likewise.
* g++.old-deja/g++.mike/ns7.C: Likewise.
* g++.old-deja/g++.ns/koenig5.C: Likewise.
* g++.old-deja/g++.other/lineno5.C: Likewise.
libstdc++-v3/ChangeLog:
* testsuite/17_intro/using_namespace_std_exp_neg.cc: Remove
"expected namespace-name before" error.
* testsuite/17_intro/using_namespace_std_tr1_neg.cc: Likewise.
From-SVN: r265610
2018-10-30 00:53:50 +01:00
|
|
|
template<typename T>
|
|
|
|
const T&
|
|
|
|
move (T& v)
|
2017-10-16 22:50:40 +02:00
|
|
|
{
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* C++11 */
|
|
|
|
|
|
|
|
/* Define gnu::unique_xmalloc_ptr, a gnu::unique_ptr that manages
|
|
|
|
xmalloc'ed memory. */
|
|
|
|
|
|
|
|
/* The deleter for gnu::unique_xmalloc_ptr. Uses free. */
|
|
|
|
template <typename T>
|
|
|
|
struct xmalloc_deleter
|
|
|
|
{
|
|
|
|
void operator() (T *ptr) const { free (ptr); }
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Same, for arrays. */
|
|
|
|
template <typename T>
|
|
|
|
struct xmalloc_deleter<T[]>
|
|
|
|
{
|
|
|
|
void operator() (T *ptr) const { free (ptr); }
|
|
|
|
};
|
|
|
|
|
|
|
|
#if __cplusplus >= 201103
|
|
|
|
|
|
|
|
/* In C++11, we just import the standard unique_ptr to our namespace
|
|
|
|
with a custom deleter. */
|
|
|
|
|
|
|
|
template<typename T> using unique_xmalloc_ptr
|
|
|
|
= std::unique_ptr<T, xmalloc_deleter<T>>;
|
|
|
|
|
|
|
|
#else /* C++11 */
|
|
|
|
|
|
|
|
/* In C++03, we don't have template aliases, so we need to define a
|
|
|
|
subclass instead, and re-define the constructors, because C++03
|
|
|
|
doesn't support inheriting constructors either. */
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class unique_xmalloc_ptr : public unique_ptr<T, xmalloc_deleter<T> >
|
|
|
|
{
|
|
|
|
typedef unique_ptr<T, xmalloc_deleter<T> > base_type;
|
|
|
|
|
|
|
|
DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Define gnu::unique_xmalloc_ptr specialization for T[]. */
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class unique_xmalloc_ptr<T[]> : public unique_ptr<T[], xmalloc_deleter<T[]> >
|
|
|
|
{
|
|
|
|
typedef unique_ptr<T[], xmalloc_deleter<T[]> > base_type;
|
|
|
|
|
|
|
|
DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* C++11 */
|
|
|
|
|
|
|
|
} /* namespace gnu */
|
|
|
|
|
|
|
|
#endif /* GNU_UNIQUE_PTR_H */
|