c++: duplicate alias templates with decltype [PR 99425]
This failure was ultimately from incorrect handling of alias templates, but required a specific set of occurrences to happen in the specialization hash table. This cleans up the specialization streaming to add alias instantiations at the same point as other instantiations. I also removed some unneeded global variables dealing with mapping of duplicate decl contexts. PR c++/99425 gcc/cp/ * cp-tree.h (map_context_from, map_context_to): Delete. (add_mergeable_specialization): Add is_alias parm. * pt.c (add_mergeable_specialization): Add is_alias parm, add them. * module.cc (map_context_from, map_context_to): Delete. (trees_in::decl_value): Add specializations later, adjust call. Drop useless alias lookup. Set duplicate fn parm context. (check_mergeable_decl): Drop context mapping. (trees_in::is_matching_decl): Likewise. (trees_in::read_function_def): Drop parameter context adjustment here. gcc/testsuite/ * g++.dg/modules/pr99425-1.h: New. * g++.dg/modules/pr99425-1_a.H: New. * g++.dg/modules/pr99425-1_b.H: New. * g++.dg/modules/pr99425-1_c.C: New. * g++.dg/modules/pr99425-2_a.X: New. * g++.dg/modules/pr99425-2_b.X: New. * g++.dg/template/pr99425.C: New.
This commit is contained in:
parent
150a829acc
commit
87e3c2ef68
@ -5444,10 +5444,6 @@ extern int comparing_specializations;
|
||||
FIXME we should always do this except during deduction/ordering. */
|
||||
extern int comparing_dependent_aliases;
|
||||
|
||||
/* When comparing specializations permit context _FROM to match _TO. */
|
||||
extern tree map_context_from;
|
||||
extern tree map_context_to;
|
||||
|
||||
/* In parser.c. */
|
||||
|
||||
/* Nonzero if we are parsing an unevaluated operand: an operand to
|
||||
@ -7241,7 +7237,8 @@ extern void walk_specializations (bool,
|
||||
void *);
|
||||
extern tree match_mergeable_specialization (bool is_decl, spec_entry *);
|
||||
extern unsigned get_mergeable_specialization_flags (tree tmpl, tree spec);
|
||||
extern void add_mergeable_specialization (bool is_decl, spec_entry *,
|
||||
extern void add_mergeable_specialization (bool is_decl, bool is_alias,
|
||||
spec_entry *,
|
||||
tree outer, unsigned);
|
||||
extern tree add_outermost_template_args (tree, tree);
|
||||
extern tree add_extra_args (tree, tree);
|
||||
|
||||
@ -279,11 +279,6 @@ static inline tree identifier (const cpp_hashnode *node)
|
||||
return HT_IDENT_TO_GCC_IDENT (HT_NODE (const_cast<cpp_hashnode *> (node)));
|
||||
}
|
||||
|
||||
/* During duplicate detection we need to tell some comparators that
|
||||
these are equivalent. */
|
||||
tree map_context_from;
|
||||
tree map_context_to;
|
||||
|
||||
/* Id for dumping module information. */
|
||||
int module_dump_id;
|
||||
|
||||
@ -8074,16 +8069,6 @@ trees_in::decl_value ()
|
||||
|
||||
if (spec.spec)
|
||||
set_constraints (decl, spec.spec);
|
||||
if (mk & MK_template_mask
|
||||
|| mk == MK_partial)
|
||||
{
|
||||
/* Add to specialization tables now that constraints etc are
|
||||
added. */
|
||||
bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
|
||||
|
||||
spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl;
|
||||
add_mergeable_specialization (!is_type, &spec, decl, spec_flags);
|
||||
}
|
||||
|
||||
if (TREE_CODE (decl) == INTEGER_CST && !TREE_OVERFLOW (decl))
|
||||
{
|
||||
@ -8111,28 +8096,25 @@ trees_in::decl_value ()
|
||||
/* Set the TEMPLATE_DECL's type. */
|
||||
TREE_TYPE (decl) = TREE_TYPE (inner);
|
||||
|
||||
if (mk & MK_template_mask
|
||||
|| mk == MK_partial)
|
||||
{
|
||||
/* Add to specialization tables now that constraints etc are
|
||||
added. */
|
||||
bool is_type = mk == MK_partial || !(mk & MK_tmpl_decl_mask);
|
||||
|
||||
spec.spec = is_type ? type : mk & MK_tmpl_tmpl_mask ? inner : decl;
|
||||
add_mergeable_specialization (!is_type,
|
||||
!is_type && mk & MK_tmpl_alias_mask,
|
||||
&spec, decl, spec_flags);
|
||||
}
|
||||
|
||||
if (NAMESPACE_SCOPE_P (decl)
|
||||
&& (mk == MK_named || mk == MK_unique
|
||||
|| mk == MK_enum || mk == MK_friend_spec)
|
||||
&& !(VAR_OR_FUNCTION_DECL_P (decl) && DECL_LOCAL_DECL_P (decl)))
|
||||
add_module_namespace_decl (CP_DECL_CONTEXT (decl), decl);
|
||||
|
||||
/* The late insertion of an alias here or an implicit member
|
||||
(next block), is ok, because we ensured that all imports were
|
||||
loaded up before we started this cluster. Thus an insertion
|
||||
from some other import cannot have happened between the
|
||||
merged insertion above and these insertions down here. */
|
||||
if (mk == MK_alias_spec)
|
||||
{
|
||||
/* Insert into type table. */
|
||||
tree ti = DECL_TEMPLATE_INFO (inner);
|
||||
spec_entry elt =
|
||||
{TI_TEMPLATE (ti), TI_ARGS (ti), TREE_TYPE (inner)};
|
||||
tree texist = match_mergeable_specialization (false, &elt);
|
||||
if (texist)
|
||||
set_overrun ();
|
||||
}
|
||||
|
||||
if (DECL_ARTIFICIAL (decl)
|
||||
&& TREE_CODE (decl) == FUNCTION_DECL
|
||||
&& !DECL_TEMPLATE_INFO (decl)
|
||||
@ -8176,6 +8158,14 @@ trees_in::decl_value ()
|
||||
if (!is_matching_decl (existing, decl, is_typedef))
|
||||
unmatched_duplicate (existing);
|
||||
|
||||
if (inner && TREE_CODE (inner) == FUNCTION_DECL)
|
||||
{
|
||||
tree e_inner = STRIP_TEMPLATE (existing);
|
||||
for (auto parm = DECL_ARGUMENTS (inner);
|
||||
parm; parm = DECL_CHAIN (parm))
|
||||
DECL_CONTEXT (parm) = e_inner;
|
||||
}
|
||||
|
||||
/* And our result is the existing node. */
|
||||
decl = existing;
|
||||
}
|
||||
@ -8186,7 +8176,7 @@ trees_in::decl_value ()
|
||||
if (!e)
|
||||
{
|
||||
spec.spec = inner;
|
||||
add_mergeable_specialization (true, &spec, decl, spec_flags);
|
||||
add_mergeable_specialization (true, false, &spec, decl, spec_flags);
|
||||
}
|
||||
else if (e != existing)
|
||||
set_overrun ();
|
||||
@ -10378,8 +10368,9 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
|
||||
{
|
||||
if (mk & MK_tmpl_alias_mask)
|
||||
/* It should be in both tables. */
|
||||
gcc_assert (match_mergeable_specialization (false, entry)
|
||||
== TREE_TYPE (existing));
|
||||
gcc_checking_assert
|
||||
(match_mergeable_specialization (false, entry)
|
||||
== TREE_TYPE (existing));
|
||||
else if (mk & MK_tmpl_tmpl_mask)
|
||||
existing = DECL_TI_TEMPLATE (existing);
|
||||
}
|
||||
@ -10392,7 +10383,7 @@ trees_out::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
|
||||
}
|
||||
|
||||
/* The walkabout should have found ourselves. */
|
||||
gcc_assert (existing == decl);
|
||||
gcc_checking_assert (existing == decl);
|
||||
}
|
||||
}
|
||||
else if (mk != MK_unique)
|
||||
@ -10622,8 +10613,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
|
||||
break;
|
||||
|
||||
case FUNCTION_DECL:
|
||||
map_context_from = d_inner;
|
||||
map_context_to = m_inner;
|
||||
if (tree m_type = TREE_TYPE (m_inner))
|
||||
if ((!key.ret
|
||||
|| same_type_p (key.ret, fndecl_declared_return_type (m_inner)))
|
||||
@ -10647,7 +10636,6 @@ check_mergeable_decl (merge_kind mk, tree decl, tree ovl, merge_key const &key)
|
||||
if (cp_tree_equal (key.constraints, m_reqs))
|
||||
found = match;
|
||||
}
|
||||
map_context_from = map_context_to = NULL_TREE;
|
||||
break;
|
||||
|
||||
case TYPE_DECL:
|
||||
@ -11022,12 +11010,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
|
||||
gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner));
|
||||
}
|
||||
|
||||
gcc_checking_assert (!map_context_from);
|
||||
/* This mapping requres the new decl on the lhs and the existing
|
||||
entity on the rhs of the comparitors below. */
|
||||
map_context_from = d_inner;
|
||||
map_context_to = e_inner;
|
||||
|
||||
if (TREE_CODE (d_inner) == FUNCTION_DECL)
|
||||
{
|
||||
tree e_ret = fndecl_declared_return_type (existing);
|
||||
@ -11104,7 +11086,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
|
||||
else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing)))
|
||||
{
|
||||
mismatch:
|
||||
map_context_from = map_context_to = NULL_TREE;
|
||||
if (DECL_IS_UNDECLARED_BUILTIN (existing))
|
||||
/* Just like duplicate_decls, presum the user knows what
|
||||
they're doing in overriding a builtin. */
|
||||
@ -11121,8 +11102,6 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
|
||||
}
|
||||
}
|
||||
|
||||
map_context_from = map_context_to = NULL_TREE;
|
||||
|
||||
if (DECL_IS_UNDECLARED_BUILTIN (existing)
|
||||
&& !DECL_IS_UNDECLARED_BUILTIN (decl))
|
||||
{
|
||||
@ -11463,10 +11442,6 @@ trees_in::read_function_def (tree decl, tree maybe_template)
|
||||
tree maybe_dup = odr_duplicate (maybe_template, DECL_SAVED_TREE (decl));
|
||||
bool installing = maybe_dup && !DECL_SAVED_TREE (decl);
|
||||
|
||||
if (maybe_dup)
|
||||
for (auto parm = DECL_ARGUMENTS (maybe_dup); parm; parm = DECL_CHAIN (parm))
|
||||
DECL_CONTEXT (parm) = decl;
|
||||
|
||||
if (int wtag = i ())
|
||||
{
|
||||
int tag = 1;
|
||||
@ -12881,10 +12856,11 @@ specialization_add (bool decl_p, spec_entry *entry, void *data_)
|
||||
|| DECL_CLASS_TEMPLATE_P (entry->tmpl));
|
||||
|
||||
/* Only alias templates can appear in both tables (and
|
||||
if they're in the type table they must also be in the decl table). */
|
||||
if they're in the type table they must also be in the decl
|
||||
table). */
|
||||
gcc_checking_assert
|
||||
(!match_mergeable_specialization (true, entry)
|
||||
== (decl_p || !DECL_ALIAS_TEMPLATE_P (entry->tmpl)));
|
||||
== !DECL_ALIAS_TEMPLATE_P (entry->tmpl));
|
||||
}
|
||||
else if (VAR_OR_FUNCTION_DECL_P (entry->spec))
|
||||
gcc_checking_assert (!DECL_LOCAL_DECL_P (entry->spec));
|
||||
|
||||
38
gcc/cp/pt.c
38
gcc/cp/pt.c
@ -30009,25 +30009,41 @@ get_mergeable_specialization_flags (tree tmpl, tree decl)
|
||||
get_mergeable_specialization_flags. */
|
||||
|
||||
void
|
||||
add_mergeable_specialization (bool decl_p, spec_entry *elt,
|
||||
add_mergeable_specialization (bool decl_p, bool alias_p, spec_entry *elt,
|
||||
tree decl, unsigned flags)
|
||||
{
|
||||
hash_table<spec_hasher> *specializations
|
||||
= decl_p ? decl_specializations : type_specializations;
|
||||
|
||||
hashval_t hash = spec_hasher::hash (elt);
|
||||
auto *slot = specializations->find_slot_with_hash (elt, hash, INSERT);
|
||||
|
||||
/* We don't distinguish different constrained partial type
|
||||
specializations, so there could be duplicates. Everything else
|
||||
must be new. */
|
||||
if (!(flags & 2 && *slot))
|
||||
if (decl_p)
|
||||
{
|
||||
gcc_checking_assert (!*slot);
|
||||
auto *slot = decl_specializations->find_slot_with_hash (elt, hash, INSERT);
|
||||
|
||||
gcc_checking_assert (!*slot);
|
||||
auto entry = ggc_alloc<spec_entry> ();
|
||||
*entry = *elt;
|
||||
*slot = entry;
|
||||
|
||||
if (alias_p)
|
||||
{
|
||||
elt->spec = TREE_TYPE (elt->spec);
|
||||
gcc_checking_assert (elt->spec);
|
||||
}
|
||||
}
|
||||
|
||||
if (!decl_p || alias_p)
|
||||
{
|
||||
auto *slot = type_specializations->find_slot_with_hash (elt, hash, INSERT);
|
||||
|
||||
/* We don't distinguish different constrained partial type
|
||||
specializations, so there could be duplicates. Everything else
|
||||
must be new. */
|
||||
if (!(flags & 2 && *slot))
|
||||
{
|
||||
gcc_checking_assert (!*slot);
|
||||
|
||||
auto entry = ggc_alloc<spec_entry> ();
|
||||
*entry = *elt;
|
||||
*slot = entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & 1)
|
||||
|
||||
11
gcc/testsuite/g++.dg/modules/pr99425-1.h
Normal file
11
gcc/testsuite/g++.dg/modules/pr99425-1.h
Normal file
@ -0,0 +1,11 @@
|
||||
template<typename T>
|
||||
struct make_signed
|
||||
{
|
||||
using type = int;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
using make_signed_t = typename make_signed<S>::type;
|
||||
|
||||
template<typename U>
|
||||
auto ssize (U &parm) -> make_signed_t<decltype(parm.call())>;
|
||||
4
gcc/testsuite/g++.dg/modules/pr99425-1_a.H
Normal file
4
gcc/testsuite/g++.dg/modules/pr99425-1_a.H
Normal file
@ -0,0 +1,4 @@
|
||||
// PR 99425 alias dependent specializations
|
||||
// { dg-additional-options {-fmodule-header} }
|
||||
// { dg-module-cmi {} }
|
||||
#include "pr99425-1.h"
|
||||
19
gcc/testsuite/g++.dg/modules/pr99425-1_b.H
Normal file
19
gcc/testsuite/g++.dg/modules/pr99425-1_b.H
Normal file
@ -0,0 +1,19 @@
|
||||
// { dg-additional-options {-fmodule-header -fdump-lang-module-alias} }
|
||||
// { dg-module-cmi {} }
|
||||
|
||||
#include "pr99425-1.h"
|
||||
|
||||
import "pr99425-1_a.H";
|
||||
|
||||
struct Cont
|
||||
{
|
||||
int call ();
|
||||
};
|
||||
|
||||
inline void widget (Cont parm)
|
||||
{
|
||||
ssize (parm);
|
||||
}
|
||||
|
||||
// { dg-final { scan-lang-dump {Read:-[0-9]*'s alias spec merge key \(new\) type_decl:'::make_signed_t'\n ... Read:-[0-9]*'s type spec merge key \(new\) type_decl:'::make_signed'\n Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
|
||||
|
||||
11
gcc/testsuite/g++.dg/modules/pr99425-1_c.C
Normal file
11
gcc/testsuite/g++.dg/modules/pr99425-1_c.C
Normal file
@ -0,0 +1,11 @@
|
||||
// { dg-additional-options {-fmodules-ts -fdump-lang-module-alias} }
|
||||
import "pr99425-1_a.H";
|
||||
import "pr99425-1_b.H";
|
||||
|
||||
void frob (Cont parm)
|
||||
{
|
||||
ssize (parm);
|
||||
}
|
||||
|
||||
// { dg-final { scan-lang-dump {Read:-1's named merge key \(new\) template_decl:'::template ssize'} module } }
|
||||
// { dg-final { scan-lang-dump {Read:-1's named merge key \(matched\) template_decl:'::template ssize'} module } }
|
||||
7
gcc/testsuite/g++.dg/modules/pr99425-2_a.X
Normal file
7
gcc/testsuite/g++.dg/modules/pr99425-2_a.X
Normal file
@ -0,0 +1,7 @@
|
||||
// PR 99425 template aliases can cause equivalences in the hash
|
||||
// tables, and for extra excitement be reordered on rehash.
|
||||
|
||||
// { dg-additional-options {-x c++-system-header stdexcept -fmodules-ts} }
|
||||
// { dg-prune-output {linker input file unused} }
|
||||
|
||||
No! DO NOT COMPILE;
|
||||
4
gcc/testsuite/g++.dg/modules/pr99425-2_b.X
Normal file
4
gcc/testsuite/g++.dg/modules/pr99425-2_b.X
Normal file
@ -0,0 +1,4 @@
|
||||
// { dg-additional-options {-x c++-system-header mutex -fmodules-ts} }
|
||||
// { dg-prune-output {linker input file unused} }
|
||||
|
||||
No! DO NOT COMPILE;
|
||||
45
gcc/testsuite/g++.dg/template/pr99425.C
Normal file
45
gcc/testsuite/g++.dg/template/pr99425.C
Normal file
@ -0,0 +1,45 @@
|
||||
// { dg-do compile { target c++20 } }
|
||||
// a potential fix for 99425 generated an ICE here.
|
||||
|
||||
template<typename _Tp>
|
||||
struct is_nothrow_destructible;
|
||||
|
||||
template<typename _Tp>
|
||||
struct common_reference;
|
||||
|
||||
template<typename _Tp>
|
||||
concept same_as
|
||||
= true;
|
||||
|
||||
template<typename _Sent, typename _Iter>
|
||||
concept sentinel_for
|
||||
= same_as<common_reference<_Sent>>
|
||||
&& is_nothrow_destructible<_Iter>::value;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __member_end
|
||||
= requires (_Tp& __t)
|
||||
{
|
||||
{ true }
|
||||
-> sentinel_for<decltype(__t)>;
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
concept __adl_end
|
||||
= requires (_Tp& __t)
|
||||
{
|
||||
{ true }
|
||||
-> sentinel_for<decltype(__t)>;
|
||||
};
|
||||
|
||||
template<typename _Tp>
|
||||
requires __member_end<_Tp> || __adl_end<_Tp>
|
||||
void
|
||||
Bar (_Tp&& __t)
|
||||
{
|
||||
}
|
||||
|
||||
void test03 ()
|
||||
{
|
||||
Bar (1); // { dg-error "no matching function" }
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user