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: Reduce direct use of OFFSET_TYPE


The C++ front-end curiously represents pointer-to-data-memer types as
POINTER_TYPEs wrappe around OFFSET_TYPEs.  Someday we may change that,
but not now.  However, we should try to minimize the direct use of
OFFSET_TYPE; we have machinery for accessing these pointer-to-member
types in an abstractly appropriate way and we may as well use them.

This patch removes some of the places where we are explicitly creating
OFFSET_TYPEs when what we really want is a pointer-to-member.  And
thereby brings the new parser a little closer to compiling libstdc++...

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2002-08-09  Mark Mitchell  <mark@codesourcery.com>

	* call.c (standard_conversion): Use build_ptrmem_type.
	* cp-tree.h (build_ptrmem_type): New function.
	(adjust_result_of_qualified_name_lookup): Likewise.
	* decl.c (grokvardecl): Do not look for OFFSET_TYPEs to indicate
	static data members.
	(build_ptrmem_type): New function.
	(grokdeclarator): Do not use build_offset_type when encountering a
	qualified name.
	* parse.y (parse_finish_call_expr): Use
	adjust_result_of_qualified_name_lookup.
	* search.c (adjust_result_of_qualified_name_lookup): New function.
	* typeck.c (qualify_type_recursive): Use TYPE_PTRMEM_* rather than
	accessing OFFSET_TYPEs directly.
	
2002-08-09  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/template/crash1.C: New test.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.328
diff -c -p -r1.328 call.c
*** cp/call.c	8 Aug 2002 05:48:34 -0000	1.328
--- cp/call.c	9 Aug 2002 19:45:17 -0000
*************** standard_conversion (to, from, expr)
*** 838,845 ****
  		  (TREE_TYPE (TREE_TYPE (from)),
  		   TREE_TYPE (TREE_TYPE (to)))))
  	    {
! 	      from = build_offset_type (tbase, TREE_TYPE (TREE_TYPE (from)));
! 	      from = build_pointer_type (from);
  	      conv = build_conv (PMEM_CONV, from, conv);
  	    }
  	}
--- 838,844 ----
  		  (TREE_TYPE (TREE_TYPE (from)),
  		   TREE_TYPE (TREE_TYPE (to)))))
  	    {
! 	      from = build_ptrmem_type (tbase, TREE_TYPE (TREE_TYPE (from)));
  	      conv = build_conv (PMEM_CONV, from, conv);
  	    }
  	}
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.743
diff -c -p -r1.743 cp-tree.h
*** cp/cp-tree.h	8 Aug 2002 05:48:35 -0000	1.743
--- cp/cp-tree.h	9 Aug 2002 19:45:20 -0000
*************** extern void expand_static_init			PARAMS 
*** 3682,3687 ****
--- 3682,3688 ----
  extern tree start_handler_parms                 PARAMS ((tree, tree));
  extern int complete_array_type			PARAMS ((tree, tree, int));
  extern tree build_ptrmemfunc_type		PARAMS ((tree));
+ extern tree build_ptrmem_type                   (tree, tree);
  /* the grokdeclarator prototype is in decl.h */
  extern int parmlist_is_exprlist			PARAMS ((tree));
  extern int copy_fn_p				PARAMS ((tree));
*************** extern tree find_vbase_instance         
*** 4056,4062 ****
  extern tree binfo_for_vbase                     PARAMS ((tree, tree));
  extern tree binfo_via_virtual                   PARAMS ((tree, tree));
  extern tree build_baselink                      (tree, tree, tree, tree);
! 
  /* in semantics.c */
  extern void init_cp_semantics                   PARAMS ((void));
  extern tree finish_expr_stmt                    PARAMS ((tree));
--- 4057,4064 ----
  extern tree binfo_for_vbase                     PARAMS ((tree, tree));
  extern tree binfo_via_virtual                   PARAMS ((tree, tree));
  extern tree build_baselink                      (tree, tree, tree, tree);
! extern tree adjust_result_of_qualified_name_lookup
!                                                 (tree, tree, tree);
  /* in semantics.c */
  extern void init_cp_semantics                   PARAMS ((void));
  extern tree finish_expr_stmt                    PARAMS ((tree));
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.927
diff -c -p -r1.927 decl.c
*** cp/decl.c	8 Aug 2002 05:48:35 -0000	1.927
--- cp/decl.c	9 Aug 2002 19:45:23 -0000
*************** grokfndecl (ctype, type, declarator, ori
*** 9137,9200 ****
    return decl;
  }
  
  static tree
! grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
       tree type;
!      tree declarator;
       RID_BIT_TYPE *specbits_in;
       int initialized;
       int constp;
!      tree in_namespace;
  {
    tree decl;
    RID_BIT_TYPE specbits;
  
    specbits = *specbits_in;
  
!   if (TREE_CODE (type) == OFFSET_TYPE)
      {
!       /* If you declare a static member so that it
! 	 can be initialized, the code will reach here.  */
!       tree basetype = TYPE_OFFSET_BASETYPE (type);
!       type = TREE_TYPE (type);
!       decl = build_lang_decl (VAR_DECL, declarator, type);
!       DECL_CONTEXT (decl) = basetype;
      }
-   else
-     {
-       tree context;
  
!       if (in_namespace)
! 	context = in_namespace;
!       else if (namespace_bindings_p () || RIDBIT_SETP (RID_EXTERN, specbits))
! 	context = current_namespace;
!       else
! 	context = NULL_TREE;
! 
!       /* For namespace-scope variables, declared in a template, we
! 	 need the full lang_decl.  The same is true for
! 	 namespace-scope variables that do not have C++ language
! 	 linkage.  */
!       if (context 
! 	  && (processing_template_decl 
! 	      || current_lang_name != lang_name_cplusplus))
! 	decl = build_lang_decl (VAR_DECL, declarator, type);
!       else
! 	decl = build_decl (VAR_DECL, declarator, type);
! 
!       if (context)
! 	set_decl_namespace (decl, context, 0);
  
!       context = DECL_CONTEXT (decl);
!       if (declarator && context && current_lang_name != lang_name_c)
! 	/* We can't mangle lazily here because we don't have any
! 	   way to recover whether or not a variable was `extern
! 	   "C"' later.  */
! 	mangle_decl (decl);
!     }
  
!   if (in_namespace)
!     set_decl_namespace (decl, in_namespace, 0);
  
    if (RIDBIT_SETP (RID_EXTERN, specbits))
      {
--- 9137,9204 ----
    return decl;
  }
  
+ /* Create a VAR_DECL named NAME with the indicated TYPE.  
+ 
+    If SCOPE is non-NULL, it is the class type or namespace containing
+    the variable.  If SCOPE is NULL, the variable should is created in
+    the innermost enclosings scope.  */
+ 
  static tree
! grokvardecl (type, name, specbits_in, initialized, constp, scope)
       tree type;
!      tree name;
       RID_BIT_TYPE *specbits_in;
       int initialized;
       int constp;
!      tree scope;
  {
    tree decl;
    RID_BIT_TYPE specbits;
  
+   my_friendly_assert (!name || TREE_CODE (name) == IDENTIFIER_NODE, 
+ 		      20020808);
+ 
    specbits = *specbits_in;
  
!   /* Compute the scope in which to place the variable.  */
!   if (!scope)
      {
!       /* An explicit "extern" specifier indicates a namespace-scope
! 	 variable.  */
!       if (RIDBIT_SETP (RID_EXTERN, specbits))
! 	scope = current_namespace;
!       else if (!at_function_scope_p ())
! 	{
! 	  scope = current_scope ();
! 	  if (!scope)
! 	    scope = current_namespace;
! 	}
      }
  
!   if (scope
!       && (/* If the variable is a namespace-scope variable declared in a
! 	     template, we need DECL_LANG_SPECIFIC.  */
! 	  (TREE_CODE (scope) == NAMESPACE_DECL && processing_template_decl)
! 	  /* Similarly for namespace-scope variables with language linkage
! 	     other than C++.  */
! 	  || (TREE_CODE (scope) == NAMESPACE_DECL 
! 	      && current_lang_name != lang_name_cplusplus)
! 	  /* Similarly for static data members.  */
! 	  || TYPE_P (scope)))
!     decl = build_lang_decl (VAR_DECL, name, type);
!   else
!     decl = build_decl (VAR_DECL, name, type);
  
!   if (scope && TREE_CODE (scope) == NAMESPACE_DECL)
!     set_decl_namespace (decl, scope, 0);
!   else
!     DECL_CONTEXT (decl) = scope;
  
!   if (name && scope && current_lang_name != lang_name_c)
!     /* We can't mangle lazily here because we don't have any
!        way to recover whether or not a variable was `extern
!        "C"' later.  */
!     mangle_decl (decl);
  
    if (RIDBIT_SETP (RID_EXTERN, specbits))
      {
*************** build_ptrmemfunc_type (type)
*** 9320,9325 ****
--- 9324,9337 ----
    return t;
  }
  
+ /* Create and return a pointer to data member type.  */
+ 
+ tree
+ build_ptrmem_type (tree class_type, tree member_type)
+ {
+   return build_pointer_type (build_offset_type (class_type, member_type));
+ }
+ 
  /* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
     Check to see that the definition is valid.  Issue appropriate error
     messages.  Return 1 if the definition is particularly bad, or 0
*************** grokdeclarator (declarator, declspecs, d
*** 9811,9816 ****
--- 9823,9834 ----
  
  		tree attributes;
  
+ 		if (decl_context != NORMAL)
+ 		  {
+ 		    error ("variable declaration is not allowed here");
+ 		    return error_mark_node;
+ 		  }
+ 
  		*next = TREE_OPERAND (decl, 0);
  		init = CALL_DECLARATOR_PARMS (decl);
  
*************** grokdeclarator (declarator, declspecs, d
*** 9835,9841 ****
  		  }
  		else
  		  error ("invalid declarator");
! 		return 0;
  	      }
  	    innermost_code = TREE_CODE (decl);
  	    if (decl_context == FIELD && ctype == NULL_TREE)
--- 9853,9859 ----
  		  }
  		else
  		  error ("invalid declarator");
! 		return NULL_TREE;
  	      }
  	    innermost_code = TREE_CODE (decl);
  	    if (decl_context == FIELD && ctype == NULL_TREE)
*************** grokdeclarator (declarator, declspecs, d
*** 10580,10586 ****
  
    /* Now figure out the structure of the declarator proper.
       Descend through it, creating more complex types, until we reach
!      the declared identifier (or NULL_TREE, in an absolute declarator).  */
  
    while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
  	 && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
--- 10598,10604 ----
  
    /* Now figure out the structure of the declarator proper.
       Descend through it, creating more complex types, until we reach
!      the declared identifier (or NULL_TREE, in an abstract declarator).  */
  
    while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
  	 && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
*************** grokdeclarator (declarator, declspecs, d
*** 10892,10900 ****
  	      continue;
  	    }
  
! 	  if (TREE_CODE (type) == OFFSET_TYPE
! 	      && (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE
! 		  || TREE_CODE (TREE_TYPE (type)) == REFERENCE_TYPE))
  	    {
  	      error ("cannot declare pointer to `%#T' member",
  			TREE_TYPE (type));
--- 10910,10918 ----
  	      continue;
  	    }
  
! 	  if (ctype
! 	      && (TREE_CODE (type) == VOID_TYPE
! 		  || TREE_CODE (type) == REFERENCE_TYPE))
  	    {
  	      error ("cannot declare pointer to `%#T' member",
  			TREE_TYPE (type));
*************** grokdeclarator (declarator, declspecs, d
*** 10917,10922 ****
--- 10935,10942 ----
  	    }
  	  else if (TREE_CODE (type) == METHOD_TYPE)
  	    type = build_ptrmemfunc_type (build_pointer_type (type));
+ 	  else if (ctype)
+ 	    type = build_ptrmem_type (ctype, type);
  	  else
  	    type = build_pointer_type (type);
  
*************** grokdeclarator (declarator, declspecs, d
*** 11102,11108 ****
  				  ctype, name, current_class_type);
  			return void_type_node;
  		      }
- 		    type = build_offset_type (ctype, type);
  		  }
  		else
  	          {
--- 11122,11127 ----
*************** grokdeclarator (declarator, declspecs, d
*** 11121,11134 ****
  		if (declarator && TREE_CODE (declarator) == CALL_EXPR)
  		  /* In this case, we will deal with it later.  */
  		  ;
! 		else
! 		  {
! 		    if (TREE_CODE (type) == FUNCTION_TYPE)
! 		      type = build_cplus_method_type (ctype, TREE_TYPE (type),
! 						      TYPE_ARG_TYPES (type));
! 		    else
! 		      type = build_offset_type (ctype, type);
! 		  }
  	      }
  	  }
  	  break;
--- 11140,11148 ----
  		if (declarator && TREE_CODE (declarator) == CALL_EXPR)
  		  /* In this case, we will deal with it later.  */
  		  ;
! 		else if (TREE_CODE (type) == FUNCTION_TYPE)
! 		  type = build_cplus_method_type (ctype, TREE_TYPE (type),
! 						  TYPE_ARG_TYPES (type));
  	      }
  	  }
  	  break;
