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 typesusing different approach)


Hi

This patch fixes PR18681 (a regression) for GCC 4.0 using a different
approach than my previous version:

http://gcc.gnu.org/ml/gcc-patches/2004-12/msg00854.html

This is also a complete fix and solves the problems mentioned in the
follow up mails of the patch above.


For the 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>;

the type node of the typedef (such as 'XX' above) is copied (via
build_variant_type_copy in grokdeclarator) and marked it with
TYPE_NO_ACCESS_CHECK_P flag.  When tsubst encounter a type with
this flag marked, access checking is turned off.  In the old
approach, TYPENAME_TYPE, UNBOUND_CLASS_TEMPLATE and SCOPE_REF would
be marked instead.


As in the previous version, the tricky part is about access checking in the typedef declaration itself when the class template containing this typedef is instantiated:

1. Even though we don't want to check any occurrent of 'XX', we still
  want to perform access checking for the declaration

typedef typename T::X XX;

  i.e., whether T::X is accessible, when the enclosing class template
  is instantiated.

The type of typedef, which is TYPENANE_TYPE in this case, is marked.
So we clear TYPE_NO_ACCESS_CHECK_P before the tsubst call, enabling
access checking. During tsubst, the access of the qualified ID 'T::X'
is checked in make_typename_type. This marker is later set back after
tsubst finishes.


2. Second tricky issue is that we don't want to check access for

typedef XX* XX1; // Prior typedef of 'XX' is assumed.

  This is handled exactly the same way as case 1.  We clear
  TYPE_NO_ACCESS_CHECK_P of the type node which is a POINTER_TYPE.
  Nested inside this POINTER_TYPE is a TYPENAME_TYPE node inherited
  from 'XX' declaration which is still marked with TYPE_NO_ACCESS_CHECK_P.
  So no access checking for 'XX'.

The same applies with cases like

typedef D<XX, typename T::X> XX2;

  The TYPE_NO_ACCESS_CHECK_P is cleared for the RECORD_TYPE (for D<...>).
  Inside this RECORD_TYPE, we find 2 TYPENAME_TYPE nodes.
  - One is 'XX', inherited from a previous typedef so it is marked
    and no checking is performed.
  - The other is the 'T::X', not inherited, so it is not marked and
    access checking is done.

  Those cases work because the type of 'XX1' and 'XX2' is different tree
  node from 'XX'.


3. We still require to deal with the special case.


typedef XX XX2;

  the type of 'XX2' and the inherited type 'XX' is exactly the same node.
  We need to avoid clearing TYPE_NO_ACCESS_CHECK_P in the first place.
  So an additional DECL_NO_ACCESS_CHECK_P flag is utilized on the TYPE_DECL
  for this purpose.


Tested on i686-pc-linux-gnu. OK for the mainline?


--Kriang


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

	PR c++/18681
	* cp-tree.h (TYPE_NO_ACCESS_CHECK_P, DECL_NO_ACCESS_CHECK_P):
	New macros.
	* decl.c (grokdeclarator): Set TYPE_NO_ACCESS_CHECK_P and
	maybe DECL_NO_ACCESS_CHECK_P for typedef declared in class
	template.
	* pt.c (instantiate_class_template): Handle
	TYPE_NO_ACCESS_CHECK_P and DECL_NO_ACCESS_CHECK_P when
	tsubst'ing TYPE_DECL.
	(tsubst): Handle TYPE_NO_ACCESS_CHECK_P.

2004-12-22  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.
	* g++.dg/template/access-typedef6.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	Sun Dec 19 19:04:57 2004
--- gcc-main-new/gcc/cp/cp-tree.h	Mon Dec 20 23:09:01 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)
+       TYPE_NO_ACCESS_CHECK_P (in _TYPE)
+       DECL_NO_ACCESS_CHECK_P (in TYPE_DECL)
     6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
        DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL)
        TYPE_MARKED_P (in _TYPE)
*************** struct lang_type GTY(())
*** 1178,1183 ****
--- 1180,1193 ----
     convenient, don't reprocess any methods that appear in its redefinition.  */
  #define TYPE_REDEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->redefined)
  
+ /* Nonzero means that no access checking should be performed on
+    this type.  */
+ #define TYPE_NO_ACCESS_CHECK_P(NODE) TREE_LANG_FLAG_5 (TYPE_CHECK (NODE))
+ 
+ /* Nonzero means that no access checking should be performed on
+    this TYPE_DECL.  */
+ #define DECL_NO_ACCESS_CHECK_P(NODE) TREE_LANG_FLAG_5 (TYPE_DECL_CHECK (NODE))
+ 
  /* Mark bits for repeated base checks.  */
  #define TYPE_MARKED_P(NODE) TREE_LANG_FLAG_6 (TYPE_CHECK (NODE))
  
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Sun Dec 19 19:04:57 2004
--- gcc-main-new/gcc/cp/decl.c	Tue Dec 21 00:18:38 2004
*************** grokdeclarator (const cp_declarator *dec
*** 7698,7703 ****
--- 7698,7750 ----
  	  /* FIXME remangle member functions; member functions of a
  	     type with external linkage have external linkage.  */
  	}
+       else if (type != error_mark_node
+ 	       && processing_template_decl
+ 	       && at_class_scope_p ()
+ 	       && CLASSTYPE_TEMPLATE_INFO (current_class_type)
+ 	       && dependent_type_p (type))
+ 	{
+ 	  /* 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
+ 		   typedef XX1 XX3;		// #3
+ 		   void f1(XX1);		// #4
+ 		   void f2(XX2);		// #5
+ 		   void f3(typename T::X);	// #6
+ 		 };
+ 	       };
+ 	     In cases 4 to 6, we have function parameter with type
+ 	     TYPENAME_TYPE.  However during template instantiation,
+ 	     we want to check access only for case 6, so we set
+ 	     TYPE_NO_ACCESS_CHECK_P for all types coming from typedef.
+ 	     Access checking will be disabled in tsubst for code 4 and 5.
+ 
+ 	     For typedef, we also need to check access of the TYPENAME_TYPE
+ 	     in case 1 but not cases 2 and 3.  This is accomplished by
+ 	     setting DECL_NO_ACCESS_CHECK_P for case 3.  Then in
+ 	     instantiate_class_template, TYPE_NO_ACCESS_CHECK_P of the
+ 	     typedef in 1 and 2 will be cleared temporarily.
+ 
+ 	     For case 1, the type node is a TYPENAME_TYPE so access
+ 	     checking is performed.
+ 
+ 	     For case 2, the type node is a POINTER_TYPE, pointing
+ 	     to the TYPENAME_TYPE.  Even though the TYPE_NO_ACCESS_CHECK_P
+ 	     flag of POINTER_TYPE is cleared, this flag remains set of
+ 	     TYPENAME_TYPE so access checking for the name XX1 is disabled.
+ 
+ 	     Case 3 requires special handling because the typedef has
+ 	     exactly the same type as case 1.  Therefore the TYPE_DECL
+ 	     is marked specially.  */
+ 	  if (TYPE_NO_ACCESS_CHECK_P (type))
+ 	    DECL_NO_ACCESS_CHECK_P (decl) = 1;
+ 	  type = build_variant_type_copy (type);
+ 	  TYPE_NO_ACCESS_CHECK_P (type) = 1;
+ 	  TREE_TYPE (decl) = type;
+ 	}
  
        if (quals)
  	{
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Sun Dec 19 19:05:18 2004
--- gcc-main-new/gcc/cp/pt.c	Tue Dec 21 21:55:05 2004
*************** instantiate_class_template (tree type)
*** 5691,5696 ****
--- 5691,5702 ----
  		{
  		  tree r;
  
+ 		  /* For typedef access checking.  */
+ 		  bool skip_access_check_p
+ 		    = TREE_CODE (t) == TYPE_DECL
+ 		      && TYPE_NO_ACCESS_CHECK_P (TREE_TYPE (t))
+ 		      && !DECL_NO_ACCESS_CHECK_P (t);
+ 
  		  /* The the file and line for this declaration, to
  		     assist in error message reporting.  Since we
  		     called push_tinst_level above, we don't need to
*************** instantiate_class_template (tree type)
*** 5699,5707 ****
--- 5705,5718 ----
  
  		  if (TREE_CODE (t) == TEMPLATE_DECL)
  		    ++processing_template_decl;
+ 		  if (skip_access_check_p)
+ 		    TYPE_NO_ACCESS_CHECK_P (TREE_TYPE (t)) = 0;
  		  r = tsubst (t, args, tf_error | tf_warning, NULL_TREE);
  		  if (TREE_CODE (t) == TEMPLATE_DECL)
  		    --processing_template_decl;
+ 		  if (skip_access_check_p)
+ 		    TYPE_NO_ACCESS_CHECK_P (TREE_TYPE (t)) = 1;
+ 
  		  if (TREE_CODE (r) == VAR_DECL)
  		    {
  		      tree init;
*************** tsubst (tree t, tree args, tsubst_flags_
*** 6920,6925 ****
--- 6931,6948 ----
    if (DECL_P (t))
      return tsubst_decl (t, args, complain);
  
+   if (TYPE_P (t) && TYPE_NO_ACCESS_CHECK_P (t))
+     {
+       /* Temporary clear TYPE_NO_ACCESS_CHECK_P to prevent infinite
+ 	 recursion.  */
+       TYPE_NO_ACCESS_CHECK_P (t) = 0;
+       push_deferring_access_checks (dk_no_check);
+       r = tsubst (t, args, complain, in_decl);
+       pop_deferring_access_checks ();
+       TYPE_NO_ACCESS_CHECK_P (t) = 1;
+       return r;
+     }
+ 
    if (TREE_CODE (t) == IDENTIFIER_NODE)
      type = IDENTIFIER_TYPE_VALUE (t);
    else
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	Mon Dec 20 22:51:37 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	Mon Dec 20 22:51:37 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	Mon Dec 20 22:51:37 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	Mon Dec 20 23:40:22 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
+ //		 (typedef to name previously declared as typedef)
+ 
+ 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	Mon Dec 20 22:51:37 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>;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef6.C gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef6.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access-typedef6.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/access-typedef6.C	Mon Dec 20 23:40:23 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
+ //		 (typedef to name previously declared as typedef)
+ 
+ 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>;

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