/* 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 GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
+along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "expr.h"
static int casts_away_constness PARAMS ((tree, tree));
static void maybe_warn_about_returning_address_of_local PARAMS ((tree));
static tree strip_all_pointer_quals PARAMS ((tree));
+static tree lookup_destructor (tree, tree, tree);
/* Return the target type of TYPE, which means return T for:
T*, T&, T[], T (...), and otherwise, just T. */
return type;
}
-/* Like complete_type, but issue an error if the TYPE cannot be
- completed. VALUE is used for informative diagnostics. WARN_ONLY
- will cause a warning message to be printed, instead of an error.
+/* Like complete_type, but issue an error if the TYPE cannot be completed.
+ VALUE is used for informative diagnostics. DIAG_TYPE indicates the type
+ of diagnostic: 0 for an error, 1 for a warning, 2 for a pedwarn.
Returns NULL_TREE if the type cannot be made complete. */
tree
-complete_type_or_diagnostic (type, value, warn_only)
+complete_type_or_diagnostic (type, value, diag_type)
tree type;
tree value;
- int warn_only;
+ int diag_type;
{
type = complete_type (type);
if (type == error_mark_node)
return NULL_TREE;
else if (!COMPLETE_TYPE_P (type))
{
- cxx_incomplete_type_diagnostic (value, type, warn_only);
+ cxx_incomplete_type_diagnostic (value, type, diag_type);
return NULL_TREE;
}
else
if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
|| (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
{
- tree tt1 = TREE_TYPE (t1);
- tree tt2 = TREE_TYPE (t2);
+ tree tt1;
+ tree tt2;
tree b1;
int type_quals;
tree tgt;
tree attributes = (*targetm.merge_type_attributes) (t1, t2);
- if (TREE_CODE (tt1) == OFFSET_TYPE)
+ if (TYPE_PTRMEM_P (t1))
{
- b1 = TYPE_OFFSET_BASETYPE (tt1);
- tt1 = TREE_TYPE (tt1);
- tt2 = TREE_TYPE (tt2);
+ b1 = TYPE_PTRMEM_CLASS_TYPE (t1);
+ tt1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
+ tt2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
}
else
- b1 = NULL_TREE;
+ {
+ b1 = NULL_TREE;
+ tt1 = TREE_TYPE (t1);
+ tt2 = TREE_TYPE (t2);
+ }
type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
tgt = qualify_type_recursive (tt1, tt2);
tgt = cp_build_qualified_type (tgt, type_quals);
if (b1)
- tgt = build_offset_type (b1, tgt);
- t1 = build_pointer_type (tgt);
+ t1 = build_ptrmem_type (b1, tgt);
+ else
+ t1 = build_pointer_type (tgt);
t1 = build_type_attribute_variant (t1, attributes);
}
return t1;
return t1;
/* Deal with pointer-to-member functions in the same way as we deal
- with pointers to functions. */
+ with pointers to functions. */
if (TYPE_PTRMEMFUNC_P (t1))
t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
if (TYPE_PTRMEMFUNC_P (t2))
if (t1 == t2)
return 1;
- if (t1 == NULL_TREE) /* T1 is ... */
+ if (t1 == NULL_TREE) /* T1 is ... */
return t2 == NULL_TREE || !exact;
if (!TREE_VALUE (t1)) /* t1 is EMPTY */
return t2 != NULL_TREE && !TREE_VALUE (t2);
- if (t2 == NULL_TREE) /* T2 is ... */
+ if (t2 == NULL_TREE) /* T2 is ... */
return 0;
if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
return !exact;
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 (TREE_STATIC (field))
continue;
- if (TREE_CODE (field) != FIELD_DECL)
+ if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
continue;
/* If we find it directly, return the field. */
if (object == error_mark_node || member == error_mark_node)
return error_mark_node;
+ if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
+ return member;
+
my_friendly_assert (DECL_P (member) || BASELINK_P (member),
20020801);
return error_mark_node;
}
+ /* 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. */
+ {
+ tree temp = unary_complex_lvalue (ADDR_EXPR, object);
+ if (temp)
+ object = build_indirect_ref (temp, NULL);
+ }
+
/* In [expr.ref], there is an explicit list of the valid choices for
MEMBER. We check for each of those cases here. */
if (TREE_CODE (member) == VAR_DECL)
my_friendly_assert (object != error_mark_node,
20020801);
}
-
- /* Issue a warning about access a member of a NULL object. */
+
+ /* 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. */
if (null_object_p && CLASSTYPE_NON_POD_P (object_type))
{
warning ("invalid access to non-static data member `%D' of NULL object",
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. */
- if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member)))
+ if (ANON_AGGR_TYPE_P (DECL_CONTEXT (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. */
+ && (!same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (object), DECL_CONTEXT (member))))
{
tree anonymous_union;
{
/* The member is a (possibly overloaded) member function. */
tree functions;
+ tree type;
/* If the MEMBER is exactly one static member function, then we
know the type of the expression. Otherwise, we must wait
functions = BASELINK_FUNCTIONS (member);
if (TREE_CODE (functions) == FUNCTION_DECL
&& DECL_STATIC_FUNCTION_P (functions))
- {
- /* A static member function. */
- result = functions;
- mark_used (result);
- /* If OBJECT has side-effects, they are supposed to occur. */
- if (TREE_SIDE_EFFECTS (object))
- result = build (COMPOUND_EXPR, TREE_TYPE (result),
- object, result);
- }
+ type = TREE_TYPE (functions);
else
- /* Note that we do not convert OBJECT to the BASELINK_BINFO
- base. That will happen when the function is called. */
- result = build (COMPONENT_REF, unknown_type_node, object, member);
+ 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);
}
else if (TREE_CODE (member) == CONST_DECL)
{
return result;
}
+/* Return the destructor denoted by OBJECT.SCOPE::~DTOR_NAME, or, if
+ SCOPE is NULL, by OBJECT.~DTOR_NAME. */
+
+static tree
+lookup_destructor (tree object, tree scope, tree dtor_name)
+{
+ tree object_type = TREE_TYPE (object);
+ tree dtor_type = TREE_OPERAND (dtor_name, 0);
+
+ if (scope && !check_dtor_name (scope, dtor_name))
+ {
+ error ("qualified type `%T' does not match destructor name `~%T'",
+ scope, dtor_type);
+ return error_mark_node;
+ }
+ if (!same_type_p (dtor_type, TYPE_MAIN_VARIANT (object_type)))
+ {
+ error ("destructor name `%T' does not match type `%T' of expression",
+ dtor_type, object_type);
+ return error_mark_node;
+ }
+ if (!TYPE_HAS_DESTRUCTOR (object_type))
+ return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
+ dtor_type);
+ return lookup_member (object_type, complete_dtor_identifier,
+ /*protect=*/1, /*want_type=*/false);
+}
+
/* This function is called by the parser to process a class member
access expression of the form OBJECT.NAME. NAME is a node used by
the parser to represent a name; it is not yet a DECL. It may,
if (TREE_CODE (scope) == NAMESPACE_DECL)
{
error ("`%D::%D' is not a member of `%T'",
- scope, member, object_type);
+ scope, name, object_type);
return error_mark_node;
}
if (!access_path || access_path == error_mark_node)
return error_mark_node;
- /* Look up the member. */
- member = lookup_member (access_path, name, /*protect=*/1,
- /*want_type=*/0);
- if (member == error_mark_node)
- return error_mark_node;
- }
- else if (TREE_CODE (name) == BIT_NOT_EXPR)
- {
- /* A destructor. */
- if (TYPE_IDENTIFIER (object_type) != TREE_OPERAND (name, 0))
- {
- error ("destructor specifier `%T::~%T' must have matching names",
- object_type, TREE_OPERAND (name, 0));
- return error_mark_node;
- }
- if (! TYPE_HAS_DESTRUCTOR (object_type))
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ member = lookup_destructor (object, scope, name);
+ else
{
- error ("type `%T' has no destructor", object_type);
- return error_mark_node;
+ /* Look up the member. */
+ member = lookup_member (access_path, name, /*protect=*/1,
+ /*want_type=*/false);
+ if (member == NULL_TREE)
+ {
+ error ("'%D' has no member named '%E'", object_type, name);
+ return error_mark_node;
+ }
+ if (member == error_mark_node)
+ return error_mark_node;
}
- member = CLASSTYPE_DESTRUCTORS (object_type);
}
+ else if (TREE_CODE (name) == BIT_NOT_EXPR)
+ member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
else if (TREE_CODE (name) == IDENTIFIER_NODE)
{
/* An unqualified name. */
member = lookup_member (object_type, name, /*protect=*/1,
- /*want_type=*/0);
- if (member == error_mark_node)
+ /*want_type=*/false);
+ if (member == NULL_TREE)
+ {
+ error ("'%D' has no member named '%E'", object_type, name);
+ return error_mark_node;
+ }
+ else if (member == error_mark_node)
return error_mark_node;
}
else
}
}
+ if (TREE_DEPRECATED (member))
+ warn_deprecated_use (member);
+
return build_class_member_access_expr (object, member, access_path,
/*preserve_reference=*/false);
}
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))))
+ && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
/* The POINTER was something like `&x'. We simplify `*&x' to
`x'. */
return TREE_OPERAND (pointer, 0);
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;
}
}
With the final ISO C++ rules, such an optimization is
incorrect: A pointer to a derived member can be static_cast
to pointer-to-base-member, as long as the dynamic object
- later has the right member. */
+ later has the right member. */
tree
get_member_function_from_ptrfunc (instance_ptrptr, function)
tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
tree instance_ptr = *instance_ptrptr;
+ tree instance_save_expr = 0;
if (instance_ptr == error_mark_node)
{
if (TREE_CODE (function) == PTRMEM_CST)
{
/* Extracting the function address from a pmf is only
allowed with -Wno-pmf-conversions. It only works for
- pmf constants. */
+ pmf constants. */
e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
e1 = convert (fntype, e1);
return e1;
}
if (TREE_SIDE_EFFECTS (instance_ptr))
- instance_ptr = save_expr (instance_ptr);
+ instance_ptr = instance_save_expr = save_expr (instance_ptr);
if (TREE_SIDE_EFFECTS (function))
function = save_expr (function);
}
/* Convert down to the right base before using the instance. First
- use the type... */
+ use the type... */
basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
basetype, ba_check, NULL);
/* Make sure this doesn't get evaluated first inside one of the
branches of the COND_EXPR. */
- if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+ if (instance_save_expr)
e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
- instance_ptr, e1);
+ instance_save_expr, e1);
function = e1;
}
}
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;
/* 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. */
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 (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);
-}
\f
/* Convert the actual parameter expressions in the list VALUES
to the types in the list TYPELIST.
if (typetail != 0 && typetail != void_list_node)
{
/* See if there are default arguments that can be used */
- if (TREE_PURPOSE (typetail))
+ if (TREE_PURPOSE (typetail)
+ && TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
{
for (; typetail != void_list_node; ++i)
{
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
is enough to prevent anybody from looking inside for
associativity, but won't generate any code. */
if (!(arg = build_expr_type_conversion
- (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1)))
+ (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, true)))
errstring = "wrong type argument to unary plus";
else
{
break;
case NEGATE_EXPR:
- if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
errstring = "wrong type argument to unary minus";
else if (!noconvert)
arg = default_conversion (arg);
arg = default_conversion (arg);
}
else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
- arg, 1)))
+ arg, true)))
errstring = "wrong type argument to bit-complement";
else if (!noconvert)
arg = default_conversion (arg);
break;
case ABS_EXPR:
- if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
errstring = "wrong type argument to abs";
else if (!noconvert)
arg = default_conversion (arg);
case CONJ_EXPR:
/* Conjugating a real value is a no-op, but allow it anyway. */
- if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
errstring = "wrong type argument to conjugation";
else if (!noconvert)
arg = default_conversion (arg);
/* Report invalid types. */
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
- arg, 1)))
+ arg, true)))
{
if (code == PREINCREMENT_EXPR)
errstring ="no pre-increment operator for type";
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 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);
}
is an error. */
else if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
- && !lvalue_or_else (arg, "unary `&'"))
+ && !non_cast_lvalue_or_else (arg, "unary `&'"))
return error_mark_node;
if (argtype != error_mark_node)
argtype = build_pointer_type (argtype);
- if (!cxx_mark_addressable (arg))
- return error_mark_node;
-
{
tree addr;
if (TREE_CODE (arg) == COMPONENT_REF
+ && 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)))
{
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))
+ {
+ /* offsetof idiom, fold it. */
+ 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)),
+ decl_type_context (field),
+ ba_check, NULL);
+
+ rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
+ rval = build1 (NOP_EXPR, argtype, rval);
+ TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
+ 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;
+ addr = build_address (arg);
if (TREE_CODE (argtype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
return error_mark_node;
}
- type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
- type = build_pointer_type (type);
-
+ type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
return t;
}
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)));
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{
- /* FIXME: This test should be in the implicit cast to void of the LHS. */
+ /* FIXME: This test should be in the implicit cast to void of the LHS. */
/* 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). */
? can_convert_arg (type, intype, expr)
: can_convert_arg (strip_all_pointer_quals (type),
strip_all_pointer_quals (intype), expr))
- /* This is a standard conversion. */
+ /* This is a standard conversion. */
ok = 1;
else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
{
/* They're pointers to objects. They must be aggregates that
- are related non-virtually. */
+ are related non-virtually. */
base_kind kind;
if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
{
/* They're pointers to members. The pointed to objects must be
the same (ignoring CV qualifiers), and the containing classes
- must be related non-virtually. */
+ must be related non-virtually. */
base_kind kind;
if (same_type_p
/* 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);
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
? 1 + (modifycode != INIT_EXPR): 0;
- return build_vec_init (lhs, newrhs, from_array);
+ return build_vec_init (lhs, NULL_TREE, newrhs, from_array);
}
if (modifycode == INIT_EXPR)
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)));
+ /* This is a reinterpret cast, we choose to do nothing. */
+ warning ("pointer to member cast via virtual base `%T'",
+ BINFO_TYPE (virt_binfo));
return delta;
}
delta = BINFO_OFFSET (binfo);
virt_binfo = binfo_from_vbase (binfo);
if (virt_binfo)
{
- /* This is a reinterpret cast, we choose to do nothing. */
+ /* 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);
as a value in expressions. TYPE is the POINTER to METHOD_TYPE we
want to be.
- If FORCE is non-zero, then force this conversion, even if
+ If FORCE is nonzero, then force this conversion, even if
we would rather not do it. Usually set when using an explicit
cast.
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 we're dealing with a virtual function, we have to adjust 'this'
again, to point to the base which provides the vtable entry for
fn; the call will do the opposite adjustment. */
- tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+ tree orig_class = DECL_CONTEXT (fn);
tree binfo = binfo_or_else (orig_class, fn_class);
*delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
*delta, BINFO_OFFSET (binfo)));
/* Simplify the RHS if possible. */
if (TREE_CODE (rhs) == CONST_DECL)
rhs = DECL_INITIAL (rhs);
- else if (coder != ARRAY_TYPE)
- rhs = decl_constant_value (rhs);
+
+ /* We do not use decl_constant_value here because of this case:
+
+ const char* const s = "s";
+
+ The conversion rules for a string literal are more lax than for a
+ variable; in particular, a string literal can be converted to a
+ "char *" but the variable "s" cannot be converted in the same
+ way. If the conversion is allowed, the optimization should be
+ performed while creating the converted expression. */
/* [expr.ass]
}
/* Convert RHS to be of type TYPE.
- If EXP is non-zero, it is the target of the initialization.
+ If EXP is nonzero, it is the target of the initialization.
ERRTYPE is a string to use in error messages.
Two major differences between the behavior of
if (fndecl)
savew = warningcount, savee = errorcount;
- rhs = initialize_reference (type, rhs);
+ rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE);
if (fndecl)
{
if (warningcount > savew)
else
{
tree type = TREE_TYPE (o[i]);
- if (CP_TYPE_CONST_P (type)
- || (IS_AGGR_TYPE_CODE (TREE_CODE (type))
- && C_TYPE_FIELDS_READONLY (type)))
+ if (type != error_mark_node
+ && (CP_TYPE_CONST_P (type)
+ || (CLASS_TYPE_P (type) && C_TYPE_FIELDS_READONLY (type))))
readonly_error (o[i], "modification by `asm'", 1);
}
}
{
if (in_function_try_handler)
/* If a return statement appears in a handler of the
- function-try-block of a constructor, the program is ill-formed. */
+ function-try-block of a constructor, the program is ill-formed. */
error ("cannot return from a handler of a function-try-block of a constructor");
else if (retval)
/* You can't return a value from a constructor. */
return NULL_TREE;
}
+ if (processing_template_decl)
+ {
+ current_function_returns_value = 1;
+ return retval;
+ }
+
/* When no explicit return-value is given in a function with a named
return value, the named return value is used. */
result = DECL_RESULT (current_function_decl);
/* First convert the value to the function's return type, then
to the type of return value's location to handle the
- case that functype is smaller than the valtype. */
+ case that functype is smaller than the valtype. */
retval = convert_for_initialization
(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
"return", NULL_TREE, 0);
}
\f
-/* Returns non-zero if the pointer-type FROM can be converted to the
+/* Returns nonzero if the pointer-type FROM can be converted to the
pointer-type TO via a qualification conversion. If CONSTP is -1,
- then we return non-zero if the pointers are similar, and the
+ then we return nonzero if the pointers are similar, and the
cv-qualification signature of FROM is a proper subset of that of TO.
If CONSTP is positive, then all outer pointers have been
tree type;
{
type = strip_array_types (type);
+ if (type == error_mark_node)
+ return TYPE_UNQUALIFIED;
return TYPE_QUALS (type);
}
-/* Returns non-zero if the TYPE contains a mutable member */
+/* Returns nonzero if the TYPE contains a mutable member */
int
cp_has_mutable_p (type)
*t2 = cp_build_qualified_type (*t2, quals2);
}
-/* Returns non-zero if casting from TYPE1 to TYPE2 casts away
+/* Returns nonzero if casting from TYPE1 to TYPE2 casts away
constness. */
static int