/* Build expressions with type checking for C++ compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
/* This file is part of the C++ front end.
It contains routines to build C++ expressions given their operands,
including computing the types of the result, C and C++ specific error
- checks, and some optimization.
-
- There are also routines to build RETURN_STMT nodes and CASE_STMT nodes,
- and to process initializations in declarations (since they work
- like a strange sort of assignment). */
+ checks, and some optimization. */
#include "config.h"
#include "system.h"
static bool comp_except_types (tree, tree, bool);
static bool comp_array_types (tree, tree, bool);
static tree common_base_type (tree, tree);
-static tree lookup_anon_field (tree, tree);
static tree pointer_diff (tree, tree, tree);
static tree get_delta_difference (tree, tree, int);
static void casts_away_constness_r (tree *, tree *);
else
type = TREE_TYPE (value);
+ if (type == error_mark_node)
+ return error_mark_node;
+
/* First, detect a valid value with a complete type. */
if (COMPLETE_TYPE_P (type))
return value;
else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
{
tree t = complete_type (TREE_TYPE (type));
- if (COMPLETE_TYPE_P (t) && ! processing_template_decl)
+ if (COMPLETE_TYPE_P (t) && !dependent_type_p (type))
layout_type (type);
TYPE_NEEDS_CONSTRUCTING (type)
= TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
int
type_unknown_p (tree exp)
{
- return (TREE_CODE (exp) == OVERLOAD
- || TREE_CODE (exp) == TREE_LIST
+ return (TREE_CODE (exp) == TREE_LIST
|| TREE_TYPE (exp) == unknown_type_node);
}
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_long_integer_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_long_integer_type_node))
{
- tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ tree t = ((TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
? long_long_unsigned_type_node
: long_long_integer_type_node);
return build_type_attribute_variant (t, attributes);
if (same_type_p (TYPE_MAIN_VARIANT (t1), long_integer_type_node)
|| same_type_p (TYPE_MAIN_VARIANT (t2), long_integer_type_node))
{
- tree t = ((TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+ tree t = ((TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
? long_unsigned_type_node : long_integer_type_node);
return build_type_attribute_variant (t, attributes);
}
/* Otherwise prefer the unsigned one. */
- if (TREE_UNSIGNED (t1))
+ if (TYPE_UNSIGNED (t1))
return build_type_attribute_variant (t1, attributes);
else
return build_type_attribute_variant (t2, attributes);
result_type = cp_build_qualified_type (result_type,
(cp_type_quals (pointee1)
| cp_type_quals (pointee2)));
- result_type = build_pointer_type (result_type);
/* If the original types were pointers to members, so is the
result. */
if (TYPE_PTR_TO_MEMBER_P (t1))
result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
result_type);
}
+ else
+ result_type = build_pointer_type (result_type);
/* Merge the attributes. */
attributes = (*targetm.merge_type_attributes) (t1, t2);
tree
merge_types (tree t1, tree t2)
{
- register enum tree_code code1;
- register enum tree_code code2;
+ enum tree_code code1;
+ enum tree_code code2;
tree attributes;
/* Save time if the two types are the same. */
/* Save space: see if the result is identical to one of the args. */
if (valtype == TREE_TYPE (t1) && ! p2)
- return build_type_attribute_variant (t1, attributes);
+ return cp_build_type_attribute_variant (t1, attributes);
if (valtype == TREE_TYPE (t2) && ! p1)
- return build_type_attribute_variant (t2, attributes);
+ return cp_build_type_attribute_variant (t2, attributes);
/* Simple way if one arg fails to specify argument types. */
if (p1 == NULL_TREE || TREE_VALUE (p1) == void_type_node)
rval = build_function_type (valtype, p2);
if ((raises = TYPE_RAISES_EXCEPTIONS (t2)))
rval = build_exception_variant (rval, raises);
- return build_type_attribute_variant (rval, attributes);
+ return cp_build_type_attribute_variant (rval, attributes);
}
raises = TYPE_RAISES_EXCEPTIONS (t1);
if (p2 == NULL_TREE || TREE_VALUE (p2) == void_type_node)
rval = build_function_type (valtype, p1);
if (raises)
rval = build_exception_variant (rval, raises);
- return build_type_attribute_variant (rval, attributes);
+ return cp_build_type_attribute_variant (rval, attributes);
}
rval = build_function_type (valtype, commonparms (p1, p2));
break;
}
+ case TYPENAME_TYPE:
+ /* There is no need to merge attributes into a TYPENAME_TYPE.
+ When the type is instantiated it will have whatever
+ attributes result from the instantiation. */
+ return t1;
+
default:;
}
- return build_type_attribute_variant (t1, attributes);
+ return cp_build_type_attribute_variant (t1, attributes);
}
/* Return the common type of two types.
{
tree d1;
tree d2;
+ tree max1, max2;
if (t1 == t2)
return true;
return allow_redeclaration;
/* Check that the dimensions are the same. */
- return (cp_tree_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
- && cp_tree_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)));
+
+ if (!cp_tree_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)))
+ return false;
+ max1 = TYPE_MAX_VALUE (d1);
+ max2 = TYPE_MAX_VALUE (d2);
+ if (processing_template_decl && !abi_version_at_least (2)
+ && !value_dependent_expression_p (max1)
+ && !value_dependent_expression_p (max2))
+ {
+ /* With abi-1 we do not fold non-dependent array bounds, (and
+ consequently mangle them incorrectly). We must therefore
+ fold them here, to verify the domains have the same
+ value. */
+ max1 = fold (max1);
+ max2 = fold (max2);
+ }
+
+ if (!cp_tree_equal (max1, max2))
+ return false;
+
+ return true;
}
/* Return true if T1 and T2 are related as allowed by STRICT. STRICT
if (t1 == t2)
return true;
- /* Suppress errors caused by previously reported errors */
+ /* Suppress errors caused by previously reported errors. */
if (t1 == error_mark_node || t2 == error_mark_node)
return false;
/* If either type is the internal version of sizetype, use the
language version. */
if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
- && TYPE_DOMAIN (t1))
- t1 = TYPE_DOMAIN (t1);
+ && TYPE_ORIG_SIZE_TYPE (t1))
+ t1 = TYPE_ORIG_SIZE_TYPE (t1);
if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
- && TYPE_DOMAIN (t2))
- t2 = TYPE_DOMAIN (t2);
+ && TYPE_ORIG_SIZE_TYPE (t2))
+ t2 = TYPE_ORIG_SIZE_TYPE (t2);
if (TYPE_PTRMEMFUNC_P (t1))
t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
if (TREE_CODE (t1) != TREE_CODE (t2))
return false;
- /* Qualifiers must match. */
- if (cp_type_quals (t1) != cp_type_quals (t2))
+ /* Qualifiers must match. For array types, we will check when we
+ recur on the array element types. */
+ if (TREE_CODE (t1) != ARRAY_TYPE
+ && TYPE_QUALS (t1) != TYPE_QUALS (t2))
return false;
if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
return false;
definition. Note that we already checked for equality of the type
qualifiers (just above). */
- if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+ if (TREE_CODE (t1) != ARRAY_TYPE
+ && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return true;
if (!(*targetm.comp_type_attributes) (t1, t2))
return true;
/* Don't check inheritance. */
strict = COMPARE_STRICT;
- /* fall through */
+ /* Fall through. */
case RECORD_TYPE:
case UNION_TYPE:
if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
strict & ~COMPARE_REDECLARATION))
return false;
- /* FALLTHROUGH*/
+ /* Fall through. */
case POINTER_TYPE:
case REFERENCE_TYPE:
case COMPLEX_TYPE:
return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+ case VECTOR_TYPE:
+ return TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
+ && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+ break;
+
default:
break;
}
}
\f
+/* EXPR is being used in a context that is not a function call.
+ Enforce:
+
+ [expr.ref]
+
+ The expression can be used only as the left-hand operand of a
+ member function call.
+
+ [expr.mptr.operator]
+
+ If the result of .* or ->* is a function, then that result can be
+ used only as the operand for the function call operator ().
+
+ by issuing an error message if appropriate. Returns true iff EXPR
+ violates these rules. */
+
+bool
+invalid_nonstatic_memfn_p (tree expr)
+{
+ if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
+ {
+ error ("invalid use of non-static member function");
+ return true;
+ }
+ return false;
+}
+
/* Perform the conversions in [expr] that apply when an lvalue appears
in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and
function-to-pointer conversions.
tree
decay_conversion (tree exp)
{
- register tree type;
- register enum tree_code code;
+ tree type;
+ enum tree_code code;
type = TREE_TYPE (exp);
code = TREE_CODE (type);
error ("void value not ignored as it ought to be");
return error_mark_node;
}
- if (code == METHOD_TYPE)
- {
- error ("invalid use of non-static member function");
- return error_mark_node;
- }
+ if (invalid_nonstatic_memfn_p (exp))
+ return error_mark_node;
if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
return build_unary_op (ADDR_EXPR, exp, 0);
if (code == ARRAY_TYPE)
{
- register tree adr;
+ tree adr;
tree ptrtype;
if (TREE_CODE (exp) == INDIRECT_REF)
if (TREE_CODE (exp) == VAR_DECL)
{
- /* ??? This is not really quite correct
- in that the type of the operand of ADDR_EXPR
- is not the target type of the type of the ADDR_EXPR itself.
- Question is, can this lossage be avoided? */
- adr = build1 (ADDR_EXPR, ptrtype, exp);
if (!cxx_mark_addressable (exp))
return error_mark_node;
- TREE_CONSTANT (adr) = staticp (exp);
- TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */
+ adr = build_nop (ptrtype, build_address (exp));
return adr;
}
/* This way is better for a COMPONENT_REF since it can
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1)),
+ TREE_OPERAND (t, 1),
+ /*overloaded_p=*/NULL),
build_unary_op (code, TREE_OPERAND (t, 0), 0),
build_unary_op (code, TREE_OPERAND (t, 1), 0));
}
anonymous unions can nest, we must also search all anonymous unions
that are directly reachable. */
-static tree
+tree
lookup_anon_field (tree t, tree type)
{
tree field;
The type of the first expression shall be "class object" (of a
complete type). */
object_type = TREE_TYPE (object);
- if (!complete_type_or_else (object_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))
{
member_type = cp_build_qualified_type (member_type, type_quals);
}
- result = fold (build (COMPONENT_REF, member_type, object, member));
+ result = fold (build (COMPONENT_REF, member_type, object, member,
+ NULL_TREE));
/* Mark the expression const or volatile, as appropriate. Even
though we've dealt with the type above, we still have to mark the
type = unknown_type_node;
/* Note that we do not convert OBJECT to the BASELINK_BINFO
base. That will happen when the function is called. */
- result = build (COMPONENT_REF, type, object, member);
+ result = build (COMPONENT_REF, type, object, member, NULL_TREE);
}
else if (TREE_CODE (member) == CONST_DECL)
{
{
tree object_type = TREE_TYPE (object);
tree dtor_type = TREE_OPERAND (dtor_name, 0);
+ tree expr;
if (scope && !check_dtor_name (scope, dtor_name))
{
scope, dtor_type);
return error_mark_node;
}
- if (!same_type_p (dtor_type, TYPE_MAIN_VARIANT (object_type)))
+ if (!DERIVED_FROM_P (dtor_type, TYPE_MAIN_VARIANT (object_type)))
{
- error ("destructor name `%T' does not match type `%T' of expression",
- dtor_type, object_type);
+ error ("the type being destroyed is `%T', but the destructor refers to `%T'",
+ TYPE_MAIN_VARIANT (object_type), dtor_type);
return error_mark_node;
}
- if (!TYPE_HAS_DESTRUCTOR (object_type))
+ if (!TYPE_HAS_DESTRUCTOR (dtor_type))
return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
dtor_type);
- return lookup_member (object_type, complete_dtor_identifier,
+ expr = lookup_member (dtor_type, complete_dtor_identifier,
/*protect=*/1, /*want_type=*/false);
+ expr = (adjust_result_of_qualified_name_lookup
+ (expr, dtor_type, object_type));
+ return expr;
}
/* This function is called by the parser to process a class member
{
if (/* If OBJECT_TYPE is dependent, so is OBJECT.NAME. */
dependent_type_p (object_type)
+ /* If NAME is just an IDENTIFIER_NODE, then the expression
+ is dependent. */
+ || TREE_CODE (object) == IDENTIFIER_NODE
/* If NAME is "f<args>", where either 'f' or 'args' is
dependent, then the expression is dependent. */
|| (TREE_CODE (name) == TEMPLATE_ID_EXPR
|| (TREE_CODE (name) == SCOPE_REF
&& TYPE_P (TREE_OPERAND (name, 0))
&& dependent_type_p (TREE_OPERAND (name, 0))))
- return build_min_nt (COMPONENT_REF, object, name);
+ return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
object = build_non_dependent_expr (object);
}
The type of the first expression shall be "class object" (of a
complete type). */
- if (!complete_type_or_else (object_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))
{
/*preserve_reference=*/false);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (COMPONENT_REF, expr,
- orig_object, orig_name);
+ orig_object, orig_name, NULL_TREE);
return expr;
}
/*want_type=*/false);
member_type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (ptrmem_type));
- return fold (build (COMPONENT_REF, member_type, ptrmem, member));
+ return fold (build (COMPONENT_REF, member_type, ptrmem, member, NULL_TREE));
}
/* Given an expression PTR for a pointer, return an expression
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
- NULL_TREE);
+ NULL_TREE, /*overloaded_p=*/NULL);
if (!rval)
rval = build_indirect_ref (expr, errorstring);
tree
build_indirect_ref (tree ptr, const char *errorstring)
{
- register tree pointer, type;
+ tree pointer, type;
if (ptr == error_mark_node)
return error_mark_node;
break;
}
- if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
- && TREE_CODE (array) != INDIRECT_REF)
+ if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
{
tree rval, type;
would get a crash in store_bit_field/extract_bit_field when trying
to access a non-existent part of the register. */
if (TREE_CODE (idx) == INTEGER_CST
- && TYPE_VALUES (TREE_TYPE (array))
- && ! int_fits_type_p (idx, TYPE_VALUES (TREE_TYPE (array))))
+ && TYPE_DOMAIN (TREE_TYPE (array))
+ && ! int_fits_type_p (idx, TYPE_DOMAIN (TREE_TYPE (array))))
{
if (!cxx_mark_addressable (array))
return error_mark_node;
}
type = TREE_TYPE (TREE_TYPE (array));
- rval = build (ARRAY_REF, type, array, idx);
+ rval = build (ARRAY_REF, type, array, idx, NULL_TREE, NULL_TREE);
/* Array ref is const/volatile if the array elements are
or if the array is.. */
TREE_READONLY (rval)
e2 = fold (build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
e2 = build_indirect_ref (e2, NULL);
TREE_CONSTANT (e2) = 1;
+ TREE_INVARIANT (e2) = 1;
/* When using function descriptors, the address of the
vtable entry is treated as a function pointer. */
tree
build_function_call (tree function, tree params)
{
- register tree fntype, fndecl;
- register tree coerced_params;
- tree result;
- tree name = NULL_TREE, assembler_name = NULL_TREE;
+ tree fntype, fndecl;
+ tree coerced_params;
+ tree name = NULL_TREE;
int is_method;
tree original = function;
if (TREE_CODE (function) == FUNCTION_DECL)
{
name = DECL_NAME (function);
- assembler_name = DECL_ASSEMBLER_NAME (function);
mark_used (function);
fndecl = function;
/* Check for errors in format strings. */
if (warn_format)
- check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
-
- /* Recognize certain built-in functions so we can make tree-codes
- other than CALL_EXPR. We do this when it enables fold-const.c
- to do something useful. */
-
- if (TREE_CODE (function) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL
- && DECL_BUILT_IN (TREE_OPERAND (function, 0)))
- {
- result = expand_tree_builtin (TREE_OPERAND (function, 0),
- params, coerced_params);
- if (result)
- return result;
- }
+ check_function_format (TYPE_ATTRIBUTES (fntype), coerced_params);
- return build_cxx_call (function, params, coerced_params);
+ return build_cxx_call (function, coerced_params);
}
\f
/* Convert the actual parameter expressions in the list VALUES
tree
convert_arguments (tree typelist, tree values, tree fndecl, int flags)
{
- register tree typetail, valtail;
- register tree result = NULL_TREE;
+ tree typetail, valtail;
+ tree result = NULL_TREE;
const char *called_thing = 0;
int i = 0;
valtail;
valtail = TREE_CHAIN (valtail), i++)
{
- register tree type = typetail ? TREE_VALUE (typetail) : 0;
- register tree val = TREE_VALUE (valtail);
+ tree type = typetail ? TREE_VALUE (typetail) : 0;
+ tree val = TREE_VALUE (valtail);
if (val == error_mark_node)
return error_mark_node;
if (typetail != 0 && typetail != void_list_node)
{
- /* See if there are default arguments that can be used */
+ /* See if there are default arguments that can be used. */
if (TREE_PURPOSE (typetail)
&& TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
{
conversions on the operands. CODE is the kind of expression to build. */
tree
-build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
+build_x_binary_op (enum tree_code code, tree arg1, tree arg2,
+ bool *overloaded_p)
{
tree orig_arg1;
tree orig_arg2;
if (code == DOTSTAR_EXPR)
expr = build_m_component_ref (arg1, arg2);
else
- expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+ expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
+ overloaded_p);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
int convert_p ATTRIBUTE_UNUSED)
{
tree op0, op1;
- register enum tree_code code0, code1;
+ enum tree_code code0, code1;
tree type0, type1;
/* Expression code to give to the expression when it is built.
Normally this is CODE, which is what the caller asked for,
but in some special cases we change it. */
- register enum tree_code resultcode = code;
+ enum tree_code resultcode = code;
/* Data type in which the computation is to be performed.
In the simplest cases this is the common type of the arguments. */
- register tree result_type = NULL;
+ tree result_type = NULL;
/* Nonzero means operands have already been type-converted
in whatever way is necessary.
point, so we have to dig out the original type to find out if
it was unsigned. */
shorten = ((TREE_CODE (op0) == NOP_EXPR
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
+ && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
|| (TREE_CODE (op1) == INTEGER_CST
&& ! integer_all_onesp (op1)));
quotient can't be represented in the computation mode. We shorten
only if unsigned or if dividing by something we know != -1. */
shorten = ((TREE_CODE (op0) == NOP_EXPR
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
+ && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
|| (TREE_CODE (op1) == INTEGER_CST
&& ! integer_all_onesp (op1)));
common = 1;
tree arg0 = get_narrower (op0, &unsigned0);
tree arg1 = get_narrower (op1, &unsigned1);
/* UNS is 1 if the operation to be done is an unsigned one. */
- int uns = TREE_UNSIGNED (result_type);
+ int uns = TYPE_UNSIGNED (result_type);
tree type;
final_type = result_type;
but it *requires* conversion to FINAL_TYPE. */
if (op0 == arg0 && TREE_TYPE (op0) != final_type)
- unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0));
+ unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
if (op1 == arg1 && TREE_TYPE (op1) != final_type)
- unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1));
+ unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1));
/* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE. */
final_type = result_type;
if (arg0 == op0 && final_type == TREE_TYPE (op0))
- unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
+ unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
/* We can shorten only if the shift count is less than the
ones made by sign-extension and bring in zeros.
We can't optimize that case at all, but in most machines
it never happens because available widths are 2**N. */
- && (!TREE_UNSIGNED (final_type)
+ && (!TYPE_UNSIGNED (final_type)
|| unsigned_arg
|| (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
<= TYPE_PRECISION (result_type))))
bound the ranges of the arguments until that point. */
&& !processing_template_decl)
{
- int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
- int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
+ int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0));
+ int op1_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op1));
int unsignedp0, unsignedp1;
tree primop0 = get_narrower (op0, &unsignedp0);
/* Do not warn if the comparison is being done in a signed type,
since the signed type will only be chosen if it can represent
all the values of the unsigned type. */
- if (! TREE_UNSIGNED (result_type))
+ if (!TYPE_UNSIGNED (result_type))
/* OK */;
/* Do not warn if both operands are unsigned. */
else if (op0_signed == op1_signed)
build_type = result_type;
{
- register tree result = build (resultcode, build_type, op0, op1);
- register tree folded;
-
- folded = fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
+ tree result = fold (build (resultcode, build_type, op0, op1));
if (final_type != 0)
- return cp_convert (final_type, folded);
- return folded;
+ result = cp_convert (final_type, result);
+ return result;
}
}
\f
of pointer PTROP and integer INTOP. */
static tree
-cp_pointer_int_sum (enum tree_code resultcode, register tree ptrop,
- register tree intop)
+cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
{
tree res_type = TREE_TYPE (ptrop);
The resulting tree has type int. */
static tree
-pointer_diff (register tree op0, register tree op1, register tree ptrtype)
+pointer_diff (tree op0, tree op1, tree ptrtype)
{
- register tree result, folded;
+ tree result;
tree restype = ptrdiff_type_node;
tree target_type = TREE_TYPE (ptrtype);
/* Do the division. */
result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
-
- folded = fold (result);
- if (folded == result)
- TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
- return folded;
+ return fold (result);
}
\f
/* Construct and perhaps optimize a tree representation
exp = NULL_TREE;
- /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
- error message. */
+ /* [expr.unary.op] says:
+
+ The address of an object of incomplete type can be taken.
+
+ (And is just the ordinary address operator, not an overloaded
+ "operator &".) However, if the type is a template
+ specialization, we must complete the type at this point so that
+ an overloaded "operator &" will be available if required. */
if (code == ADDR_EXPR
&& TREE_CODE (xarg) != TEMPLATE_ID_EXPR
- && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
- && !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
+ && ((CLASS_TYPE_P (TREE_TYPE (xarg))
+ && !COMPLETE_TYPE_P (complete_type (TREE_TYPE (xarg))))
|| (TREE_CODE (xarg) == OFFSET_REF)))
- /* don't look for a function */;
+ /* Don't look for a function. */;
else
- exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
+ exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
+ /*overloaded_p=*/NULL);
if (!exp && code == ADDR_EXPR)
{
/* A pointer to member-function can be formed only by saying
return error_mark_node;
addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)), t);
- if (staticp (t))
- TREE_CONSTANT (addr) = 1;
return addr;
}
tree
build_nop (tree type, tree expr)
{
- tree nop;
-
if (type == error_mark_node || error_operand_p (expr))
return expr;
-
- nop = build1 (NOP_EXPR, type, expr);
- if (TREE_CONSTANT (expr))
- TREE_CONSTANT (nop) = 1;
-
- return nop;
+ return build1 (NOP_EXPR, type, expr);
}
/* C++: Must handle pointers to members.
build_unary_op (enum tree_code code, tree xarg, int noconvert)
{
/* No default_conversion here. It causes trouble for ADDR_EXPR. */
- register tree arg = xarg;
- register tree argtype = 0;
+ tree arg = xarg;
+ tree argtype = 0;
const char *errstring = NULL;
tree val;
else
{
if (!noconvert)
- arg = default_conversion (arg);
+ arg = default_conversion (arg);
arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
- TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
}
break;
0);
{
- register tree inc;
+ tree inc;
tree result_type = TREE_TYPE (arg);
arg = get_unwidened (arg, 0);
compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
/* Eliminate warning about unused result of + or -. */
- TREE_NO_UNUSED_WARNING (compound) = 1;
+ TREE_NO_WARNING (compound) = 1;
return compound;
}
if (TREE_CODE (argtype) == REFERENCE_TYPE)
{
- arg = build1
- (CONVERT_EXPR,
- build_pointer_type (TREE_TYPE (argtype)), arg);
- TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
+ tree type = build_pointer_type (TREE_TYPE (argtype));
+ arg = build1 (CONVERT_EXPR, type, arg);
return arg;
}
else if (pedantic && DECL_MAIN_P (arg))
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
{
- arg = build1
- (CONVERT_EXPR,
- build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
- TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
+ tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
+ arg = build1 (CONVERT_EXPR, type, arg);
}
else if (lvalue_p (arg))
/* Don't let this be an lvalue. */
return arg;
}
- /* For &x[y], return x+y */
- if (TREE_CODE (arg) == ARRAY_REF)
+ /* For &x[y], return x+y. But, in a template, ARG may be an
+ ARRAY_REF representing a non-dependent expression. In that
+ case, there may be an overloaded "operator []" that will be
+ chosen at instantiation time; we must not try to optimize
+ here. */
+ if (TREE_CODE (arg) == ARRAY_REF && !processing_template_decl)
{
if (!cxx_mark_addressable (TREE_OPERAND (arg, 0)))
return error_mark_node;
if (! lvalue_p (arg) && pedantic)
pedwarn ("ISO C++ forbids taking the address of a cast to a non-lvalue expression");
break;
-
+
+ case OVERLOAD:
+ arg = OVL_CURRENT (arg);
+ break;
+
default:
break;
}
{
tree addr;
- if (TREE_CODE (arg) != COMPONENT_REF)
+ if (TREE_CODE (arg) != COMPONENT_REF
+ /* Inside a template, we are processing a non-dependent
+ expression so we can just form an ADDR_EXPR with the
+ correct type. */
+ || processing_template_decl)
addr = build_address (arg);
else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
{
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
- TREE_NO_UNUSED_WARNING (arg) = 1;
+ TREE_NO_WARNING (arg) = 1;
return arg;
}
return error_mark_node;
}
- type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
+ type = build_ptrmem_type (context_for_name_lookup (t),
+ TREE_TYPE (t));
t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
return t;
}
bool
cxx_mark_addressable (tree exp)
{
- register tree x = exp;
+ tree x = exp;
while (1)
switch (TREE_CODE (x))
if (x == current_class_ptr)
{
error ("cannot take the address of `this', which is an rvalue expression");
- TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
+ TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later. */
return true;
}
- /* FALLTHRU */
+ /* Fall through. */
case VAR_DECL:
/* Caller should not be trying to mark initialized
|| DECL_IN_AGGR_P (x) == 0
|| TREE_STATIC (x)
|| DECL_EXTERNAL (x), 314);
- /* FALLTHRU */
+ /* Fall through. */
case CONST_DECL:
case RESULT_DECL:
case FUNCTION_DECL:
TREE_ADDRESSABLE (x) = 1;
- TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
return true;
case CONSTRUCTOR:
op2 = build_non_dependent_expr (op2);
}
- result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
+ result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
+ /*overloaded_p=*/NULL);
if (!result)
result = build_compound_expr (op1, op2);
t. */
result = perform_direct_initialization_if_possible (type, expr);
if (result)
- return convert_from_reference (result);
+ {
+ result = convert_from_reference (result);
+ /* [expr.static.cast]
+
+ If T is a reference type, the result is an lvalue; otherwise,
+ the result is an rvalue. */
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ && real_lvalue_p (result))
+ result = build1 (NON_LVALUE_EXPR, TREE_TYPE (result), result);
+ return result;
+ }
/* [expr.static.cast]
return t;
}
- if (!POINTER_TYPE_P (type))
+ if (!POINTER_TYPE_P (type) && !TYPE_PTRMEM_P (type))
error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
{
tree
build_c_cast (tree type, tree expr)
{
- register tree value = expr;
+ tree value = expr;
tree otype;
if (type == error_mark_node || expr == error_mark_node)
if (TREE_CODE (value) == INTEGER_CST)
{
TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
- TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+
+ if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
+ TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
}
}
tree
build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
{
- register tree result;
+ tree result;
tree newrhs = rhs;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
/* Handle control structure constructs used as "lvalues". */
switch (TREE_CODE (lhs))
{
- /* Handle --foo = 5; as these are valid constructs in C++ */
+ /* Handle --foo = 5; as these are valid constructs in C++. */
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
return cond;
/* Make sure the code to compute the rhs comes out
before the split. */
- return build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
+ if (preeval)
+ cond = build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
+ return cond;
}
default:
return result;
}
else if (! IS_AGGR_TYPE (lhstype))
- /* Do the default thing */;
+ /* Do the default thing. */;
else
{
result = build_special_member_call (lhs, complete_ctor_identifier,
{
/* `operator=' is not an inheritable operator. */
if (! IS_AGGR_TYPE (lhstype))
- /* Do the default thing */;
+ /* Do the default thing. */;
else
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
+ lhs, rhs, make_node (NOP_EXPR),
+ /*overloaded_p=*/NULL);
if (result == NULL_TREE)
return error_mark_node;
return result;
20011220);
}
- /* Handle a cast used as an "lvalue".
- We have already performed any binary operator using the value as cast.
- Now convert the result to the cast type of the lhs,
- and then true type of the lhs and store it there;
- then convert result back to the cast type to be the value
- of the assignment. */
-
- switch (TREE_CODE (lhs))
- {
- case NOP_EXPR:
- case CONVERT_EXPR:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_CEIL_EXPR:
- {
- tree inner_lhs = TREE_OPERAND (lhs, 0);
- tree result;
-
- if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
- newrhs = decay_conversion (newrhs);
-
- /* ISO C++ 5.4/1: The result is an lvalue if T is a reference
- type, otherwise the result is an rvalue. */
- if (! lvalue_p (lhs))
- pedwarn ("ISO C++ forbids cast to non-reference type used as lvalue");
-
- result = build_modify_expr (inner_lhs, NOP_EXPR,
- cp_convert (TREE_TYPE (inner_lhs),
- cp_convert (lhstype, newrhs)));
- if (result == error_mark_node)
- return result;
- return cp_convert (TREE_TYPE (lhs), result);
- }
-
- default:
- break;
- }
-
- /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
- Reject anything strange now. */
-
+ /* The left-hand side must be an lvalue. */
if (!lvalue_or_else (lhs, "assignment"))
return error_mark_node;
if (olhs)
{
result = build (COMPOUND_EXPR, olhstype, result, olhs);
- TREE_NO_UNUSED_WARNING (result) = 1;
+ TREE_NO_WARNING (result) = 1;
return result;
}
return convert_for_assignment (olhstype, result, "assignment",
if (modifycode != NOP_EXPR)
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
- make_node (modifycode));
+ make_node (modifycode),
+ /*overloaded_p=*/NULL);
if (rval)
return rval;
}
tree binfo;
tree virt_binfo;
base_kind kind;
-
+ tree result;
+
+ /* Assume no conversion is required. */
+ result = integer_zero_node;
binfo = lookup_base (to, from, ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
- {
- error (" in pointer to member function conversion");
- goto error;
- }
- if (!binfo)
+ error (" in pointer to member function conversion");
+ else if (!binfo)
{
if (!force)
{
error_not_base_type (from, to);
error (" in pointer to member conversion");
- goto error;
}
- binfo = lookup_base (from, to, ba_check, &kind);
- if (!binfo)
- goto error;
+ else
+ {
+ binfo = lookup_base (from, to, ba_check, &kind);
+ if (binfo)
+ {
+ virt_binfo = binfo_from_vbase (binfo);
+ if (virt_binfo)
+ /* This is a reinterpret cast, we choose to do nothing. */
+ warning ("pointer to member cast via virtual base `%T'",
+ BINFO_TYPE (virt_binfo));
+ else
+ result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
+ }
+ }
+ }
+ else
+ {
virt_binfo = binfo_from_vbase (binfo);
- if (virt_binfo)
- {
- /* This is a reinterpret cast, we choose to do nothing. */
- warning ("pointer to member cast via virtual base `%T'",
+ if (!virt_binfo)
+ result = BINFO_OFFSET (binfo);
+ else
+ {
+ /* This is a reinterpret cast, we choose to do nothing. */
+ if (force)
+ warning ("pointer to member cast via virtual base `%T'",
+ BINFO_TYPE (virt_binfo));
+ else
+ error ("pointer to member conversion via virtual base `%T'",
BINFO_TYPE (virt_binfo));
- goto error;
- }
- return convert_to_integer (ptrdiff_type_node,
- size_diffop (size_zero_node,
- BINFO_OFFSET (binfo)));
+ }
}
- virt_binfo = binfo_from_vbase (binfo);
- if (!virt_binfo)
- return convert_to_integer (ptrdiff_type_node, BINFO_OFFSET (binfo));
-
- /* This is a reinterpret cast, we choose to do nothing. */
- if (force)
- warning ("pointer to member cast via virtual base `%T'",
- BINFO_TYPE (virt_binfo));
- else
- error ("pointer to member conversion via virtual base `%T'",
- BINFO_TYPE (virt_binfo));
-
- error:
- return convert_to_integer(ptrdiff_type_node, integer_zero_node);
+ return fold (convert_to_integer (ptrdiff_type_node, result));
}
/* Return a constructor for the pointer-to-member-function TYPE using
u = tree_cons (pfn_field, pfn,
build_tree_list (delta_field, delta));
u = build_constructor (type, u);
- TREE_CONSTANT (u) = TREE_CONSTANT (pfn) && TREE_CONSTANT (delta);
+ TREE_CONSTANT (u) = TREE_CONSTANT (pfn) & TREE_CONSTANT (delta);
+ TREE_INVARIANT (u) = TREE_INVARIANT (pfn) & TREE_INVARIANT (delta);
TREE_STATIC (u) = (TREE_CONSTANT (u)
&& (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
!= NULL_TREE)
given by CST.
??? There is no consistency as to the types returned for the above
- values. Some code acts as if its a sizetype and some as if its
+ values. Some code acts as if it were a sizetype and some as if it were
integer_type_node. */
void
}
/* And warn about assigning a negative value to an unsigned
variable. */
- else if (TREE_UNSIGNED (type) && TREE_CODE (type) != BOOLEAN_TYPE)
+ else if (TYPE_UNSIGNED (type) && TREE_CODE (type) != BOOLEAN_TYPE)
{
- if (TREE_CODE (expr) == INTEGER_CST
- && TREE_NEGATED_INT (expr))
+ if (TREE_CODE (expr) == INTEGER_CST && TREE_NEGATED_INT (expr))
{
if (fndecl)
warning ("passing negative value `%E' for %s %P of `%D'",
convert_for_assignment (tree type, tree rhs,
const char *errtype, tree fndecl, int parmnum)
{
- register tree rhstype;
- register enum tree_code coder;
+ tree rhstype;
+ enum tree_code coder;
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
coder = TREE_CODE (rhstype);
if (TREE_CODE (type) == VECTOR_TYPE && coder == VECTOR_TYPE
- && ((*targetm.vector_opaque_p) (type)
- || (*targetm.vector_opaque_p) (rhstype)))
+ && vector_types_convertible_p (type, rhstype))
return convert (type, rhs);
if (rhs == error_mark_node || rhstype == error_mark_node)
if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
return error_mark_node;
- rhs = dubious_conversion_warnings (type, rhs, errtype, fndecl, parmnum);
-
/* The RHS of an assignment cannot have void type. */
if (coder == VOID_TYPE)
{
convert_for_initialization (tree exp, tree type, tree rhs, int flags,
const char *errtype, tree fndecl, int parmnum)
{
- register enum tree_code codel = TREE_CODE (type);
- register tree rhstype;
- register enum tree_code coder;
+ enum tree_code codel = TREE_CODE (type);
+ tree rhstype;
+ enum tree_code coder;
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
int vol, location_t locus)
{
int noutputs = list_length (outputs);
- register int i;
+ int i;
/* o[I] is the place that output number I should be written. */
- register tree *o = alloca (noutputs * sizeof (tree));
- register tree tail;
+ tree *o = alloca (noutputs * sizeof (tree));
+ tree tail;
/* Record the contents of OUTPUTS before it is modified. */
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
}
}
- if (TREE_CODE (whats_returned) == VAR_DECL
+ if (DECL_P (whats_returned)
&& DECL_NAME (whats_returned)
&& DECL_FUNCTION_SCOPE_P (whats_returned)
&& !(TREE_STATIC (whats_returned)
returned expression uses the chosen variable somehow. And people expect
this restriction, anyway. (jason 2000-11-19)
- See finish_function, cxx_expand_function_start, and
- cp_copy_res_decl_for_inlining for other pieces of this
- optimization. */
+ See finish_function and finalize_nrv for the rest of this optimization. */
if (fn_returns_value_p && flag_elide_constructors)
{
return TYPE_QUALS (type);
}
-/* Returns nonzero if the TYPE contains a mutable member */
+/* Returns nonzero if the TYPE contains a mutable member. */
bool
cp_has_mutable_p (tree type)