This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH for 4.0] Fix PR18681 (access checking for typedef types)Part 1 or 2


Hi

This patch is a partial fix to PR18681 (a regression) for GCC 4.0.
The version for 3.4 branch will be posted separately due to
lots of differences of code surrounding the changes.

The problem in PR18681 is that we don't check access correctly for
code like:

 class C {
   typedef int X;
   template <class T> friend class A;
 };

 template <classs T> class A {
   typedef typename T::X XX;
   class B {
     void f(XX);	// should be allowed, currently issue error
			// message that C::X is private
   };
 };

template class A<C>;

We have problem accessing 'XX' at the commented line despite it's a name
from the enclosing class of 'B'. This because the type of 'XX' is 'typename T::X' from typedef declaration.


To solve this issue, I add a TREE_NO_ACCESS_CHECK_P flag.
When parsing code like 'typedef typename T::X XX;', all TYPENAME_TYPE
and UNBOUND_CLASS_TEMPLATE are marked with TREE_NO_ACCESS_CHECK_P.
Later during tsubst'ing 'void f(XX);', we notice that the TYPENAME_TYPE
of the type of 'XX' is marked and access checking is skipped.
This approach is very safe because only functions creating/tsubt'ing
those tree nodes have to aware of this extra flag.

Note that we also need to mark SCOPE_REF as well.  This part will be
posted as part 2 of this fix as SCOPE_REF tree nodes are created in
many places, with several different variations.

There are 2 tricky issues to deal with:

1. One issue is that we also want to perform access checking for

typedef typename T::X XX;

This explains the condition logic used to disable access checking:

	if (TREE_NO_ACCESS_CHECK_P (t) && !processing_typedef)
	  ...

  i.e., we disable access checking for 'void f(XX);' but not the typedef
  above.

2. Another tricky issue is that we want to check access for

typedef typename T::X XX;

but not

typedef XX XX1;

  Both cases contain TYPENAME_TYPE with TREE_NO_ACCESS_CHECK_P.  We
  distinguish these 2 cases by marking TREE_NO_ACCESS_CHECK_P of
  TYPE_DECL node for 'XX1'.


Tested on i686-pc-linux-gnu. OK to commit to mainline?


--Kriang


2004-12-12  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/18681
	* cp-tree.h (struct saved_scope): Add x_processing_typedef field.
	(processing_typedef, TREE_NO_ACCESS_CHECK_P): New macros.
	* decl.c (struct typename_info): Add no_access_check_p field.
	(typename_compare): Use it.
	(build_typename_type, make_unbound_class_template): Set
	TREE_NO_ACCESS_CHECK_P for code appearing inside typedef.
	(grokdeclarator): Set TREE_NO_ACCESS_CHECK_P for typedef to
	previuosly declared typedef type.
	* parser.c (cp_parser_decl_specifier_seq): Set processing_typedef
	when typedef keyword is encountered.
	* pt.c (instantiate_class_template): Set processing_typedef
	when tsubst'ing typedef.  Handle TREE_NO_ACCESS_CHECK_P.
	(tsubst <case TYPENAME_TYPE, UNBOUND_CLASS_TEMPLATE>): Handle
	TREE_NO_ACCESS_CHECK_P.
	(tsubst_qualified_id): Handle TREE_NO_ACCESS_CHECK_P.

2004-12-12  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/18681
	* g++.dg/template/access-typedef1.C: New test.
	* g++.dg/template/access-typedef2.C: Likewise.
	* g++.dg/template/access-typedef3.C: Likewise.
	* g++.dg/template/access-typedef4.C: Likewise.
	* g++.dg/template/access-typedef5.C: Likewise.


diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h	Wed Dec  8 17:15:12 2004
--- gcc-main-new/gcc/cp/cp-tree.h	Sat Dec 11 01:21:34 2004
*************** struct diagnostic_context;
*** 72,77 ****
--- 72,79 ----
        DECL_TINFO_P (in VAR_DECL)
     5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
        DECL_VTABLE_OR_VTT_P (in VAR_DECL)
+       TREE_NO_ACCESS_CHECK_P (in TYPENAME_TYPE, UNBOUND_CLASS_TEMPLATE,
+ 			      SCOPE_REF, or TYPE_DECL)
     6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
        DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
        TYPE_MARKED_P (in _TYPE)
*************** struct saved_scope GTY(())
*** 665,670 ****
--- 667,673 ----
    HOST_WIDE_INT x_processing_template_decl;
    int x_processing_specialization;
    bool x_processing_explicit_instantiation;
+   bool x_processing_typedef;
    int need_pop_function_context;
  
    struct stmt_tree_s x_stmt_tree;
