Commit 02c7dd78 by Nathan Sidwell Committed by Nathan Sidwell

[PR c++/59930] template friend injection

https://gcc.gnu.org/ml/gcc-patches/2017-12/msg01168.html
	PR c++/59930
	* name-lookup.c (name_lookup::search_unqualified): Don't search
	parent namespace when looking for hidden things.
	* pt.c (tsubst_friend_class): Always push to friend scope, drop
	unneeded self-friend check. Inject new hidden friend into correct
	scope.

	PR c++/59930
	* g++.dg/parse/pr81247-c.C: Adjust.
	* g++.dg/template/pr59930-[123].C: New.

From-SVN: r255780
parent 0cf0bc67
2017-12-18 Nathan Sidwell <nathan@acm.org>
PR c++/59930
* name-lookup.c (name_lookup::search_unqualified): Don't search
parent namespace when looking for hidden things.
* pt.c (tsubst_friend_class): Always push to friend scope, drop
unneeded self-friend check. Inject new hidden friend into correct
scope.
2017-12-15 Jakub Jelinek <jakub@redhat.com>
PR c++/83205
......
......@@ -711,6 +711,15 @@ name_lookup::search_unqualified (tree scope, cp_binding_level *level)
done:;
if (scope == global_namespace)
break;
/* If looking for hidden names, we only look in the innermost
namespace scope. [namespace.memdef]/3 If a friend
declaration in a non-local class first declares a class,
function, class template or function template the friend is a
member of the innermost enclosing namespace. See also
[basic.lookup.unqual]/7 */
if (flags & LOOKUP_HIDDEN)
break;
}
vec_safe_truncate (queue, length);
......
......@@ -10005,57 +10005,23 @@ tsubst_friend_function (tree decl, tree args)
static tree
tsubst_friend_class (tree friend_tmpl, tree args)
{
tree friend_type;
tree tmpl;
tree context;
if (DECL_TEMPLATE_TEMPLATE_PARM_P (friend_tmpl))
{
tree t = tsubst (TREE_TYPE (friend_tmpl), args, tf_none, NULL_TREE);
return TREE_TYPE (t);
}
context = CP_DECL_CONTEXT (friend_tmpl);
if (context != global_namespace)
{
if (TREE_CODE (context) == NAMESPACE_DECL)
push_nested_namespace (context);
else
push_nested_class (tsubst (context, args, tf_none, NULL_TREE));
tmpl = tsubst (TREE_TYPE (friend_tmpl), args, tf_none, NULL_TREE);
return TREE_TYPE (tmpl);
}
/* Look for a class template declaration. We look for hidden names
because two friend declarations of the same template are the
same. For example, in:
struct A {
template <typename> friend class F;
};
template <typename> struct B {
template <typename> friend class F;
};
both F templates are the same. */
tmpl = lookup_name_real (DECL_NAME (friend_tmpl), 0, 0,
/*block_p=*/true, 0, LOOKUP_HIDDEN);
/* But, if we don't find one, it might be because we're in a
situation like this:
template <class T>
struct S {
template <class U>
friend struct S;
};
tree context = CP_DECL_CONTEXT (friend_tmpl);
if (TREE_CODE (context) == NAMESPACE_DECL)
push_nested_namespace (context);
else
push_nested_class (context);
Here, in the scope of (say) S<int>, `S' is bound to a TYPE_DECL
for `S<int>', not the TEMPLATE_DECL. */
if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl))
{
tmpl = lookup_name_prefer_type (DECL_NAME (friend_tmpl), 1);
tmpl = maybe_get_template_decl_from_type_decl (tmpl);
}
tmpl = lookup_name_real (DECL_NAME (friend_tmpl), /*prefer_type=*/false,
/*non_class=*/false, /*block_p=*/false,
/*namespaces_only=*/false, LOOKUP_HIDDEN);
if (tmpl && DECL_CLASS_TEMPLATE_P (tmpl))
{
......@@ -10068,53 +10034,50 @@ tsubst_friend_class (tree friend_tmpl, tree args)
if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (friend_tmpl))
> TMPL_ARGS_DEPTH (args))
{
tree parms;
location_t saved_input_location;
parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl),
args, tf_warning_or_error);
saved_input_location = input_location;
tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl),
args, tf_warning_or_error);
location_t saved_input_location = input_location;
input_location = DECL_SOURCE_LOCATION (friend_tmpl);
tree cons = get_constraints (tmpl);
redeclare_class_template (TREE_TYPE (tmpl), parms, cons);
input_location = saved_input_location;
}
friend_type = TREE_TYPE (tmpl);
}
else
{
/* The friend template has not already been declared. In this
case, the instantiation of the template class will cause the
injection of this template into the global scope. */
injection of this template into the namespace scope. */
tmpl = tsubst (friend_tmpl, args, tf_warning_or_error, NULL_TREE);
if (tmpl == error_mark_node)
return error_mark_node;
/* The new TMPL is not an instantiation of anything, so we
forget its origins. We don't reset CLASSTYPE_TI_TEMPLATE for
the new type because that is supposed to be the corresponding
template decl, i.e., TMPL. */
DECL_USE_TEMPLATE (tmpl) = 0;
DECL_TEMPLATE_INFO (tmpl) = NULL_TREE;
CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0;
CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))
= INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)));
if (tmpl != error_mark_node)
{
/* The new TMPL is not an instantiation of anything, so we
forget its origins. We don't reset CLASSTYPE_TI_TEMPLATE
for the new type because that is supposed to be the
corresponding template decl, i.e., TMPL. */
DECL_USE_TEMPLATE (tmpl) = 0;
DECL_TEMPLATE_INFO (tmpl) = NULL_TREE;
CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0;
CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl))
= INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (TREE_TYPE (tmpl)));
/* It is hidden. */
retrofit_lang_decl (DECL_TEMPLATE_RESULT (tmpl));
DECL_ANTICIPATED (tmpl)
= DECL_ANTICIPATED (DECL_TEMPLATE_RESULT (tmpl)) = true;
/* Inject this template into the global scope. */
friend_type = TREE_TYPE (pushdecl_top_level (tmpl, true));
/* Inject this template into the enclosing namspace scope. */
tmpl = pushdecl_namespace_level (tmpl, true);
}
}
if (context != global_namespace)
{
if (TREE_CODE (context) == NAMESPACE_DECL)
pop_nested_namespace (context);
else
pop_nested_class ();
}
if (TREE_CODE (context) == NAMESPACE_DECL)
pop_nested_namespace (context);
else
pop_nested_class ();
return friend_type;
return TREE_TYPE (tmpl);
}
/* Returns zero if TYPE cannot be completed later due to circularity.
......
2017-12-18 Nathan Sidwell <nathan@acm.org>
PR c++/59930
* g++.dg/parse/pr81247-c.C: Adjust.
* g++.dg/template/pr59930-[123].C: New.
2017-12-18 Claudiu Zissulescu <claziss@synopsys.com>
* gcc.target/arc/tumaddsidi4.c: New test.
......
// PR c++/81247 confused error
// PR c++/81247 rejected well-formed
namespace N { // { dg-message "previous declaration" }
namespace N {
template < typename T > class A
{ // { dg-error "conflicts with a previous" }
{
// injects a hidden class N::N at instantiation time
template < T > friend class N;
};
}
......
// PR c++/59930
namespace N {
template<typename T> class A {
// The injected name is N::B, because we don;t look outside of N
template<typename U> friend struct B;
private:
int n; // { dg-message "declared private here" }
public:
A (int);
};
}
template<typename T> struct B {
int f(N::A<int> ai) { return ai.n; } // { dg-error "is private" }
};
int k = B<int>().f(0);
// PR c++/59930
namespace N {
template < typename T > class A
{
// Injects N::N
template < T > friend class N;
// { dg-error "template parameter" "" { target *-*-* } .-1 }
// { dg-error "redeclared" "" { target *-*-* } .-2 }
};
}
void f ()
{
N::A < int > a1;
N::A <short > a2;
}
// PR c++/59930
namespace NS {
template<typename T> class Holder
{
private:
void func();
template<typename> friend class User;
};
template class Holder<long>;
template<typename T> class User
{
public:
void method() const
{
Holder<T> x;
x.func();
}
};
} // namespace
void Foo()
{
NS::User<long> decl;
decl.method();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment