/* 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. */
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 (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);
- /* Transform `(a, b).x' into `a, b.x' and `(a ? b : c).x' into
- `a ? b.x : c.x'. These transformations should not really be
- necessary, but they are. */
- if (TREE_CODE (object) == COMPOUND_EXPR)
- {
- result = build_class_member_access_expr (TREE_OPERAND (object, 1),
- member, access_path,
- preserve_reference);
- return build (COMPOUND_EXPR, TREE_TYPE (result),
- TREE_OPERAND (object, 0), result);
- }
- else if (TREE_CODE (object) == COND_EXPR)
- return (build_conditional_expr
- (TREE_OPERAND (object, 0),
- build_class_member_access_expr (TREE_OPERAND (object, 1),
- member, access_path,
- preserve_reference),
- build_class_member_access_expr (TREE_OPERAND (object, 2),
- member, access_path,
- preserve_reference)));
-
/* [expr.ref]
The type of the first expression shall be "class object" (of a
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 (!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 == NULL_TREE)
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ member = lookup_destructor (object, scope, name);
+ else
{
- error ("'%D' has no member named '%E'", object_type, name);
- 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;
}
- else 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))
- {
- error ("type `%T' has no destructor", object_type);
- return error_mark_node;
- }
- member = CLASSTYPE_DESTRUCTORS (object_type);
- }
+ 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);
+ /*want_type=*/false);
if (member == NULL_TREE)
{
error ("'%D' has no member named '%E'", object_type, name);
}
}
+ 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;
}
}
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)
}
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);
/* 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);
}
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'",
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)
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)));
/* 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)));
+ 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);
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;
/* 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]
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);
}
}
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);
tree type;
{
type = strip_array_types (type);
+ if (type == error_mark_node)
+ return TYPE_UNQUALIFIED;
return TYPE_QUALS (type);
}