From: Kriang Lerdsuwanakij Date: Wed, 8 Jan 2003 14:42:39 +0000 (+0000) Subject: re PR c++/9030 (Template friends and access to local classes) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2b59fc25c6e31acae34c6ab5c108941e5d31e5b4;p=gcc.git re PR c++/9030 (Template friends and access to local classes) PR c++/9030 * decl.c (make_typename_type): Check access only when tf_error. (make_unbound_class_template): Likewise. * pt.c (saved_access_scope): New variable. (push_access_scope_real): New function. (push_access_scope): Likewise. (pop_access_scope): Likewise. (tsubst_default_argument): Use them. (instantiate_template): Likewise. (regenerate_decl_from_template): Likewise. (instantiate_decl): Likewise. (get_mostly_instantiated_function_type): Likewise. * g++.dg/template/friend12.C: New test. * g++.dg/template/friend13.C: Likewise. * g++.old-deja/g++.eh/spec6.C: Add missing error message. From-SVN: r61046 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9b7f67a783e..26207b7a373 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2003-01-08 Kriang Lerdsuwanakij + + PR c++/9030 + * decl.c (make_typename_type): Check access only when tf_error. + (make_unbound_class_template): Likewise. + * pt.c (saved_access_scope): New variable. + (push_access_scope_real): New function. + (push_access_scope): Likewise. + (pop_access_scope): Likewise. + (tsubst_default_argument): Use them. + (instantiate_template): Likewise. + (regenerate_decl_from_template): Likewise. + (instantiate_decl): Likewise. + (get_mostly_instantiated_function_type): Likewise. + 2003-01-07 Nathanael Nerode * tree.c: Delete bogus #if 0 code. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f8141823e30..538519ed043 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5671,10 +5671,13 @@ make_typename_type (context, name, complain) return error_mark_node; } - if (complain & tf_parsing) - type_access_control (context, tmpl); - else - enforce_access (context, tmpl); + if (complain & tf_error) + { + if (complain & tf_parsing) + type_access_control (context, tmpl); + else + enforce_access (context, tmpl); + } return lookup_template_class (tmpl, TREE_OPERAND (fullname, 1), @@ -5703,10 +5706,13 @@ make_typename_type (context, name, complain) return error_mark_node; } - if (complain & tf_parsing) - type_access_control (context, t); - else - enforce_access (context, t); + if (complain & tf_error) + { + if (complain & tf_parsing) + type_access_control (context, t); + else + enforce_access (context, t); + } if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) t = TREE_TYPE (t); @@ -5774,10 +5780,13 @@ make_unbound_class_template (context, name, complain) return error_mark_node; } - if (complain & tf_parsing) - type_access_control (context, tmpl); - else - enforce_access (context, tmpl); + if (complain & tf_error) + { + if (complain & tf_parsing) + type_access_control (context, tmpl); + else + enforce_access (context, tmpl); + } return tmpl; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f7a9114d7a8..b63443b174b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -67,6 +67,8 @@ static size_t inline_parm_levels_used; static GTY(()) tree current_tinst_level; +static GTY(()) tree saved_access_scope; + /* A map from local variable declarations in the body of the template presently being instantiated to the corresponding instantiated local variables. */ @@ -88,6 +90,9 @@ static htab_t local_specializations; #define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current type with the desired type. */ +static void push_access_scope_real PARAMS ((tree, tree, tree)); +static void push_access_scope PARAMS ((tree)); +static void pop_access_scope PARAMS ((tree)); static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree, unification_kind_t, int)); static int try_one_overload PARAMS ((tree, tree, tree, tree, tree, @@ -168,6 +173,80 @@ static int invalid_nontype_parm_type_p PARAMS ((tree, tsubst_flags_t)); static int eq_local_specializations (const void *, const void *); static tree template_for_substitution (tree); +/* Make the current scope suitable for access checking when we are + processing T. T can be FUNCTION_DECL for instantiated function + template, TEMPLATE_DECL for uninstantiated one, or VAR_DECL for + static member variable (need by instantiate_decl). ARGS is the + template argument for TEMPLATE_DECL. If CONTEXT is not NULL_TREE, + this is used instead of the context of T. */ + +void +push_access_scope_real (t, args, context) + tree t, args, context; +{ + if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t)) + { + /* When we are processing specialization `foo' for code like + + template typename U::Inner foo (); + class Outer { + struct Inner {}; + friend Outer::Inner foo (); + }; + + `T' is a TEMPLATE_DECL, but `Outer' is only a friend of one of + its specialization. We can get the FUNCTION_DECL with the right + information because this specialization has already been + registered by the friend declaration above. */ + + if (DECL_FUNCTION_TEMPLATE_P (t) && args) + { + tree full_args = tsubst_template_arg_vector + (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t)), args, tf_none); + tree spec = NULL_TREE; + if (full_args != error_mark_node) + spec = retrieve_specialization (t, full_args); + if (spec) + t = spec; + } + + saved_access_scope = tree_cons + (NULL_TREE, current_function_decl, saved_access_scope); + current_function_decl = t; + } + + if (!context) + context = DECL_CONTEXT (t); + if (context && TYPE_P (context)) + push_nested_class (context, 2); +} + +/* Like push_access_scope_real, but always uses DECL_CONTEXT. */ + +void +push_access_scope (t) + tree t; +{ + push_access_scope_real (t, NULL_TREE, NULL_TREE); +} + +/* Restore the scope set up by push_access_scope. T is the node we + are processing. */ + +void +pop_access_scope (t) + tree t; +{ + if (DECL_CLASS_SCOPE_P (t)) + pop_nested_class (); + + if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t)) + { + current_function_decl = TREE_VALUE (saved_access_scope); + saved_access_scope = TREE_CHAIN (saved_access_scope); + } +} + /* Do any processing required when DECL (a member template declaration) is finished. Returns the TEMPLATE_DECL corresponding to DECL, unless it is a specialization, in which case the DECL @@ -5733,14 +5812,14 @@ tsubst_default_argument (fn, type, arg) ??? current_class_type affects a lot more than name lookup. This is very fragile. Fortunately, it will go away when we do 2-phase name binding properly. */ - if (DECL_CLASS_SCOPE_P (fn)) - pushclass (DECL_CONTEXT (fn), 2); + + /* FN is already the desired FUNCTION_DECL. */ + push_access_scope (fn); arg = tsubst_expr (arg, DECL_TI_ARGS (fn), tf_error | tf_warning, NULL_TREE); - if (DECL_CLASS_SCOPE_P (fn)) - popclass (); + pop_access_scope (fn); /* Make sure the default argument is reasonable. */ arg = check_default_argument (type, arg); @@ -7873,17 +7952,17 @@ instantiate_template (tmpl, targ_ptr) } /* Make sure that we can see identifiers, and compute access - correctly. */ - if (DECL_CLASS_SCOPE_P (gen_tmpl)) - pushclass (tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, tf_error, - gen_tmpl), 1); + correctly. The desired FUNCTION_DECL for FNDECL may or may not be + created earlier. Let push_access_scope_real figure that out. */ + push_access_scope_real + (gen_tmpl, targ_ptr, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, + tf_error, gen_tmpl)); /* substitute template parameters */ fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl), targ_ptr, tf_error, gen_tmpl); - if (DECL_CLASS_SCOPE_P (gen_tmpl)) - popclass (); + pop_access_scope (gen_tmpl); /* The DECL_TI_TEMPLATE should always be the immediate parent template, not the most general template. */ @@ -7955,7 +8034,7 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type, int result; my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0); - + fntype = TREE_TYPE (fn); if (explicit_targs) { @@ -9977,6 +10056,7 @@ regenerate_decl_from_template (decl, tmpl) instantiation of a specialization, which it isn't: it's a full instantiation. */ gen_tmpl = most_general_template (tmpl); + push_access_scope_real (gen_tmpl, args, DECL_CONTEXT (decl)); unregistered = unregister_specialization (decl, gen_tmpl); /* If the DECL was not unregistered then something peculiar is @@ -9984,12 +10064,6 @@ regenerate_decl_from_template (decl, tmpl) register_specialization for it. */ my_friendly_assert (unregistered, 0); - if (DECL_CLASS_SCOPE_P (decl)) - /* Make sure that we can see identifiers, and compute access - correctly, for the class members used in the declaration of - this static variable or function. */ - push_nested_class (DECL_CONTEXT (decl), 2); - /* Do the substitution to get the new declaration. */ new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE); @@ -10010,9 +10084,7 @@ regenerate_decl_from_template (decl, tmpl) DECL_INITIAL (decl) = NULL_TREE; } - /* Pop the class context we pushed above. */ - if (DECL_CLASS_SCOPE_P (decl)) - pop_nested_class (); + pop_access_scope (decl); /* The immediate parent of the new template is still whatever it was before, even though tsubst sets DECL_TI_TEMPLATE up as the most @@ -10218,9 +10290,9 @@ instantiate_decl (d, defer_ok) tree type = TREE_TYPE (gen); /* Make sure that we can see identifiers, and compute access - correctly. */ - if (DECL_CLASS_SCOPE_P (d)) - pushclass (DECL_CONTEXT (d), 1); + correctly. D is already the target FUNCTION_DECL with the + right context. */ + push_access_scope (d); if (TREE_CODE (gen) == FUNCTION_DECL) { @@ -10235,8 +10307,7 @@ instantiate_decl (d, defer_ok) } tsubst (type, gen_args, tf_error | tf_warning, d); - if (DECL_CLASS_SCOPE_P (d)) - popclass (); + pop_access_scope (d); } if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d) @@ -10597,8 +10668,7 @@ get_mostly_instantiated_function_type (decl) partial substitution here. It depends only on outer template parameters, regardless of whether the innermost level is specialized or not. */ - if (DECL_CLASS_SCOPE_P (decl)) - pushclass (DECL_CONTEXT (decl), 1); + push_access_scope (decl); /* Now, do the (partial) substitution to figure out the appropriate function type. */ @@ -10611,8 +10681,7 @@ get_mostly_instantiated_function_type (decl) TREE_VEC_LENGTH (partial_args)--; tparms = tsubst_template_parms (tparms, partial_args, tf_error); - if (DECL_CLASS_SCOPE_P (decl)) - popclass (); + pop_access_scope (decl); } return fn_type; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ba32c50072b..848423d59d3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2003-01-08 Kriang Lerdsuwanakij + + PR c++/9030 + * g++.dg/template/friend12.C: New test. + * g++.dg/template/friend13.C: Likewise. + * g++.old-deja/g++.eh/spec6.C: Add missing error message. + Wed Jan 8 11:41:47 CET 2003 Jan Hubicka * gcc.dg/i386-cadd.c: New test. diff --git a/gcc/testsuite/g++.dg/template/friend12.C b/gcc/testsuite/g++.dg/template/friend12.C new file mode 100644 index 00000000000..0cd561b5a2a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend12.C @@ -0,0 +1,24 @@ +// { dg-do compile } + +// Origin: Wolfgang Bangerth + +// PR 9030. Perform access checking to parameter and return type of +// function template correctly when the template is friend. + +template class Outer { + private: + struct Inner {}; + + template + friend typename Outer::Inner foo (); +}; + +template +typename Outer::Inner +foo () { + return typename Outer::Inner(); +} + +void f() { + foo(); +} diff --git a/gcc/testsuite/g++.dg/template/friend13.C b/gcc/testsuite/g++.dg/template/friend13.C new file mode 100644 index 00000000000..6eebf6b951f --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend13.C @@ -0,0 +1,21 @@ +// { dg-do compile } + +// Perform access checking to parameter and return type of +// function template correctly when only specialization is friend. + +template +typename T::Inner +foo () { + return typename T::Inner(); +} + +class Outer { + private: + struct Inner {}; + + friend Outer::Inner foo (); +}; + +void f() { + foo(); +} diff --git a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C index 1bde4cb92b8..d9d4edf1f48 100644 --- a/gcc/testsuite/g++.old-deja/g++.eh/spec6.C +++ b/gcc/testsuite/g++.old-deja/g++.eh/spec6.C @@ -25,7 +25,7 @@ template void fnx(T *) throw(T){} // ERROR - invalid use of void expre void fx() { fnx((int *)0); - fnx((void *)0); + fnx((void *)0); // ERROR - instantiated from here } // [except.spec] 2, exception specifiers must be the same set of types (but