FreeBSD/contrib/gcc/cp/typeck.c
/* Build a constructor for a pointer to member function.  It can be
   used to initialize global variables, local variable, or used
   as a value in expressions.  TYPE is the POINTER to METHOD_TYPE we
   want to be.

   If FORCE is nonzero, then force this conversion, even if
   we would rather not do it.  Usually set when using an explicit
   cast.  A C-style cast is being processed iff C_CAST_P is true.

   Return error_mark_node, if something goes wrong.  */
Build a constructor for a pointer to member function.  It can be
used to initialize global variables, local variable, or used
as a value in expressions.  TYPE is the POINTER to METHOD_TYPE we
want to be.

If FORCE is nonzero, then force this conversion, even if
we would rather not do it.  Usually set when using an explicit
cast.  A C-style cast is being processed iff C_CAST_P is true.

Return error_mark_node, if something goes wrong.
Build a constructor for a pointer to member function . It can be used to initialize global variables local variable or used as a value in expressions . TYPE is the POINTER to METHOD_TYPE we want to be . If FORCE is nonzero then force this conversion even if we would rather not do it . Usually set when using an explicit cast . A C - style cast is being processed iff C_CAST_P is true . Return error_mark_node if something goes wrong .
tree
build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
{
  tree fn;
  tree pfn_type;
  tree to_type;
  if (error_operand_p (pfn))
    return error_mark_node;
  pfn_type = TREE_TYPE (pfn);
  to_type = build_ptrmemfunc_type (type);
  if (TYPE_PTRMEMFUNC_P (pfn_type))
    {
      tree delta = NULL_TREE;
      tree npfn = NULL_TREE;
      tree n;
      if (!force
	  && !can_convert_arg (to_type, TREE_TYPE (pfn), pfn, LOOKUP_NORMAL))
	error ("invalid conversion to type %qT from type %qT",
	       to_type, pfn_type);
      n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
				TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
				force,
				c_cast_p);
      if (TREE_CODE (pfn) != PTRMEM_CST)
	{
	  if (same_type_p (to_type, pfn_type))
	    return pfn;
	  else if (integer_zerop (n))
	    return build_reinterpret_cast (to_type, pfn);
	}
      if (TREE_SIDE_EFFECTS (pfn))
	pfn = save_expr (pfn);
      if (TREE_CODE (pfn) == PTRMEM_CST)
	expand_ptrmemfunc_cst (pfn, &delta, &npfn);
      else
	{
	  npfn = build_ptrmemfunc_access_expr (pfn, pfn_identifier);
	  delta = build_ptrmemfunc_access_expr (pfn, delta_identifier);
	}
      gcc_assert  (same_type_ignoring_top_level_qualifiers_p
		   (TREE_TYPE (delta), ptrdiff_type_node));
      if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
	n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node);
      delta = cp_build_binary_op (PLUS_EXPR, delta, n);
      return build_ptrmemfunc1 (to_type, delta, npfn);
    }
  if (integer_zerop (pfn))
    {
      pfn = build_c_cast (type, integer_zero_node);
      return build_ptrmemfunc1 (to_type,
				integer_zero_node,
				pfn);
    }
  if (type_unknown_p (pfn))
    return instantiate_type (type, pfn, tf_warning_or_error);
  fn = TREE_OPERAND (pfn, 0);
  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
	      || (processing_template_decl && TREE_CODE (fn) == OFFSET_REF));
  return make_ptrmem_cst (to_type, fn);
}
tree build_ptrmemfunc ( tree type , tree pfn , int force , bool c_cast_p ) { tree fn ; tree pfn_type ; tree to_type ; if ( error_operand_p ( pfn ) ) return error_mark_node ; pfn_type = TREE_TYPE ( pfn ) ; to_type = build_ptrmemfunc_type ( type ) ; if ( TYPE_PTRMEMFUNC_P ( pfn_type ) ) { tree delta = NULL_TREE ; tree npfn = NULL_TREE ; tree n ; if ( ! force && ! can_convert_arg ( to_type , TREE_TYPE ( pfn ) , pfn , LOOKUP_NORMAL ) ) error ( " " , to_type , pfn_type ) ; n = get_delta_difference ( TYPE_PTRMEMFUNC_OBJECT_TYPE ( pfn_type ) , TYPE_PTRMEMFUNC_OBJECT_TYPE ( to_type ) , force , c_cast_p ) ; if ( TREE_CODE ( pfn ) != PTRMEM_CST ) { if ( same_type_p ( to_type , pfn_type ) ) return pfn ; else if ( integer_zerop ( n ) ) return build_reinterpret_cast ( to_type , pfn ) ; } if ( TREE_SIDE_EFFECTS ( pfn ) ) pfn = save_expr ( pfn ) ; if ( TREE_CODE ( pfn ) == PTRMEM_CST ) expand_ptrmemfunc_cst ( pfn , & delta , & npfn ) ; else { npfn = build_ptrmemfunc_access_expr ( pfn , pfn_identifier ) ; delta = build_ptrmemfunc_access_expr ( pfn , delta_identifier ) ; } gcc_assert ( same_type_ignoring_top_level_qualifiers_p ( TREE_TYPE ( delta ) , ptrdiff_type_node ) ) ; if ( TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta ) n = cp_build_binary_op ( LSHIFT_EXPR , n , integer_one_node ) ; delta = cp_build_binary_op ( PLUS_EXPR , delta , n ) ; return build_ptrmemfunc1 ( to_type , delta , npfn ) ; } if ( integer_zerop ( pfn ) ) { pfn = build_c_cast ( type , integer_zero_node ) ; return build_ptrmemfunc1 ( to_type , integer_zero_node , pfn ) ; } if ( type_unknown_p ( pfn ) ) return instantiate_type ( type , pfn , tf_warning_or_error ) ; fn = TREE_OPERAND ( pfn , 0 ) ; gcc_assert ( TREE_CODE ( fn ) == FUNCTION_DECL || ( processing_template_decl && TREE_CODE ( fn ) == OFFSET_REF ) ) ; return make_ptrmem_cst ( to_type , fn ) ; }
Build a constructor for a pointer to member function.
Build a constructor for a pointer to member function .
/* Handle multiple conversions of pointer to member functions.  */ /* We don't have to do any conversion to convert a
	 pointer-to-member to its own type.  But, we don't want to
	 just return a PTRMEM_CST if there's an explicit cast; that
	 cast should make the expression an invalid template argument.  */ /* Obtain the function pointer and the current DELTA.  */ /* Just adjust the DELTA field.  */ /* Handle null pointer to member function conversions.  */ /* In a template, we will have preserved the
		 OFFSET_REF.  */