c++: lambda mangling alias issues [PR107897]
In 107897, by the time we are looking at the mangling clash, the alias has already been removed from the symbol table by analyze_functions, so we can't look at n->cpp_implicit_alias. So just assume that it's an alias if it's internal. In 108887 the problem is that removing the mangling alias from the symbol table confuses analyze_functions, because it ended up as first_analyzed somehow, so it becomes a dangling pointer. So instead we call reset() to neutralize the alias. To make this work for variables, I needed to move reset() from cgraph_node to symtab_node. PR c++/107897 PR c++/108887 gcc/ChangeLog: * cgraph.h: Move reset() from cgraph_node to symtab_node. * cgraphunit.cc (symtab_node::reset): Adjust. Also call remove_from_same_comdat_group. gcc/cp/ChangeLog: * decl2.cc (record_mangling): Use symtab_node::reset. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-lambda3.C: Use -flto if supported. * g++.dg/cpp0x/lambda/lambda-mangle7.C: New test.
This commit is contained in:
parent
04b0a7b1a6
commit
a23b33a1bd
5 changed files with 108 additions and 25 deletions
11
gcc/cgraph.h
11
gcc/cgraph.h
|
@ -152,6 +152,9 @@ public:
|
|||
/* Remove symbol from symbol table. */
|
||||
void remove (void);
|
||||
|
||||
/* Undo any definition or use of the symbol. */
|
||||
void reset (void);
|
||||
|
||||
/* Dump symtab node to F. */
|
||||
void dump (FILE *f);
|
||||
|
||||
|
@ -1066,14 +1069,6 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
|
|||
/* Expand function specified by node. */
|
||||
void expand (void);
|
||||
|
||||
/* As an GCC extension we allow redefinition of the function. The
|
||||
semantics when both copies of bodies differ is not well defined.
|
||||
We replace the old body with new body so in unit at a time mode
|
||||
we always use new body, while in normal mode we may end up with
|
||||
old body inlined into some functions and new body expanded and
|
||||
inlined in others. */
|
||||
void reset (void);
|
||||
|
||||
/* Creates a wrapper from cgraph_node to TARGET node. Thunk is used for this
|
||||
kind of wrapper method. */
|
||||
void create_wrapper (cgraph_node *target);
|
||||
|
|
|
@ -378,21 +378,15 @@ symbol_table::process_new_functions (void)
|
|||
inlined in others.
|
||||
|
||||
??? It may make more sense to use one body for inlining and other
|
||||
body for expanding the function but this is difficult to do. */
|
||||
body for expanding the function but this is difficult to do.
|
||||
|
||||
This is also used to cancel C++ mangling aliases, which can be for
|
||||
functions or variables. */
|
||||
|
||||
void
|
||||
cgraph_node::reset (void)
|
||||
symtab_node::reset (void)
|
||||
{
|
||||
/* If process is set, then we have already begun whole-unit analysis.
|
||||
This is *not* testing for whether we've already emitted the function.
|
||||
That case can be sort-of legitimately seen with real function redefinition
|
||||
errors. I would argue that the front end should never present us with
|
||||
such a case, but don't enforce that for now. */
|
||||
gcc_assert (!process);
|
||||
|
||||
/* Reset our data structures so we can analyze the function again. */
|
||||
inlined_to = NULL;
|
||||
memset (&rtl, 0, sizeof (rtl));
|
||||
analyzed = false;
|
||||
definition = false;
|
||||
alias = false;
|
||||
|
@ -400,8 +394,22 @@ cgraph_node::reset (void)
|
|||
weakref = false;
|
||||
cpp_implicit_alias = false;
|
||||
|
||||
remove_callees ();
|
||||
remove_all_references ();
|
||||
remove_from_same_comdat_group ();
|
||||
|
||||
if (cgraph_node *cn = dyn_cast <cgraph_node *> (this))
|
||||
{
|
||||
/* If process is set, then we have already begun whole-unit analysis.
|
||||
This is *not* testing for whether we've already emitted the function.
|
||||
That case can be sort-of legitimately seen with real function
|
||||
redefinition errors. I would argue that the front end should never
|
||||
present us with such a case, but don't enforce that for now. */
|
||||
gcc_assert (!cn->process);
|
||||
|
||||
memset (&cn->rtl, 0, sizeof (cn->rtl));
|
||||
cn->inlined_to = NULL;
|
||||
cn->remove_callees ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true when there are references to the node. INCLUDE_SELF is
|
||||
|
|
|
@ -4742,15 +4742,24 @@ record_mangling (tree decl, bool need_warning)
|
|||
= mangled_decls->find_slot_with_hash (id, IDENTIFIER_HASH_VALUE (id),
|
||||
INSERT);
|
||||
|
||||
/* If this is already an alias, remove the alias, because the real
|
||||
/* If this is already an alias, cancel the alias, because the real
|
||||
decl takes precedence. */
|
||||
if (*slot && DECL_ARTIFICIAL (*slot) && DECL_IGNORED_P (*slot))
|
||||
if (symtab_node *n = symtab_node::get (*slot))
|
||||
if (n->cpp_implicit_alias)
|
||||
{
|
||||
if (symtab_node *n = symtab_node::get (*slot))
|
||||
{
|
||||
n->remove ();
|
||||
*slot = NULL_TREE;
|
||||
if (n->cpp_implicit_alias)
|
||||
/* Actually removing the node isn't safe if other code is already
|
||||
holding a pointer to it, so just neutralize it. */
|
||||
n->reset ();
|
||||
}
|
||||
else
|
||||
/* analyze_functions might have already removed the alias from the
|
||||
symbol table if it's internal. */
|
||||
gcc_checking_assert (!TREE_PUBLIC (*slot));
|
||||
|
||||
*slot = NULL_TREE;
|
||||
}
|
||||
|
||||
if (!*slot)
|
||||
*slot = decl;
|
||||
|
|
70
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle7.C
Normal file
70
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle7.C
Normal file
|
@ -0,0 +1,70 @@
|
|||
// PR c++/108887
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
template <int __v> struct integral_constant {
|
||||
static constexpr int value = __v;
|
||||
};
|
||||
using false_type = integral_constant<false>;
|
||||
template <bool, bool, typename...> struct __result_of_impl;
|
||||
template <typename _Functor, typename... _ArgTypes>
|
||||
struct __result_of_impl<false, false, _Functor, _ArgTypes...> {
|
||||
typedef decltype(0) type;
|
||||
};
|
||||
template <typename... _ArgTypes>
|
||||
struct __invoke_result
|
||||
: __result_of_impl<false_type::value, false_type::value, _ArgTypes...> {};
|
||||
template <typename, typename _Fn, typename... _Args>
|
||||
void __invoke_impl(_Fn __f, _Args... __args) {
|
||||
__f(__args...);
|
||||
}
|
||||
template <typename, typename _Callable, typename... _Args>
|
||||
void __invoke_r(_Callable __fn, _Args... __args) {
|
||||
using __result = __invoke_result<_Args...>;
|
||||
using __type = typename __result::type;
|
||||
__invoke_impl<__type>(__fn, __args...);
|
||||
}
|
||||
struct QString {
|
||||
QString(const char *);
|
||||
};
|
||||
template <typename> class function;
|
||||
template <typename _Functor> struct _Base_manager {
|
||||
static _Functor _M_get_pointer(int) { __builtin_abort (); }
|
||||
};
|
||||
template <typename, typename> class _Function_handler;
|
||||
template <typename _Res, typename _Functor, typename... _ArgTypes>
|
||||
struct _Function_handler<_Res(_ArgTypes...), _Functor> {
|
||||
using _Base = _Base_manager<_Functor>;
|
||||
static _Res _M_invoke(const int &__functor, _ArgTypes &&...__args) {
|
||||
auto __trans_tmp_1 = _Base::_M_get_pointer(__functor);
|
||||
__invoke_r<_Res>(__trans_tmp_1, __args...);
|
||||
}
|
||||
};
|
||||
template <typename _Res, typename... _ArgTypes>
|
||||
struct function<_Res(_ArgTypes...)> {
|
||||
template <typename _Functor>
|
||||
using _Handler = _Function_handler<_Res(_ArgTypes...), _Functor>;
|
||||
template <typename _Functor> function(_Functor) {
|
||||
using _My_handler = _Handler<_Functor>;
|
||||
_M_invoker = _My_handler::_M_invoke;
|
||||
}
|
||||
using _Invoker_type = _Res (*)(const int &, _ArgTypes &&...);
|
||||
_Invoker_type _M_invoker;
|
||||
};
|
||||
struct QRegularExpression {
|
||||
QRegularExpression(QString);
|
||||
};
|
||||
struct AbstractAccount {
|
||||
void get(function<void(AbstractAccount *)>,
|
||||
function<void(AbstractAccount *)>);
|
||||
};
|
||||
struct AbstractTimelineModel {
|
||||
AbstractAccount m_account;
|
||||
};
|
||||
struct LinkPaginationTimelineModel : AbstractTimelineModel {
|
||||
void fillTimeline();
|
||||
};
|
||||
void LinkPaginationTimelineModel::fillTimeline() {
|
||||
[] {};
|
||||
m_account.get([](AbstractAccount *) { static QRegularExpression re(""); },
|
||||
[](AbstractAccount *) {});
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// { dg-do run { target c++20 } }
|
||||
// { dg-do compile { target c++17_down } }
|
||||
// { dg-excess-errors "" { target { c++17_down } } } (PR108972)
|
||||
// { dg-additional-options "-flto" { target lto } } (PR107897)
|
||||
|
||||
template<typename T>
|
||||
concept C1 = __is_same_as(T, int)
|
||||
|
|
Loading…
Add table
Reference in a new issue