c++: Incorrect type equivalence [PR 99496]

This bug was caused by not marking dependent template aliases
correctly -- these things look like typedefs, but are not
(necessarily) equivalent to the canonical type.  We need to record that.

	PR c++/99496
	gcc/cp/
	* module.cc (trees_out::decl_value): Adjust typedef streaming,
	indicate whether it is a dependent alias.
	(trees_in::decl_value): Likewise.  Set as dependent alias, if it
	is one.
	gcc/testsuite/
	* g++.dg/modules/pr99496_a.H: New.
	* g++.dg/modules/pr99496_b.C: New.
This commit is contained in:
Nathan Sidwell 2021-03-15 11:25:46 -07:00
parent 3c5b6d24e6
commit 7b900dca60
3 changed files with 68 additions and 16 deletions

View File

@ -7719,18 +7719,35 @@ trees_out::decl_value (tree decl, depset *dep)
}
}
bool is_typedef = (!type && inner
&& TREE_CODE (inner) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (inner)
&& TYPE_NAME (TREE_TYPE (inner)) == inner);
if (is_typedef)
bool is_typedef = false;
if (!type && inner && TREE_CODE (inner) == TYPE_DECL)
{
/* A typedef type. */
int type_tag = insert (TREE_TYPE (inner));
tree t = TREE_TYPE (inner);
unsigned tdef_flags = 0;
if (DECL_ORIGINAL_TYPE (inner)
&& TYPE_NAME (TREE_TYPE (inner)) == inner)
{
tdef_flags |= 1;
if (TYPE_STRUCTURAL_EQUALITY_P (t)
&& TYPE_DEPENDENT_P_VALID (t)
&& TYPE_DEPENDENT_P (t))
tdef_flags |= 2;
}
if (streaming_p ())
dump (dumper::TREE)
&& dump ("Cloned:%d typedef %C:%N", type_tag,
TREE_CODE (TREE_TYPE (inner)), TREE_TYPE (inner));
u (tdef_flags);
if (tdef_flags & 1)
{
/* A typedef type. */
int type_tag = insert (t);
if (streaming_p ())
dump (dumper::TREE)
&& dump ("Cloned:%d %s %C:%N", type_tag,
tdef_flags & 2 ? "depalias" : "typedef",
TREE_CODE (t), t);
is_typedef = true;
}
}
if (streaming_p () && DECL_MAYBE_IN_CHARGE_CDTOR_P (decl))
@ -7993,12 +8010,6 @@ trees_in::decl_value ()
dump (dumper::TREE) && dump ("Read:%d %C:%N", tag, TREE_CODE (decl), decl);
/* Regular typedefs will have a NULL TREE_TYPE at this point. */
bool is_typedef = (!type && inner
&& TREE_CODE (inner) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (inner)
&& !TREE_TYPE (inner));
existing = back_refs[~tag];
bool installed = install_entity (existing);
bool is_new = existing == decl;
@ -8030,6 +8041,16 @@ trees_in::decl_value ()
}
}
/* Regular typedefs will have a NULL TREE_TYPE at this point. */
unsigned tdef_flags = 0;
bool is_typedef = false;
if (!type && inner && TREE_CODE (inner) == TYPE_DECL)
{
tdef_flags = u ();
if (tdef_flags & 1)
is_typedef = true;
}
if (is_new)
{
/* A newly discovered node. */
@ -8076,6 +8097,14 @@ trees_in::decl_value ()
TREE_TYPE (inner) = DECL_ORIGINAL_TYPE (inner);
DECL_ORIGINAL_TYPE (inner) = NULL_TREE;
set_underlying_type (inner);
if (tdef_flags & 2)
{
/* Match instantiate_alias_template's handling. */
tree type = TREE_TYPE (inner);
TYPE_DEPENDENT_P (type) = true;
TYPE_DEPENDENT_P_VALID (type) = true;
SET_TYPE_STRUCTURAL_EQUALITY (type);
}
}
if (inner_tag)
@ -10661,6 +10690,9 @@ trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
spec.tmpl = tree_node ();
spec.args = tree_node ();
if (get_overrun ())
return error_mark_node;
DECL_NAME (decl) = DECL_NAME (spec.tmpl);
DECL_CONTEXT (decl) = DECL_CONTEXT (spec.tmpl);
DECL_NAME (inner) = DECL_NAME (decl);

View File

@ -0,0 +1,17 @@
// PR 99496 different types with same canonical
// (requires spec hasher to be a constant, so we get collisions)
// { dg-additional-options -fmodule-header }
// { dg-module-cmi {} }
template<typename...> using __void_t = void;
template<typename _Tp, typename = void>
struct __is_referenceable
{ };
template<typename _Tp>
struct __is_referenceable<_Tp, __void_t<_Tp&>>
{ };
template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_copy_constructible_impl;

View File

@ -0,0 +1,3 @@
// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
import "pr99496_a.H";