*************** friend declaration requires class-key, i
*** 11846,11852 ****
  	decl = grokvardecl (type, declarator, &specbits,
  			    initialized,
  			    (type_quals & TYPE_QUAL_CONST) != 0,
! 			    in_namespace);
  	bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
  			inlinep, friendp, raises != NULL_TREE);
  
--- 11860,11866 ----
  	decl = grokvardecl (type, declarator, &specbits,
  			    initialized,
  			    (type_quals & TYPE_QUAL_CONST) != 0,
! 			    ctype ? ctype : in_namespace);
  	bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
  			inlinep, friendp, raises != NULL_TREE);
  
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v
retrieving revision 1.275
diff -c -p -r1.275 parse.y
*** cp/parse.y	8 Aug 2002 05:48:36 -0000	1.275
--- cp/parse.y	9 Aug 2002 19:45:24 -0000
*************** parse_finish_call_expr (tree fn, tree ar
*** 4156,4177 ****
  				  BASELINK_FUNCTIONS (fn),
  				  template_args);
  		}
! 	      if (BASELINK_P (fn) 
! 		  && current_class_type 
! 		  && DERIVED_FROM_P (scope, current_class_type))
! 		{
! 		  scope = lookup_base (current_class_type, scope,
! 				       ba_ignore | ba_quiet, NULL);
! 		  if (scope)
! 		    {
! 		      BASELINK_ACCESS_BINFO (fn) = scope;
! 		      BASELINK_BINFO (fn) 
! 			= lookup_base (scope,
! 				       BINFO_TYPE (BASELINK_BINFO (fn)),
! 				       ba_ignore | ba_quiet,
! 				       NULL);
! 		    }
! 		}
  	    }
  	}
        disallow_virtual = true;
