FreeBSD/contrib/gcc/cp/typeck.c
/* This handles expressions of the form "a[i]", which denotes
   an array reference.

   This is logically equivalent in C to *(a+i), but we may do it differently.
   If A is a variable or a member, we generate a primitive ARRAY_REF.
   This avoids forcing the array out of registers, and can work on
   arrays that are not lvalues (for example, members of structures returned
   by functions).

   If INDEX is of some user-defined type, it must be converted to
   integer type.  Otherwise, to make a compatible PLUS_EXPR, it
   will inherit the type of the array, which will be some pointer type.  */
This handles expressions of the form "a[i]", which denotes
an array reference.

This is logically equivalent in C to *(a+i), but we may do it differently.
If A is a variable or a member, we generate a primitive ARRAY_REF.
This avoids forcing the array out of registers, and can work on
arrays that are not lvalues (for example, members of structures returned
by functions).

If INDEX is of some user-defined type, it must be converted to
integer type.  Otherwise, to make a compatible PLUS_EXPR, it
will inherit the type of the array, which will be some pointer type.
This handles expressions of the form " a [ i ] " which denotes an array reference . This is logically equivalent in C to * ( a + i ) but we may do it differently . If A is a variable or a member we generate a primitive ARRAY_REF . This avoids forcing the array out of registers and can work on arrays that are not lvalues ( for example members of structures returned by functions ) . If INDEX is of some user - defined type it must be converted to integer type . Otherwise to make a compatible PLUS_EXPR it will inherit the type of the array which will be some pointer type .
tree
build_array_ref (tree array, tree idx)
{
  if (idx == 0)
    {
      error ("subscript missing in array reference");
      return error_mark_node;
    }
  if (TREE_TYPE (array) == error_mark_node
      || TREE_TYPE (idx) == error_mark_node)
    return error_mark_node;
  switch (TREE_CODE (array))
    {
    case COMPOUND_EXPR:
      {
	tree value = build_array_ref (TREE_OPERAND (array, 1), idx);
	return build2 (COMPOUND_EXPR, TREE_TYPE (value),
		       TREE_OPERAND (array, 0), value);
      }
    case COND_EXPR:
      return build_conditional_expr
	(TREE_OPERAND (array, 0),
	 build_array_ref (TREE_OPERAND (array, 1), idx),
	 build_array_ref (TREE_OPERAND (array, 2), idx));
    default:
      break;
    }
  if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
    {
      tree rval, type;
      warn_array_subscript_with_type_char (idx);
      if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
	{
	  error ("array subscript is not an integer");
	  return error_mark_node;
	}
      idx = perform_integral_promotions (idx);
      if (TREE_CODE (idx) != INTEGER_CST
	  || (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (array)))
	      && (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
		  != INTEGER_CST)))
	{
	  if (!cxx_mark_addressable (array))
	    return error_mark_node;
	}
      if (TREE_CODE (idx) == INTEGER_CST
	  && TYPE_DOMAIN (TREE_TYPE (array))
	  && ! int_fits_type_p (idx, TYPE_DOMAIN (TREE_TYPE (array))))
	{
	  if (!cxx_mark_addressable (array))
	    return error_mark_node;
	}
      if (pedantic && !lvalue_p (array))
	pedwarn ("ISO C++ forbids subscripting non-lvalue array");
      if (extra_warnings)
	{
	  tree foo = array;
	  while (TREE_CODE (foo) == COMPONENT_REF)
	    foo = TREE_OPERAND (foo, 0);
	  if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
	    warning (OPT_Wextra, "subscripting array declared %<register%>");
	}
      type = TREE_TYPE (TREE_TYPE (array));
      rval = build4 (ARRAY_REF, type, array, idx, NULL_TREE, NULL_TREE);
      TREE_READONLY (rval)
	|= (CP_TYPE_CONST_P (type) | TREE_READONLY (array));
      TREE_SIDE_EFFECTS (rval)
	|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
      TREE_THIS_VOLATILE (rval)
	|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
      return require_complete_type (fold_if_not_in_template (rval));
    }
  {
    tree ar = default_conversion (array);
    tree ind = default_conversion (idx);
    if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
      {
	tree temp = ar;
	ar = ind;
	ind = temp;
      }
    if (ar == error_mark_node)
      return ar;
    if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE)
      {
	error ("subscripted value is neither array nor pointer");
	return error_mark_node;
      }
    if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)
      {
	error ("array subscript is not an integer");
	return error_mark_node;
      }
    return build_indirect_ref (cp_build_binary_op (PLUS_EXPR, ar, ind),
			       "array indexing");
  }
}
tree build_array_ref ( tree array , tree idx ) { if ( idx == 0 ) { error ( " " ) ; return error_mark_node ; } if ( TREE_TYPE ( array ) == error_mark_node || TREE_TYPE ( idx ) == error_mark_node ) return error_mark_node ; switch ( TREE_CODE ( array ) ) { case COMPOUND_EXPR : { tree value = build_array_ref ( TREE_OPERAND ( array , 1 ) , idx ) ; return build2 ( COMPOUND_EXPR , TREE_TYPE ( value ) , TREE_OPERAND ( array , 0 ) , value ) ; } case COND_EXPR : return build_conditional_expr ( TREE_OPERAND ( array , 0 ) , build_array_ref ( TREE_OPERAND ( array , 1 ) , idx ) , build_array_ref ( TREE_OPERAND ( array , 2 ) , idx ) ) ; default : break ; } if ( TREE_CODE ( TREE_TYPE ( array ) ) == ARRAY_TYPE ) { tree rval , type ; warn_array_subscript_with_type_char ( idx ) ; if ( ! INTEGRAL_OR_ENUMERATION_TYPE_P ( TREE_TYPE ( idx ) ) ) { error ( " " ) ; return error_mark_node ; } idx = perform_integral_promotions ( idx ) ; if ( TREE_CODE ( idx ) != INTEGER_CST || ( COMPLETE_TYPE_P ( TREE_TYPE ( TREE_TYPE ( array ) ) ) && ( TREE_CODE ( TYPE_SIZE ( TREE_TYPE ( TREE_TYPE ( array ) ) ) ) != INTEGER_CST ) ) ) { if ( ! cxx_mark_addressable ( array ) ) return error_mark_node ; } if ( TREE_CODE ( idx ) == INTEGER_CST && TYPE_DOMAIN ( TREE_TYPE ( array ) ) && ! int_fits_type_p ( idx , TYPE_DOMAIN ( TREE_TYPE ( array ) ) ) ) { if ( ! cxx_mark_addressable ( array ) ) return error_mark_node ; } if ( pedantic && ! lvalue_p ( array ) ) pedwarn ( " " ) ; if ( extra_warnings ) { tree foo = array ; while ( TREE_CODE ( foo ) == COMPONENT_REF ) foo = TREE_OPERAND ( foo , 0 ) ; if ( TREE_CODE ( foo ) == VAR_DECL && DECL_REGISTER ( foo ) ) warning ( OPT_Wextra , " " ) ; } type = TREE_TYPE ( TREE_TYPE ( array ) ) ; rval = build4 ( ARRAY_REF , type , array , idx , NULL_TREE , NULL_TREE ) ; TREE_READONLY ( rval ) |= ( CP_TYPE_CONST_P ( type ) | TREE_READONLY ( array ) ) ; TREE_SIDE_EFFECTS ( rval ) |= ( CP_TYPE_VOLATILE_P ( type ) | TREE_SIDE_EFFECTS ( array ) ) ; TREE_THIS_VOLATILE ( rval ) |= ( CP_TYPE_VOLATILE_P ( type ) | TREE_THIS_VOLATILE ( array ) ) ; return require_complete_type ( fold_if_not_in_template ( rval ) ) ; } { tree ar = default_conversion ( array ) ; tree ind = default_conversion ( idx ) ; if ( TREE_CODE ( TREE_TYPE ( ar ) ) == INTEGER_TYPE ) { tree temp = ar ; ar = ind ; ind = temp ; } if ( ar == error_mark_node ) return ar ; if ( TREE_CODE ( TREE_TYPE ( ar ) ) != POINTER_TYPE ) { error ( " " ) ; return error_mark_node ; } if ( TREE_CODE ( TREE_TYPE ( ind ) ) != INTEGER_TYPE ) { error ( " " ) ; return error_mark_node ; } return build_indirect_ref ( cp_build_binary_op ( PLUS_EXPR , ar , ind ) , " " ) ; } }
This handles expressions of the form "a[i]", which denotes
an array reference.
This handles expressions of the form " a [ i ] " which denotes an array reference .
/* If ARRAY is a COMPOUND_EXPR or COND_EXPR, move our reference
     inside it.  */ /* Apply integral promotions *after* noticing character types.
	 (It is unclear why we do these promotions -- the standard
	 does not say that we should.  In fact, the natural thing would
	 seem to be to convert IDX to ptrdiff_t; we're performing
	 pointer arithmetic.)  */ /* An array that is indexed by a non-constant
	 cannot be stored in a register; we must be able to do
	 address arithmetic on its address.
	 Likewise an array of elements of variable size.  */ /* An array that is indexed by a constant value which is not within
	 the array bounds cannot be stored in a register either; because we
	 would get a crash in store_bit_field/extract_bit_field when trying
	 to access a non-existent part of the register.  */ /* Note in C++ it is valid to subscript a `register' array, since
	 it is valid to take the address of something with that
	 storage specification.  */ /* Array ref is const/volatile if the array elements are
	 or if the array is..  */ /* Put the integer in IND to simplify error checking.  */