*************** struct saved_scope GTY(())
*** 712,717 ****
--- 715,749 ----
  #define processing_specialization scope_chain->x_processing_specialization
  #define processing_explicit_instantiation scope_chain->x_processing_explicit_instantiation
  
+ /* For typedef inside class template, we need to be careful about access
+    checking.  For example:
+ 
+      template <classs T> class A {
+        typedef typename T::X XX1;     // #1
+        class B {
+ 	 typedef XX1 XX2;             // #2
+ 	 void f1(XX1);                // #3
+ 	 void f2(XX2);                // #4
+ 	 void f3(typename T::X);      // #5
+        };
+      };
+ 
+    In cases 3 to 5, we have function parameter with type TYPENAME_TYPE.
+    However access checking should be performed only for case 5.  To
+    distinguish TYPENAME_TYPE, UNBOUND_CLASS_TEMPLATE, and SCOPE_REF
+    between those coming from typedef and those declared directly, we set
+    processing_typedef when we encounter typedef during parsing
+    in cp_parser_decl_specifier_seq.  Then the TREE_NO_ACCESS_CHECK_P
+    created for those tree nodes are set during creation in
+    build_typename_type and make_unbound_class_template.  Access checking
+    will be disabled in tsubst for code 3 and 4.
+ 
+    For typedef, we need to check access of case 1 but not case 2.  This
+    is accomplished by setting TREE_NO_ACCESS_CHECK_P for the TYPE_DECL
+    of case 2 in grokdeclarator.  This turn off access checking in
+    instantiate_class_template.  */
+ #define processing_typedef scope_chain->x_processing_typedef
+ 
  /* The cached class binding level, from the most recently exited
     class, or NULL if none.  */
  
*************** struct lang_type GTY(())
*** 1181,1186 ****
--- 1213,1222 ----
  /* Mark bits for repeated base checks.  */
  #define TYPE_MARKED_P(NODE) TREE_LANG_FLAG_6 (TYPE_CHECK (NODE))
  
+ /* Tree means access checking should be performed for this NODE after
+    template substitution.  */
+ #define TREE_NO_ACCESS_CHECK_P(NODE) TREE_LANG_FLAG_5 (NODE)
+ 
  /* Non-zero if the class NODE has multiple paths to the same (virtual)
     base object.  */
  #define CLASSTYPE_DIAMOND_SHAPED_P(NODE) \
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Wed Dec  8 17:17:39 2004
--- gcc-main-new/gcc/cp/decl.c	Sat Dec 11 01:19:08 2004
*************** typedef struct typename_info {
*** 2543,2548 ****
--- 2543,2549 ----
    tree template_id;
    bool enum_p;
    bool class_p;
+   bool no_access_check_p;
  } typename_info;
  
  /* Compare two TYPENAME_TYPEs.  K1 and K2 are really of type `tree'.  */
*************** typename_compare (const void * k1, const
*** 2560,2566 ****
  	  && TYPE_CONTEXT (t1) == t2->scope
  	  && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
  	  && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
! 	  && TYPENAME_IS_CLASS_P (t1) == t2->class_p);
  }
  
  /* Build a TYPENAME_TYPE.  If the type is `typename T::t', CONTEXT is
--- 2561,2568 ----
  	  && TYPE_CONTEXT (t1) == t2->scope
  	  && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
  	  && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
! 	  && TYPENAME_IS_CLASS_P (t1) == t2->class_p
! 	  && TREE_NO_ACCESS_CHECK_P (t1) == t2->no_access_check_p);
  }
  
  /* Build a TYPENAME_TYPE.  If the type is `typename T::t', CONTEXT is
*************** build_typename_type (tree context, tree 
*** 2591,2596 ****
--- 2593,2599 ----
    ti.class_p = (tag_type == class_type
  		|| tag_type == record_type
  		|| tag_type == union_type);
+   ti.no_access_check_p = processing_typedef;
    hash =  (htab_hash_pointer (ti.scope)
  	   ^ htab_hash_pointer (ti.name));
  
*************** build_typename_type (tree context, tree 
*** 2606,2611 ****
--- 2609,2615 ----
        TYPENAME_TYPE_FULLNAME (t) = ti.template_id;
        TYPENAME_IS_ENUM_P (t) = ti.enum_p;
        TYPENAME_IS_CLASS_P (t) = ti.class_p;
+       TREE_NO_ACCESS_CHECK_P (t) = ti.no_access_check_p;
        
        /* Build the corresponding TYPE_DECL.  */
        d = build_decl (TYPE_DECL, name, t);