--- 4156,4164 ----
  				  BASELINK_FUNCTIONS (fn),
  				  template_args);
  		}
! 	      if (current_class_type)
! 		fn = (adjust_result_of_qualified_name_lookup 
! 		      (fn, scope, current_class_type));
  	    }
  	}
        disallow_virtual = true;
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.234
diff -c -p -r1.234 search.c
*** cp/search.c	8 Aug 2002 05:48:37 -0000	1.234
--- cp/search.c	9 Aug 2002 19:45:24 -0000
*************** lookup_fnfields_1 (type, name)
*** 1640,1645 ****
--- 1640,1689 ----
  
    return -1;
  }
+ 
+ /* DECL is the result of a qualified name lookup.  QUALIFYING_CLASS
+    was the class used to qualify the name.  CONTEXT_CLASS is the class
+    corresponding to the object in which DECL will be used.  Return a
+    possibly modified version of DECL that takes into account the
+    CONTEXT_CLASS.
+ 
+    In particular, consider an expression like `B::m' in the context of
+    a derived class `D'.  If `B::m' has been resolved to a BASELINK,
+    then the most derived class indicated by the BASELINK_BINFO will be
+    `B', not `D'.  This function makes that adjustment.  */
+ 
+ tree
+ adjust_result_of_qualified_name_lookup (tree decl, 
+ 					tree qualifying_class,
+ 					tree context_class)
+ {
+   my_friendly_assert (CLASS_TYPE_P (qualifying_class), 20020808);
+   my_friendly_assert (CLASS_TYPE_P (context_class), 20020808);
+ 
+   if (BASELINK_P (decl) 
+       && DERIVED_FROM_P (qualifying_class, context_class))
+     {
+       tree base;
+ 
+       /* Look for the QUALIFYING_CLASS as a base of the
+ 	 CONTEXT_CLASS.  If QUALIFYING_CLASS is ambiguous, we cannot
+ 	 be sure yet than an error has occurred; perhaps the function
+ 	 chosen by overload resolution will be static.  */
+       base = lookup_base (context_class, qualifying_class,
+ 			  ba_ignore | ba_quiet, NULL);
+       if (base)
+ 	{
+ 	  BASELINK_ACCESS_BINFO (decl) = base;
+ 	  BASELINK_BINFO (decl) 
+ 	    = lookup_base (base, BINFO_TYPE (BASELINK_BINFO (decl)),
+ 			   ba_ignore | ba_quiet,
+ 			   NULL);
+ 	}
+     }
+ 
+   return decl;
+ }
+ 
  
  /* Walk the class hierarchy dominated by TYPE.  FN is called for each
     type in the hierarchy, in a breadth-first preorder traversal.
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.419
diff -c -p -r1.419 typeck.c
*** cp/typeck.c	8 Aug 2002 21:28:40 -0000	1.419
--- cp/typeck.c	9 Aug 2002 19:45:25 -0000
*************** qualify_type_recursive (t1, t2)
*** 203,230 ****
    if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
        || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
      {
!       tree tt1 = TREE_TYPE (t1);
!       tree tt2 = TREE_TYPE (t2);
        tree b1;
        int type_quals;
        tree tgt;
        tree attributes = (*targetm.merge_type_attributes) (t1, t2);
  
!       if (TREE_CODE (tt1) == OFFSET_TYPE)
  	{
! 	  b1 = TYPE_OFFSET_BASETYPE (tt1);
! 	  tt1 = TREE_TYPE (tt1);
! 	  tt2 = TREE_TYPE (tt2);
  	}
        else
! 	b1 = NULL_TREE;
  
        type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
        tgt = qualify_type_recursive (tt1, tt2);
        tgt = cp_build_qualified_type (tgt, type_quals);
        if (b1)
! 	tgt = build_offset_type (b1, tgt);
!       t1 = build_pointer_type (tgt);
        t1 = build_type_attribute_variant (t1, attributes);
      }
    return t1;
--- 203,235 ----
    if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
        || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
      {
!       tree tt1;
!       tree tt2;
        tree b1;
        int type_quals;
        tree tgt;
        tree attributes = (*targetm.merge_type_attributes) (t1, t2);
  
!       if (TYPE_PTRMEM_P (t1))
  	{
! 	  b1 = TYPE_PTRMEM_CLASS_TYPE (t1);
! 	  tt1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
! 	  tt2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
  	}
        else
! 	{
! 	  b1 = NULL_TREE;
! 	  tt1 = TREE_TYPE (t1);
! 	  tt2 = TREE_TYPE (t2);
! 	}
  
        type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
        tgt = qualify_type_recursive (tt1, tt2);
        tgt = cp_build_qualified_type (tgt, type_quals);
        if (b1)
! 	t1 = build_ptrmem_type (b1, tgt);
!       else
! 	t1 = build_pointer_type (tgt);
        t1 = build_type_attribute_variant (t1, attributes);
      }
    return t1;
*************** unary_complex_lvalue (code, arg)
*** 4390,4398 ****
  	      return error_mark_node;
  	    }
  
! 	  type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
! 	  type = build_pointer_type (type);
! 
  	  t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
  	  return t;
  	}
--- 4395,4401 ----
  	      return error_mark_node;
  	    }
  
! 	  type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
  	  t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
  	  return t;
  	}
Index: testsuite/g++.dg/template/crash1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/crash1.C,v
retrieving revision 1.1
diff -c -p -r1.1 crash1.C
*** testsuite/g++.dg/template/crash1.C	29 Dec 2001 17:12:55 -0000	1.1
--- testsuite/g++.dg/template/crash1.C	9 Aug 2002 19:45:27 -0000
***************
*** 1,7 ****
  // { dg-do compile }
  
! // Copyright (C) 2001 Free Software Foundation, Inc.
! // Contributed by Nathan Sidwell 29 Dec 2001 <nathan@nathan@codesourcery.com>
  
  // PR 5125. ICE
  
--- 1,7 ----
  // { dg-do compile }
  
! // Copyright (C) 2001, 2002 Free Software Foundation, Inc.
! // Contributed by Nathan Sidwell 29 Dec 2001 <nathan@codesourcery.com>
  
  // PR 5125. ICE
  
*************** class S
*** 13,17 ****
  
  template <class I>
  void S::Foo(int (*f)(TYPO&o) )
! { // { dg-error "template definition of non-template|prototype" "" }
  }
--- 13,17 ----
  
  template <class I>
  void S::Foo(int (*f)(TYPO&o) )
! { // { dg-error "template definition|variable declaration|prototype" "" }
  }


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