[C++ PATCH, committed] Fix PR9030 (main trunk version)
Kriang Lerdsuwanakij
lerdsuwa@users.sourceforge.net
Wed Jan 8 14:54:00 GMT 2003
Hi
This is the version of PR9030 bug fix that I have committed to the
main trunk. The approved version doesn't apply cleanly due to
some surrounding code changes after new parser merge. Here are the
changes I made in this version:
- Use push_nested_class instead of pushclass.
- The push_access_scope call in regenerate_decl_from_template
use the wrong context. The correct context should be the already
tsubst'ed one.
- The ARG argument of push_access_scope is no longer used and removed.
Tested on i686-pc-linux-gnu with no regressions.
--Kriang
2003-01-07 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
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.
2002-01-07 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
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.
* g++.old-deja/g++.other/defarg1.C: Change expected error message.
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c Tue Jan 7 21:21:51 2003
--- gcc-main-new/gcc/cp/decl.c Tue Jan 7 21:18:56 2003
*************** make_typename_type (context, name, compl
*** 5671,5680 ****
return error_mark_node;
}
! if (complain & tf_parsing)
! type_access_control (context, tmpl);
! else
! enforce_access (context, tmpl);
return lookup_template_class (tmpl,
TREE_OPERAND (fullname, 1),
--- 5671,5683 ----
return error_mark_node;
}
! 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),
*************** make_typename_type (context, name, compl
*** 5703,5712 ****
return error_mark_node;
}
! 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);
--- 5706,5718 ----
return error_mark_node;
}
! 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);
*************** make_unbound_class_template (context, na
*** 5774,5783 ****
return error_mark_node;
}
! if (complain & tf_parsing)
! type_access_control (context, tmpl);
! else
! enforce_access (context, tmpl);
return tmpl;
}
--- 5780,5792 ----
return error_mark_node;
}
! if (complain & tf_error)
! {
! if (complain & tf_parsing)
! type_access_control (context, tmpl);
! else
! enforce_access (context, tmpl);
! }
return tmpl;
}
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c Tue Jan 7 21:22:15 2003
--- gcc-main-new/gcc/cp/pt.c Wed Jan 8 20:48:17 2003
*************** static size_t inline_parm_levels_used;
*** 67,72 ****
--- 67,74 ----
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. */
*************** static htab_t local_specializations;
*** 88,93 ****
--- 90,98 ----
#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,
*************** static int invalid_nontype_parm_type_p P
*** 168,173 ****
--- 173,252 ----
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<Outer>' for code like
+
+ template <class U> typename U::Inner foo ();
+ class Outer {
+ struct Inner {};
+ friend Outer::Inner foo<Outer> ();
+ };
+
+ `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
*************** tsubst_default_argument (fn, type, arg)
*** 5733,5746 ****
??? 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);
arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
tf_error | tf_warning, NULL_TREE);
! if (DECL_CLASS_SCOPE_P (fn))
! popclass ();
/* Make sure the default argument is reasonable. */
arg = check_default_argument (type, arg);
--- 5812,5825 ----
??? 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. */
!
! /* 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);
! pop_access_scope (fn);
/* Make sure the default argument is reasonable. */
arg = check_default_argument (type, arg);
*************** instantiate_template (tmpl, targ_ptr)
*** 7873,7889 ****
}
/* 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);
/* substitute template parameters */
fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
targ_ptr, tf_error, gen_tmpl);
! if (DECL_CLASS_SCOPE_P (gen_tmpl))
! popclass ();
/* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */
--- 7952,7968 ----
}
/* Make sure that we can see identifiers, and compute access
! 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);
! pop_access_scope (gen_tmpl);
/* The DECL_TI_TEMPLATE should always be the immediate parent
template, not the most general template. */
*************** fn_type_unification (fn, explicit_targs,
*** 7955,7961 ****
int result;
my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
!
fntype = TREE_TYPE (fn);
if (explicit_targs)
{
--- 8034,8040 ----
int result;
my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
!
fntype = TREE_TYPE (fn);
if (explicit_targs)
{
*************** regenerate_decl_from_template (decl, tmp
*** 9977,9982 ****
--- 10056,10062 ----
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
*************** regenerate_decl_from_template (decl, tmp
*** 9984,9995 ****
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);
--- 10064,10069 ----
*************** regenerate_decl_from_template (decl, tmp
*** 10010,10018 ****
DECL_INITIAL (decl) = NULL_TREE;
}
! /* Pop the class context we pushed above. */
! if (DECL_CLASS_SCOPE_P (decl))
! pop_nested_class ();
/* The immediate parent of the new template is still whatever it was
before, even though tsubst sets DECL_TI_TEMPLATE up as the most
--- 10084,10090 ----
DECL_INITIAL (decl) = NULL_TREE;
}
! 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
*************** instantiate_decl (d, defer_ok)
*** 10218,10226 ****
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);
if (TREE_CODE (gen) == FUNCTION_DECL)
{
--- 10290,10298 ----
tree type = TREE_TYPE (gen);
/* Make sure that we can see identifiers, and compute access
! correctly. D is already the target FUNCTION_DECL with the
! right context. */
! push_access_scope (d);
if (TREE_CODE (gen) == FUNCTION_DECL)
{
*************** instantiate_decl (d, defer_ok)
*** 10235,10242 ****
}
tsubst (type, gen_args, tf_error | tf_warning, d);
! if (DECL_CLASS_SCOPE_P (d))
! popclass ();
}
if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
--- 10307,10313 ----
}
tsubst (type, gen_args, tf_error | tf_warning, d);
! pop_access_scope (d);
}
if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
*************** get_mostly_instantiated_function_type (d
*** 10597,10604 ****
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);
/* Now, do the (partial) substitution to figure out the
appropriate function type. */
--- 10668,10674 ----
partial substitution here. It depends only on outer template
parameters, regardless of whether the innermost level is
specialized or not. */
! push_access_scope (decl);
/* Now, do the (partial) substitution to figure out the
appropriate function type. */
*************** get_mostly_instantiated_function_type (d
*** 10611,10618 ****
TREE_VEC_LENGTH (partial_args)--;
tparms = tsubst_template_parms (tparms, partial_args, tf_error);
! if (DECL_CLASS_SCOPE_P (decl))
! popclass ();
}
return fn_type;
--- 10681,10687 ----
TREE_VEC_LENGTH (partial_args)--;
tparms = tsubst_template_parms (tparms, partial_args, tf_error);
! pop_access_scope (decl);
}
return fn_type;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend12.C gcc-main-new/gcc/testsuite/g++.dg/template/friend12.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend12.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend12.C Tue Jan 7 21:13:00 2003
***************
*** 0 ****
--- 1,24 ----
+ // { dg-do compile }
+
+ // Origin: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
+
+ // PR 9030. Perform access checking to parameter and return type of
+ // function template correctly when the template is friend.
+
+ template <class T> class Outer {
+ private:
+ struct Inner {};
+
+ template <class T_>
+ friend typename Outer<T_>::Inner foo ();
+ };
+
+ template <class T>
+ typename Outer<T>::Inner
+ foo () {
+ return typename Outer<T>::Inner();
+ }
+
+ void f() {
+ foo<int>();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend13.C gcc-main-new/gcc/testsuite/g++.dg/template/friend13.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend13.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend13.C Tue Jan 7 21:13:00 2003
***************
*** 0 ****
--- 1,21 ----
+ // { dg-do compile }
+
+ // Perform access checking to parameter and return type of
+ // function template correctly when only specialization is friend.
+
+ template <class T>
+ typename T::Inner
+ foo () {
+ return typename T::Inner();
+ }
+
+ class Outer {
+ private:
+ struct Inner {};
+
+ friend Outer::Inner foo<Outer> ();
+ };
+
+ void f() {
+ foo<Outer>();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.eh/spec6.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.eh/spec6.C Tue Jan 7 21:24:15 2003
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.eh/spec6.C Tue Jan 7 21:13:00 2003
*************** template<class T> void fnx(T *) throw(T)
*** 25,31 ****
void fx()
{
fnx((int *)0);
! fnx((void *)0);
}
// [except.spec] 2, exception specifiers must be the same set of types (but
--- 25,31 ----
void fx()
{
fnx((int *)0);
! fnx((void *)0); // ERROR - instantiated from here
}
// [except.spec] 2, exception specifiers must be the same set of types (but
More information about the Gcc-patches
mailing list