*************** make_unbound_class_template (tree contex
*** 2806,2811 ****
--- 2810,2816 ----
    t = make_aggr_type (UNBOUND_CLASS_TEMPLATE);
    TYPE_CONTEXT (t) = FROB_CONTEXT (context);
    TREE_TYPE (t) = NULL_TREE;
+   TREE_NO_ACCESS_CHECK_P (t) = processing_typedef;
  
    /* Build the corresponding TEMPLATE_DECL.  */
    d = build_decl (TEMPLATE_DECL, name, t);
*************** grokdeclarator (const cp_declarator *dec
*** 7705,7710 ****
--- 7710,7717 ----
  	  /* FIXME remangle member functions; member functions of a
  	     type with external linkage have external linkage.  */
  	}
+       else if (typedef_decl)
+ 	TREE_NO_ACCESS_CHECK_P (decl) = 1;
  
        if (quals)
  	{
diff -cprN gcc-main-save/gcc/cp/parser.c gcc-main-new/gcc/cp/parser.c
*** gcc-main-save/gcc/cp/parser.c	Fri Dec 10 19:04:43 2004
--- gcc-main-new/gcc/cp/parser.c	Sat Dec 11 01:04:06 2004
*************** cp_parser_decl_specifier_seq (cp_parser*
*** 7075,7080 ****
--- 7075,7081 ----
  	       typedef  */
  	case RID_TYPEDEF:
  	  ++decl_specs->specs[(int) ds_typedef];
+ 	  processing_typedef = true;
  	  /* Consume the token.  */
  	  cp_lexer_consume_token (parser->lexer);
  	  /* A constructor declarator cannot appear in a typedef.  */
*************** cp_parser_decl_specifier_seq (cp_parser*
*** 7222,7227 ****
--- 7223,7230 ----
        flags |= CP_PARSER_FLAGS_OPTIONAL;
      }
  
+   processing_typedef = false;
+ 
    /* Don't allow a friend specifier with a class definition.  */
    if (decl_specs->specs[(int) ds_friend] != 0
        && (*declares_class_or_enum & 2))
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Wed Dec  8 17:15:14 2004
--- gcc-main-new/gcc/cp/pt.c	Sat Dec 11 01:24:34 2004
*************** instantiate_class_template (tree type)
*** 5696,5704 ****
--- 5696,5723 ----
  
  		  if (TREE_CODE (t) == TEMPLATE_DECL)
  		    ++processing_template_decl;
+ 		  else if (TREE_CODE (t) == TYPE_DECL
+ 			   && !DECL_IMPLICIT_TYPEDEF_P (t)
+ 			   && !DECL_SELF_REFERENCE_P (t))
+ 		    {
+ 		      if (TREE_NO_ACCESS_CHECK_P (t))
+ 			push_deferring_access_checks (dk_no_check);
+ 		      processing_typedef = true;
+ 		    }
+ 
  		  r = tsubst (t, args, tf_error | tf_warning, NULL_TREE);
+ 
  		  if (TREE_CODE (t) == TEMPLATE_DECL)
  		    --processing_template_decl;
+ 		  else if (TREE_CODE (t) == TYPE_DECL
+ 			   && !DECL_IMPLICIT_TYPEDEF_P (t)
+ 			   && !DECL_SELF_REFERENCE_P (t))
+ 		    {
+ 		      if (TREE_NO_ACCESS_CHECK_P (t))
+ 			pop_deferring_access_checks ();
+ 		      processing_typedef = false;
+ 		    }
+ 
  		  if (TREE_CODE (r) == VAR_DECL)
  		    {
  		      tree init;
*************** tsubst (tree t, tree args, tsubst_flags_
*** 7386,7395 ****
--- 7405,7419 ----
  	      }
  	  }
  
+ 	if (TREE_NO_ACCESS_CHECK_P (t) && !processing_typedef)
+ 	  push_deferring_access_checks (dk_no_check);
  	f = make_typename_type (ctx, f, typename_type,
  				(complain & tf_error) | tf_keep_type_decl);
+ 	if (TREE_NO_ACCESS_CHECK_P (t) && !processing_typedef)
+ 	  pop_deferring_access_checks ();
  	if (f == error_mark_node)
  	  return f;
+ 
   	if (TREE_CODE (f) == TYPE_DECL)
   	  {
  	    complain |= tf_ignore_bad_quals;
*************** tsubst (tree t, tree args, tsubst_flags_
*** 7422,7428 ****
  
  	if (parm_list)
  	  parm_list = tsubst_template_parms (parm_list, args, complain);
! 	return make_unbound_class_template (ctx, name, parm_list, complain);
        }
  
      case INDIRECT_REF:
--- 7446,7459 ----
  
  	if (parm_list)
  	  parm_list = tsubst_template_parms (parm_list, args, complain);
! 
! 	if (TREE_NO_ACCESS_CHECK_P (t) && !processing_typedef)
! 	  push_deferring_access_checks (dk_no_check);
! 	r = make_unbound_class_template (ctx, name, parm_list, complain);
! 	if (TREE_NO_ACCESS_CHECK_P (t) && !processing_typedef)
! 	  pop_deferring_access_checks ();
! 
! 	return r;
        }
  
      case INDIRECT_REF:
*************** tsubst_qualified_id (tree qualified_id, 
*** 7598,7605 ****
    
    if (DECL_P (expr))
      {
!       check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
! 					   scope);
        /* Remember that there was a reference to this entity.  */
        mark_used (expr);
      }
--- 7629,7638 ----
    
    if (DECL_P (expr))
      {
!       if (!TREE_NO_ACCESS_CHECK_P (qualified_id) || processing_typedef)
! 	check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
! 					     scope);
! 
        /* Remember that there was a reference to this entity.  */
        mark_used (expr);
      }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef1.C gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef1.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef1.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef1.C	Sat Dec 11 17:57:54 2004
***************
*** 0 ****
--- 1,27 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Roehrl <wolfgang.roehrl@de.gi-de.com>
+ 
+ // PR c++/18681: Access checking of typedef to type containing typename
+ //		 (Valid case)
+ 
+ template <typename> class C1;
+ 
+ template <typename T_>
+ class C2
+ {
+   typedef T_ T_PAR_TYPE;
+   friend class C1<T_>;
+ };
+ 
+ template <typename T_>
+ class C1
+ {
+   typedef typename C2<T_>::T_PAR_TYPE T_PAR;
+   struct S1
+   {
+     T_PAR par;
+   };
+ };
+ 
+ template class C1<int>;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef2.C gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef2.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef2.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef2.C	Sat Dec 11 17:58:00 2004
***************
*** 0 ****
--- 1,24 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Roehrl <wolfgang.roehrl@de.gi-de.com>
+ 
+ // PR c++/18681: Access checking of typedef to type containing typename
+ //		 (Invalid case)
+ 
+ template <typename T_>
+ class C2
+ {
+   typedef T_ T_PAR_TYPE;			// { dg-error "private" }
+ };
+ 
+ template <typename T_>
+ class C1
+ {
+   typedef typename C2<T_>::T_PAR_TYPE T_PAR;	// { dg-error "this context" }
+   struct S1
+   {
+     T_PAR par;
+   };
+ };
+ 
+ template class C1<int>;				// { dg-error "instantiated" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef3.C gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef3.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef3.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef3.C	Sat Dec 11 17:58:04 2004
***************
*** 0 ****
--- 1,26 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Roehrl <wolfgang.roehrl@de.gi-de.com>
+ 
+ // PR c++/18681: Access checking of typedef to type containing typename
+ //		 (Invalid case)
+ 
+ template <typename> class C1;
+ 
+ template <typename T_> class C2
+ {
+   typedef T_ T_PAR_TYPE;			// { dg-error "private" }
+   friend class C1<T_>;
+ };
+ 
+ template <typename T_>
+ class C1
+ {
+   struct S1
+   {
+     typedef typename C2<T_>::T_PAR_TYPE T_PAR;	// { dg-error "this context" }
+     T_PAR par;
+   };
+ };
+ 
+ template class C1<int>;				// { dg-error "instantiated" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef4.C gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef4.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef4.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef4.C	Sat Dec 11 17:58:09 2004
***************
*** 0 ****
--- 1,28 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Roehrl <wolfgang.roehrl@de.gi-de.com>
+ 
+ // PR c++/18681: Access checking of typedef to type containing typename
+ //		 (Invalid case)
+ 
+ template <typename> class C1;
+ 
+ template <typename T_>
+ class C2
+ {
+   typedef T_ T_PAR_TYPE;
+   friend class C1<T_>;
+ };
+ 
+ template <typename T_>
+ class C1
+ {
+   typedef typename C2<T_>::T_PAR_TYPE T_PAR;
+   struct S1
+   {
+     typedef T_PAR T_PAR2;
+     T_PAR2 par;
+   };
+ };
+ 
+ template class C1<int>;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef5.C gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef5.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef5.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef5.C	Sat Dec 11 17:58:14 2004
***************
*** 0 ****
--- 1,29 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Roehrl <wolfgang.roehrl@de.gi-de.com>
+ 
+ // PR c++/18681: Access checking of typedef to type containing
+ //		 member template
+ 
+ template <typename> class C1;
+ 
+ template <typename T_>
+ class C2
+ {
+   template <typename U_> class D {};
+   friend class C1<T_>;
+ };
+ 
+ template <template <typename T_> class> class C3 {};
+ 
+ template <typename T_>
+ class C1
+ {
+   typedef C3<C2<T_>::template D> T_PAR;
+   struct S1
+   {
+     T_PAR par;
+   };
+ };
+ 
+ template class C1<int>;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]