/* Build expressions with type checking for C++ compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
if (TYPE_PTRMEMFUNC_P (t2))
t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+ /* TYPENAME_TYPEs should be resolved if the qualifying scope is the
+ current instantiation. */
+ if (TREE_CODE (t1) == TYPENAME_TYPE)
+ t1 = resolve_typename_type_in_current_instantiation (t1);
+ if (TREE_CODE (t2) == TYPENAME_TYPE)
+ t2 = resolve_typename_type_in_current_instantiation (t2);
+
/* Different classes of types can't be compatible. */
if (TREE_CODE (t1) != TREE_CODE (t2))
return 0;
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
- if (strict & COMPARE_NO_ATTRIBUTES)
- attrval = 1;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
- else if (! (attrval = (*targetm.comp_type_attributes) (t1, t2)))
- return 0;
+ if (! (attrval = (*targetm.comp_type_attributes) (t1, t2)))
+ return 0;
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
val = 0;
&& integer_zerop (TREE_OPERAND (object, 0)));
/* Convert OBJECT to the type of MEMBER. */
- if (!same_type_p (object_type, member_scope))
+ if (!same_type_p (TYPE_MAIN_VARIANT (object_type),
+ TYPE_MAIN_VARIANT (member_scope)))
{
tree binfo;
base_kind kind;
if (binfo == error_mark_node)
return error_mark_node;
- /* It is invalid to use to try to get to a virtual base of a
+ /* 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. */
if (null_object_p && kind == bk_via_virtual)
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. */
- if (null_object_p && CLASSTYPE_NON_POD_P (object_type))
+ if (null_object_p && warn_invalid_offsetof
+ && CLASSTYPE_NON_POD_P (object_type))
{
warning ("invalid access to non-static data member `%D' of NULL object",
member);
return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
dtor_type);
return lookup_member (object_type, complete_dtor_identifier,
- /*protect=*/1, /*want_type=*/0);
+ /*protect=*/1, /*want_type=*/false);
}
/* This function is called by the parser to process a class member
{
/* Look up the member. */
member = lookup_member (access_path, name, /*protect=*/1,
- /*want_type=*/0);
+ /*want_type=*/false);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
{
/* An unqualified name. */
member = lookup_member (object_type, name, /*protect=*/1,
- /*want_type=*/0);
+ /*want_type=*/false);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
ptrmem_type = TREE_TYPE (ptrmem);
my_friendly_assert (TYPE_PTRMEMFUNC_P (ptrmem_type), 20020804);
member = lookup_member (ptrmem_type, member_name, /*protect=*/0,
- /*want_type=*/0);
+ /*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));
if (processing_template_decl)
return build_min_nt (INDIRECT_REF, ptr);
- rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
- NULL_TREE);
+ rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
+ NULL_TREE);
if (rval)
return rval;
return build_indirect_ref (ptr, errorstring);
return error_mark_node;
}
else if (TREE_CODE (pointer) == ADDR_EXPR
- && !flag_volatile
&& same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
/* The POINTER was something like `&x'. We simplify `*&x' to
`x'. */
TREE_READONLY (ref) = CP_TYPE_CONST_P (t);
TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t);
TREE_SIDE_EFFECTS (ref)
- = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer)
- || flag_volatile);
+ = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer));
return ref;
}
}
}
tree
-build_function_call_real (function, params, require_complete, flags)
+build_function_call (function, params)
tree function, params;
- int require_complete, flags;
{
register tree fntype, fndecl;
- register tree value_type;
register tree coerced_params;
tree result;
tree name = NULL_TREE, assembler_name = NULL_TREE;
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
- if (flags & LOOKUP_COMPLAIN)
- coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
- params, fndecl, LOOKUP_NORMAL);
- else
- coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
- params, fndecl, 0);
-
+ coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
+ params, fndecl, LOOKUP_NORMAL);
if (coerced_params == error_mark_node)
- {
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
- else
- return error_mark_node;
- }
+ return error_mark_node;
/* Check for errors in format strings. */
return result;
}
- /* Some built-in function calls will be evaluated at
- compile-time in fold (). */
- result = fold (build_call (function, coerced_params));
- value_type = TREE_TYPE (result);
-
- if (require_complete)
- {
- if (TREE_CODE (value_type) == VOID_TYPE)
- return result;
- result = require_complete_type (result);
- }
- if (IS_AGGR_TYPE (value_type))
- result = build_cplus_new (value_type, result);
- return convert_from_reference (result);
-}
-
-tree
-build_function_call (function, params)
- tree function, params;
-{
- return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
+ return build_cxx_call (function, params, coerced_params);
}
\f
/* Convert the actual parameter expressions in the list VALUES
return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
}
+#if 0
+
+tree
+build_template_expr (enum tree_code code, tree op0, tree op1, tree op2)
+{
+ tree type;
+
+ /* If any of the operands is erroneous the result is erroneous too. */
+ if (error_operand_p (op0)
+ || (op1 && error_operand_p (op1))
+ || (op2 && error_operand_p (op2)))
+ return error_mark_node;
+
+ if (dependent_type_p (TREE_TYPE (op0))
+ || (op1 && dependent_type_p (TREE_TYPE (op1)))
+ || (op2 && dependent_type_p (TREE_TYPE (op2))))
+ /* If at least one operand has a dependent type, we cannot
+ determine the type of the expression until instantiation time. */
+ type = NULL_TREE;
+ else
+ {
+ struct z_candidate *cand;
+ tree op0_type;
+ tree op1_type;
+ tree op2_type;
+
+ /* None of the operands is dependent, so we can compute the type
+ of the expression at this point. We must compute the type so
+ that in things like:
+
+ template <int I>
+ void f() { S<sizeof(I + 3)> s; ... }
+
+ we can tell that the type of "s" is non-dependent.
+
+ If we're processing a template argument, we do not want to
+ actually change the operands in any way. Adding conversions,
+ performing constant folding, etc., would all change mangled
+ names. For example, in:
+
+ template <int I>
+ void f(S<sizeof(3 + 4 + I)>);
+
+ we need to determine that "3 + 4 + I" has type "int", without
+ actually turning the expression into "7 + I". */
+ cand = find_overloaded_op (code, op0, op1, op2);
+ if (cand)
+ /* If an overloaded operator was found, the expression will
+ have the type returned by the function. */
+ type = non_reference (TREE_TYPE (cand->fn));
+ else
+ {
+ /* There is no overloaded operator so we can just use the
+ default rules for determining the type of the operand. */
+ op0_type = TREE_TYPE (op0);
+ op1_type = op1 ? TREE_TYPE (op1) : NULL_TREE;
+ op2_type = op2 ? TREE_TYPE (op2) : NULL_TREE;
+ type = NULL_TREE;
+
+ switch (code)
+ {
+ case MODIFY_EXPR:
+ /* [expr.ass]
+
+ The result of the assignment operation is the value
+ stored in the left operand. */
+ type = op0_type;
+ break;
+ case COMPONENT_REF:
+ /* Implement this case. */
+ break;
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ /* [expr.post.incr]
+
+ The type of the result is the cv-unqualified version
+ of the type of the operand. */
+ type = TYPE_MAIN_VARIANT (op0_type);
+ break;
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ /* [expr.pre.incr]
+
+ The value is the new value of the operand. */
+ type = op0_type;
+ break;
+ case INDIRECT_REF:
+ /* [expr.unary.op]
+
+ If the type of the expression is "pointer to T", the
+ type of the result is "T". */
+ type = TREE_TYPE (op0_type);
+ break;
+ case ADDR_EXPR:
+ /* [expr.unary.op]
+
+ If the type of the expression is "T", the type of the
+ result is "pointer to T". */
+ /* FIXME: Handle the pointer-to-member case. */
+ break;
+ case MEMBER_REF:
+ /* FIXME: Implement this case. */
+ break;
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ /* [expr.shift]
+
+ The type of the result is that of the promoted left
+ operand. */
+ break;
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ /* FIXME: Be careful of special pointer-arithmetic
+ cases. */
+ /* Fall through. */
+ case MAX_EXPR:
+ case MIN_EXPR:
+ /* These are GNU extensions; the result type is computed
+ as it would be for other arithmetic operators. */
+ /* Fall through. */
+ case BIT_AND_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_IOR_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ /* [expr.bit.and], [expr.xor], [expr.or], [expr.mul]
+
+ The usual arithmetic conversions are performed on the
+ operands and determine the type of the result. */
+ /* FIXME: Check that this is possible. */
+ type = type_after_usual_arithmetic_conversions (t1, t2);
+ break;
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ /* [expr.rel]
+
+ The type of the result is bool. */
+ type = boolean_type_node;
+ break;
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ /* [expr.log.and], [expr.log.org]
+
+ The result is a bool. */
+ type = boolean_type_node;
+ break;
+ case COND_EXPR:
+ /* FIXME: Handle special rules for conditioanl
+ expressions. */
+ break;
+ case COMPOUND_EXPR:
+ type = op1_type;
+ break;
+ default:
+ abort ();
+ }
+ /* If the type of the expression could not be determined,
+ something is wrong. */
+ if (!type)
+ abort ();
+ /* If the type is erroneous, the expression is erroneous
+ too. */
+ if (type == error_mark_node)
+ return error_mark_node;
+ }
+ }
+
+ return build_min (code, type, op0, op1, op2, NULL_TREE);
+}
+
+#endif
+
/* Build a binary-operation expression without default conversions.
CODE is the kind of expression to build.
This function differs from `build' in several ways:
t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
return t;
}
-
+
+/* Return an ADDR_EXPR giving the address of T. This function
+ attempts no optimizations or simplifications; it is a low-level
+ primitive. */
+
+tree
+build_address (tree t)
+{
+ tree addr;
+
+ if (error_operand_p (t) || !cxx_mark_addressable (t))
+ return error_mark_node;
+
+ addr = build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (t)),
+ t);
+ if (staticp (t))
+ TREE_CONSTANT (addr) = 1;
+
+ return addr;
+}
+
+/* Return a NOP_EXPR converting EXPR to TYPE. */
+
+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;
+}
+
/* C++: Must handle pointers to members.
Perhaps type instantiation should be extended to handle conversion
We could defer this in non-MS mode, but it's easier to give
a useful error here. */
- tree base = TREE_TYPE (TREE_OPERAND (arg, 0));
+ /* Inside constant member functions, the `this' pointer
+ contains an extra const qualifier. TYPE_MAIN_VARIANT
+ is used here to remove this const from the diagnostics
+ and the created OFFSET_REF. */
+ tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
tree name = DECL_NAME (get_first_fn (TREE_OPERAND (arg, 1)));
if (! flag_ms_extensions)
if (current_class_type
&& TREE_OPERAND (arg, 0) == current_class_ref)
/* An expression like &memfn. */
- pedwarn ("ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say `&%T::%D'", base, name);
+ pedwarn ("ISO C++ forbids taking the address of an unqualified"
+ " or parenthesized non-static member function to form"
+ " a pointer to member function. Say `&%T::%D'",
+ base, name);
else
- pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say `&%T::%D'", base, name);
+ pedwarn ("ISO C++ forbids taking the address of a bound member"
+ " function to form a pointer to member function."
+ " Say `&%T::%D'",
+ base, name);
}
arg = build_offset_ref (base, name);
}
if (argtype != error_mark_node)
argtype = build_pointer_type (argtype);
- if (!cxx_mark_addressable (arg))
- return error_mark_node;
-
{
tree addr;
&& TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
arg = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
- if (TREE_CODE (arg) == COMPONENT_REF
- && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+ if (TREE_CODE (arg) != COMPONENT_REF)
+ addr = build_address (arg);
+ else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
{
error ("attempt to take address of bit-field structure member `%D'",
TREE_OPERAND (arg, 1));
return error_mark_node;
}
- else if (TREE_CODE (arg) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (arg, 0)) == INDIRECT_REF
- && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0))
- == INTEGER_CST))
+ else
{
- /* offsetof idiom, fold it. */
+ /* Unfortunately we cannot just build an address
+ expression here, because we would not handle
+ address-constant-expressions or offsetof correctly. */
tree field = TREE_OPERAND (arg, 1);
tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)),
addr = fold (build (PLUS_EXPR, argtype, rval,
cp_convert (argtype, byte_position (field))));
}
- else
- addr = build1 (ADDR_EXPR, argtype, arg);
-
- /* Address of a static or external variable or
- function counts as a constant */
- if (staticp (arg))
- TREE_CONSTANT (addr) = 1;
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
warning ("address requested for `%D', which is declared `register'",
x);
TREE_ADDRESSABLE (x) = 1;
- put_var_into_stack (x);
+ put_var_into_stack (x, /*rescan=*/true);
return true;
case FUNCTION_DECL:
if (rest == NULL_TREE)
return build_compound_expr (list);
- result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
- TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
+ result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL,
+ TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
return build_x_compound_expr (tree_cons (NULL_TREE, result,
TREE_CHAIN (rest)));
/* the left-hand operand of a comma expression is like an expression
statement: we should warn if it doesn't have any side-effects,
unless it was explicitly cast to (void). */
- if ((extra_warnings || warn_unused_value)
+ if (warn_unused_value
&& !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
&& VOID_TYPE_P (TREE_TYPE (TREE_VALUE(list)))))
warning("left-hand operand of comma expression has no effect");
TREE_OPERAND (lhs, 0), newrhs);
case MODIFY_EXPR:
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
+ lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs),
+ stabilize_reference (TREE_OPERAND (lhs, 0)),
+ TREE_OPERAND (lhs, 1));
newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
if (newrhs == error_mark_node)
return error_mark_node;
/* Do the default thing */;
else
{
- result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
+ result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
+ lhs, rhs, make_node (NOP_EXPR));
if (result == NULL_TREE)
return error_mark_node;
return result;
|| TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
/* If it's an aggregate and any field is const, then it is
effectively const. */
- || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
+ || (CLASS_TYPE_P (lhstype)
&& C_TYPE_FIELDS_READONLY (lhstype))))
readonly_error (lhs, "assignment", 0);
}
}
- if (TREE_CODE (lhstype) != REFERENCE_TYPE)
- {
- if (TREE_SIDE_EFFECTS (lhs))
- lhs = stabilize_reference (lhs);
- if (TREE_SIDE_EFFECTS (newrhs))
- newrhs = stabilize_reference (newrhs);
- }
-
/* Convert new value to destination type. */
if (TREE_CODE (lhstype) == ARRAY_TYPE)
if (modifycode != NOP_EXPR)
{
- tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
- make_node (modifycode));
+ tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
+ make_node (modifycode));
if (rval)
return rval;
}
if (virt_binfo)
{
/* This is a reinterpret cast, we choose to do nothing. */
- warning ("pointer to member cast via virtual base `%T' of `%T'",
- BINFO_TYPE (virt_binfo),
- BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+ warning ("pointer to member cast via virtual base `%T'",
+ BINFO_TYPE (virt_binfo));
return delta;
}
delta = BINFO_OFFSET (binfo);
{
/* This is a reinterpret cast, we choose to do nothing. */
if (force)
- warning ("pointer to member cast via virtual base `%T' of `%T'",
- BINFO_TYPE (virt_binfo),
- BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+ warning ("pointer to member cast via virtual base `%T'",
+ BINFO_TYPE (virt_binfo));
else
- error ("pointer to member conversion via virtual base `%T' of `%T'",
- BINFO_TYPE (virt_binfo),
- BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+ error ("pointer to member conversion via virtual base `%T'",
+ BINFO_TYPE (virt_binfo));
return delta;
}
delta = BINFO_OFFSET (binfo);
/* Finish creating the initializer. */
u = tree_cons (pfn_field, pfn,
build_tree_list (delta_field, delta));
- u = build (CONSTRUCTOR, type, NULL_TREE, u);
+ u = build_constructor (type, u);
TREE_CONSTANT (u) = TREE_CONSTANT (pfn) && TREE_CONSTANT (delta);
TREE_STATIC (u) = (TREE_CONSTANT (u)
&& (initializer_constant_valid_p (pfn, TREE_TYPE (pfn))
int force;
{
tree fn;
- tree pfn_type = TREE_TYPE (pfn);
- tree to_type = build_ptrmemfunc_type (type);
+ 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);
/* Handle multiple conversions of pointer to member functions. */
- if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
+ if (TYPE_PTRMEMFUNC_P (pfn_type))
{
tree delta = NULL_TREE;
tree npfn = NULL_TREE;
if (fndecl)
savew = warningcount, savee = errorcount;
- rhs = initialize_reference (type, rhs);
+ rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE);
if (fndecl)
{
if (warningcount > savew)
tree type = TREE_TYPE (o[i]);
if (type != error_mark_node
&& (CP_TYPE_CONST_P (type)
- || (IS_AGGR_TYPE_CODE (TREE_CODE (type))
- && C_TYPE_FIELDS_READONLY (type))))
+ || (CLASS_TYPE_P (type) && C_TYPE_FIELDS_READONLY (type))))
readonly_error (o[i], "modification by `asm'", 1);
}
}
}
if (TREE_CODE (to) != POINTER_TYPE)
- return
- same_type_ignoring_top_level_qualifiers_p (to, from)
- && (constp >= 0 || to_more_cv_qualified);
+ return ((constp >= 0 || to_more_cv_qualified)
+ && same_type_ignoring_top_level_qualifiers_p (to, from));
}
}
-/* When comparing, say, char ** to char const **, this function takes the
- 'char *' and 'char const *'. Do not pass non-pointer types to this
- function. */
+/* When comparing, say, char ** to char const **, this function takes
+ the 'char *' and 'char const *'. Do not pass non-pointer/reference
+ types to this function. */
int
comp_ptr_ttypes (to, from)