FreeBSD/contrib/gcc/cp/typeck.c
/* Build an expression representing OBJECT.MEMBER.  OBJECT is an
   expression; MEMBER is a DECL or baselink.  If ACCESS_PATH is
   non-NULL, it indicates the path to the base used to name MEMBER.
   If PRESERVE_REFERENCE is true, the expression returned will have
   REFERENCE_TYPE if the MEMBER does.  Otherwise, the expression
   returned will have the type referred to by the reference.

   This function does not perform access control; that is either done
   earlier by the parser when the name of MEMBER is resolved to MEMBER
   itself, or later when overload resolution selects one of the
   functions indicated by MEMBER.  */
Build an expression representing OBJECT.MEMBER.  OBJECT is an
expression; MEMBER is a DECL or baselink.  If ACCESS_PATH is
non-NULL, it indicates the path to the base used to name MEMBER.
If PRESERVE_REFERENCE is true, the expression returned will have
REFERENCE_TYPE if the MEMBER does.  Otherwise, the expression
returned will have the type referred to by the reference.

This function does not perform access control; that is either done
earlier by the parser when the name of MEMBER is resolved to MEMBER
itself, or later when overload resolution selects one of the
functions indicated by MEMBER.
Build an expression representing OBJECT . MEMBER . OBJECT is an expression ; MEMBER is a DECL or baselink . If ACCESS_PATH is non - NULL it indicates the path to the base used to name MEMBER . If PRESERVE_REFERENCE is true the expression returned will have REFERENCE_TYPE if the MEMBER does . Otherwise the expression returned will have the type referred to by the reference . This function does not perform access control ; that is either done earlier by the parser when the name of MEMBER is resolved to MEMBER itself or later when overload resolution selects one of the functions indicated by MEMBER .
tree
build_class_member_access_expr (tree object, tree member,
				tree access_path, bool preserve_reference)
{
  tree object_type;
  tree member_scope;
  tree result = NULL_TREE;
  if (error_operand_p (object) || error_operand_p (member))
    return error_mark_node;
  gcc_assert (DECL_P (member) || BASELINK_P (member));
  object_type = TREE_TYPE (object);
  if (!currently_open_class (object_type)
      && !complete_type_or_else (object_type, object))
    return error_mark_node;
  if (!CLASS_TYPE_P (object_type))
    {
      error ("request for member %qD in %qE, which is of non-class type %qT",
	     member, object, object_type);
      return error_mark_node;
    }
  if (DECL_P (member))
    {
      member_scope = DECL_CLASS_CONTEXT (member);
      mark_used (member);
      if (TREE_DEPRECATED (member))
	warn_deprecated_use (member);
    }
  else
    member_scope = BINFO_TYPE (BASELINK_BINFO (member));
  while (ANON_AGGR_TYPE_P (member_scope)
	 && !same_type_ignoring_top_level_qualifiers_p (member_scope,
							object_type))
    member_scope = TYPE_CONTEXT (member_scope);
  if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
    {
      if (TREE_CODE (member) == FIELD_DECL)
	error ("invalid use of nonstatic data member %qE", member);
      else
	error ("%qD is not a member of %qT", member, object_type);
      return error_mark_node;
    }
  {
    tree temp = unary_complex_lvalue (ADDR_EXPR, object);
    if (temp)
      object = build_indirect_ref (temp, NULL);
  }
  if (TREE_CODE (member) == VAR_DECL)
    {
      result = member;
      if (TREE_SIDE_EFFECTS (object))
	result = build2 (COMPOUND_EXPR, TREE_TYPE (result), object, result);
    }
  else if (TREE_CODE (member) == FIELD_DECL)
    {
      bool null_object_p;
      int type_quals;
      tree member_type;
      null_object_p = (TREE_CODE (object) == INDIRECT_REF
		       && integer_zerop (TREE_OPERAND (object, 0)));
      if (!same_type_p (TYPE_MAIN_VARIANT (object_type),
			TYPE_MAIN_VARIANT (member_scope)))
	{
	  tree binfo;
	  base_kind kind;
	  binfo = lookup_base (access_path ? access_path : object_type,
			       member_scope, ba_unique,  &kind);
	  if (binfo == error_mark_node)
	    return error_mark_node;
	  if (null_object_p && kind == bk_via_virtual)
	    {
	      error ("invalid access to non-static data member %qD of "
		     "NULL object",
		     member);
	      error ("(perhaps the %<offsetof%> macro was used incorrectly)");
	      return error_mark_node;
	    }
	  object = build_base_path (PLUS_EXPR, object, binfo,
				    1);
	  gcc_assert (object != error_mark_node);
	}
      if (null_object_p && warn_invalid_offsetof
	  && CLASSTYPE_NON_POD_P (object_type)
	  && !DECL_FIELD_IS_BASE (member)
	  && !skip_evaluation)
	{
	  warning (0, "invalid access to non-static data member %qD of NULL object",
		   member);
	  warning (0, "(perhaps the %<offsetof%> macro was used incorrectly)");
	}
      if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
	  && (!same_type_ignoring_top_level_qualifiers_p
	      (TREE_TYPE (object), DECL_CONTEXT (member))))
	{
	  tree anonymous_union;
	  anonymous_union = lookup_anon_field (TREE_TYPE (object),
					       DECL_CONTEXT (member));
	  object = build_class_member_access_expr (object,
						   anonymous_union,
						   NULL_TREE,
						   preserve_reference);
	}
      type_quals = TYPE_UNQUALIFIED;
      member_type = TREE_TYPE (member);
      if (TREE_CODE (member_type) != REFERENCE_TYPE)
	{
	  type_quals = (cp_type_quals (member_type)
			| cp_type_quals (object_type));
	  if (DECL_MUTABLE_P (member))
	    type_quals &= ~TYPE_QUAL_CONST;
	  member_type = cp_build_qualified_type (member_type, type_quals);
	}
      result = build3 (COMPONENT_REF, member_type, object, member,
		       NULL_TREE);
      result = fold_if_not_in_template (result);
      if (type_quals & TYPE_QUAL_CONST)
	TREE_READONLY (result) = 1;
      if (type_quals & TYPE_QUAL_VOLATILE)
	TREE_THIS_VOLATILE (result) = 1;
    }
  else if (BASELINK_P (member))
    {
      tree functions;
      tree type;
      functions = BASELINK_FUNCTIONS (member);
      if (TREE_CODE (functions) == FUNCTION_DECL
	  && DECL_STATIC_FUNCTION_P (functions))
	type = TREE_TYPE (functions);
      else
	type = unknown_type_node;
      result = build3 (COMPONENT_REF, type, object, member, NULL_TREE);
    }
  else if (TREE_CODE (member) == CONST_DECL)
    {
      result = member;
      if (TREE_SIDE_EFFECTS (object))
	result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
			 object, result);
    }
  else
    {
      error ("invalid use of %qD", member);
      return error_mark_node;
    }
  if (!preserve_reference)
    result = convert_from_reference (result);
  return result;
}
tree build_class_member_access_expr ( tree object , tree member , tree access_path , bool preserve_reference ) { tree object_type ; tree member_scope ; tree result = NULL_TREE ; if ( error_operand_p ( object ) || error_operand_p ( member ) ) return error_mark_node ; gcc_assert ( DECL_P ( member ) || BASELINK_P ( member ) ) ; object_type = TREE_TYPE ( object ) ; if ( ! currently_open_class ( object_type ) && ! complete_type_or_else ( object_type , object ) ) return error_mark_node ; if ( ! CLASS_TYPE_P ( object_type ) ) { error ( " " , member , object , object_type ) ; return error_mark_node ; } if ( DECL_P ( member ) ) { member_scope = DECL_CLASS_CONTEXT ( member ) ; mark_used ( member ) ; if ( TREE_DEPRECATED ( member ) ) warn_deprecated_use ( member ) ; } else member_scope = BINFO_TYPE ( BASELINK_BINFO ( member ) ) ; while ( ANON_AGGR_TYPE_P ( member_scope ) && ! same_type_ignoring_top_level_qualifiers_p ( member_scope , object_type ) ) member_scope = TYPE_CONTEXT ( member_scope ) ; if ( ! member_scope || ! DERIVED_FROM_P ( member_scope , object_type ) ) { if ( TREE_CODE ( member ) == FIELD_DECL ) error ( " " , member ) ; else error ( " " , member , object_type ) ; return error_mark_node ; } { tree temp = unary_complex_lvalue ( ADDR_EXPR , object ) ; if ( temp ) object = build_indirect_ref ( temp , NULL ) ; } if ( TREE_CODE ( member ) == VAR_DECL ) { result = member ; if ( TREE_SIDE_EFFECTS ( object ) ) result = build2 ( COMPOUND_EXPR , TREE_TYPE ( result ) , object , result ) ; } else if ( TREE_CODE ( member ) == FIELD_DECL ) { bool null_object_p ; int type_quals ; tree member_type ; null_object_p = ( TREE_CODE ( object ) == INDIRECT_REF && integer_zerop ( TREE_OPERAND ( object , 0 ) ) ) ; if ( ! same_type_p ( TYPE_MAIN_VARIANT ( object_type ) , TYPE_MAIN_VARIANT ( member_scope ) ) ) { tree binfo ; base_kind kind ; binfo = lookup_base ( access_path ? access_path : object_type , member_scope , ba_unique , & kind ) ; if ( binfo == error_mark_node ) return error_mark_node ; if ( null_object_p && kind == bk_via_virtual ) { error ( " " " " , member ) ; error ( " " ) ; return error_mark_node ; } object = build_base_path ( PLUS_EXPR , object , binfo , 1 ) ; gcc_assert ( object != error_mark_node ) ; } if ( null_object_p && warn_invalid_offsetof && CLASSTYPE_NON_POD_P ( object_type ) && ! DECL_FIELD_IS_BASE ( member ) && ! skip_evaluation ) { warning ( 0 , " " , member ) ; warning ( 0 , " " ) ; } if ( ANON_AGGR_TYPE_P ( DECL_CONTEXT ( member ) ) && ( ! same_type_ignoring_top_level_qualifiers_p ( TREE_TYPE ( object ) , DECL_CONTEXT ( member ) ) ) ) { tree anonymous_union ; anonymous_union = lookup_anon_field ( TREE_TYPE ( object ) , DECL_CONTEXT ( member ) ) ; object = build_class_member_access_expr ( object , anonymous_union , NULL_TREE , preserve_reference ) ; } type_quals = TYPE_UNQUALIFIED ; member_type = TREE_TYPE ( member ) ; if ( TREE_CODE ( member_type ) != REFERENCE_TYPE ) { type_quals = ( cp_type_quals ( member_type ) | cp_type_quals ( object_type ) ) ; if ( DECL_MUTABLE_P ( member ) ) type_quals &= ~ TYPE_QUAL_CONST ; member_type = cp_build_qualified_type ( member_type , type_quals ) ; } result = build3 ( COMPONENT_REF , member_type , object , member , NULL_TREE ) ; result = fold_if_not_in_template ( result ) ; if ( type_quals & TYPE_QUAL_CONST ) TREE_READONLY ( result ) = 1 ; if ( type_quals & TYPE_QUAL_VOLATILE ) TREE_THIS_VOLATILE ( result ) = 1 ; } else if ( BASELINK_P ( member ) ) { tree functions ; tree type ; functions = BASELINK_FUNCTIONS ( member ) ; if ( TREE_CODE ( functions ) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P ( functions ) ) type = TREE_TYPE ( functions ) ; else type = unknown_type_node ; result = build3 ( COMPONENT_REF , type , object , member , NULL_TREE ) ; } else if ( TREE_CODE ( member ) == CONST_DECL ) { result = member ; if ( TREE_SIDE_EFFECTS ( object ) ) result = build2 ( COMPOUND_EXPR , TREE_TYPE ( result ) , object , result ) ; } else { error ( " " , member ) ; return error_mark_node ; } if ( ! preserve_reference ) result = convert_from_reference ( result ) ; return result ; }
Build an expression representing OBJECT.MEMBER.
Build an expression representing OBJECT . MEMBER .
/* [expr.ref]

     The type of the first expression shall be "class object" (of a
     complete type).  */ /* The standard does not seem to actually say that MEMBER must be a
     member of OBJECT_TYPE.  However, that is clearly what is
     intended.  */ /* If MEMBER is from an anonymous aggregate, MEMBER_SCOPE will
     presently be the anonymous union.  Go outwards until we find a
     type related to OBJECT_TYPE.  */ /* Transform `(a, b).x' into `(*(a, &b)).x', `(a ? b : c).x' into
     `(*(a ?  &b : &c)).x', and so on.  A COND_EXPR is only an lvalue
     in the frontend; only _DECLs and _REFs are lvalues in the backend.  */ /* In [expr.ref], there is an explicit list of the valid choices for
     MEMBER.  We check for each of those cases here.  */ /* A static data member.  */ /* If OBJECT has side-effects, they are supposed to occur.  */ /* A non-static data member.  */ /* Convert OBJECT to the type of MEMBER.  */ /* It is invalid to try to get to a virtual base of a
	     NULL object.  The most common cause is invalid use of
	     offsetof macro.  */ /* Convert to the base.  */ /*nonnull=*/ /* If we found the base successfully then we should be able
	     to convert to it successfully.  */ /* Complain about other invalid uses of offsetof, even though they will
	 give the right answer.  Note that we complain whether or not they
	 actually used the offsetof macro, since there's no way to know at this
	 point.  So we just give a warning, instead of a pedwarn.  */ /* Do not produce this warning for base class field references, because
	 we know for a fact that didn't come from offsetof.  This does occur
	 in various testsuite cases where a null object is passed where a
	 vtable access is required.  */ /* If MEMBER is from an anonymous aggregate, we have converted
	 OBJECT so that it refers to the class containing the
	 anonymous union.  Generate a reference to the anonymous union
	 itself, and recur to find MEMBER.  */ /* When this code is called from build_field_call, the
	     object already has the type of the anonymous union.
	     That is because the COMPONENT_REF was already
	     constructed, and was then disassembled before calling
	     build_field_call.  After the function-call code is
	     cleaned up, this waste can be eliminated.  */ /*access_path=*/ /* Compute the type of the field, as described in [expr.ref].  */ /* A field is const (volatile) if the enclosing object, or the
	     field itself, is const (volatile).  But, a mutable field is
	     not const, even within a const object.  */ /* Mark the expression const or volatile, as appropriate.  Even
	 though we've dealt with the type above, we still have to mark the
	 expression itself.  */ /* The member is a (possibly overloaded) member function.  */ /* If the MEMBER is exactly one static member function, then we
	 know the type of the expression.  Otherwise, we must wait
	 until overload resolution has been performed.  */ /* Note that we do not convert OBJECT to the BASELINK_BINFO
	 base.  That will happen when the function is called.  */ /* The member is an enumerator.  */ /* If OBJECT has side-effects, they are supposed to occur.  */ /* [expr.ref]

       If E2 is declared to have type "reference to T", then ... the
       type of E1.E2 is T.  */