/* 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, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
-#include "toplev.h"
#include "diagnostic.h"
#include "intl.h"
#include "target.h"
#include "convert.h"
#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "params.h"
static tree pfn_from_ptrmemfunc (tree);
return cp_common_type (t1, t2);
}
+static void
+composite_pointer_error (diagnostic_t kind, tree t1, tree t2,
+ composite_pointer_operation operation)
+{
+ switch (operation)
+ {
+ case CPO_COMPARISON:
+ emit_diagnostic (kind, input_location, 0,
+ "comparison between "
+ "distinct pointer types %qT and %qT lacks a cast",
+ t1, t2);
+ break;
+ case CPO_CONVERSION:
+ emit_diagnostic (kind, input_location, 0,
+ "conversion between "
+ "distinct pointer types %qT and %qT lacks a cast",
+ t1, t2);
+ break;
+ case CPO_CONDITIONAL_EXPR:
+ emit_diagnostic (kind, input_location, 0,
+ "conditional expression between "
+ "distinct pointer types %qT and %qT lacks a cast",
+ t1, t2);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Subroutine of composite_pointer_type to implement the recursive
case. See that function for documentation of the parameters. */
&& TREE_CODE (pointee2) == POINTER_TYPE)
|| (TYPE_PTR_TO_MEMBER_P (pointee1)
&& TYPE_PTR_TO_MEMBER_P (pointee2)))
- result_type = composite_pointer_type_r (pointee1, pointee2, operation,
- complain);
+ {
+ result_type = composite_pointer_type_r (pointee1, pointee2, operation,
+ complain);
+ if (result_type == error_mark_node)
+ return error_mark_node;
+ }
else
{
if (complain & tf_error)
- {
- switch (operation)
- {
- case CPO_COMPARISON:
- permerror (input_location, "comparison between "
- "distinct pointer types %qT and %qT lacks a cast",
- t1, t2);
- break;
- case CPO_CONVERSION:
- permerror (input_location, "conversion between "
- "distinct pointer types %qT and %qT lacks a cast",
- t1, t2);
- break;
- case CPO_CONDITIONAL_EXPR:
- permerror (input_location, "conditional expression between "
- "distinct pointer types %qT and %qT lacks a cast",
- t1, t2);
- break;
- default:
- gcc_unreachable ();
- }
- }
+ composite_pointer_error (DK_PERMERROR, t1, t2, operation);
+ else
+ return error_mark_node;
result_type = void_type_node;
}
result_type = cp_build_qualified_type (result_type,
if (TYPE_PTR_TO_MEMBER_P (t1))
{
if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
- TYPE_PTRMEM_CLASS_TYPE (t2))
- && (complain & tf_error))
- {
- switch (operation)
- {
- case CPO_COMPARISON:
- permerror (input_location, "comparison between "
- "distinct pointer types %qT and %qT lacks a cast",
- t1, t2);
- break;
- case CPO_CONVERSION:
- permerror (input_location, "conversion between "
- "distinct pointer types %qT and %qT lacks a cast",
- t1, t2);
- break;
- case CPO_CONDITIONAL_EXPR:
- permerror (input_location, "conditional expression between "
- "distinct pointer types %qT and %qT lacks a cast",
- t1, t2);
- break;
- default:
- gcc_unreachable ();
- }
- }
+ TYPE_PTRMEM_CLASS_TYPE (t2)))
+ {
+ if (complain & tf_error)
+ composite_pointer_error (DK_PERMERROR, t1, t2, operation);
+ else
+ return error_mark_node;
+ }
result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
result_type);
}
else
{
if (complain & tf_error)
- switch (operation)
- {
- case CPO_COMPARISON:
- error ("comparison between distinct "
- "pointer types %qT and %qT lacks a cast", t1, t2);
- break;
- case CPO_CONVERSION:
- error ("conversion between distinct "
- "pointer types %qT and %qT lacks a cast", t1, t2);
- break;
- case CPO_CONDITIONAL_EXPR:
- error ("conditional expression between distinct "
- "pointer types %qT and %qT lacks a cast", t1, t2);
- break;
- default:
- gcc_unreachable ();
- }
+ composite_pointer_error (DK_ERROR, t1, t2, operation);
return error_mark_node;
}
}
gcc_assert (type_memfn_quals (t1) == type_memfn_quals (t2));
rval = apply_memfn_quals (rval, type_memfn_quals (t1));
raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
- TYPE_RAISES_EXCEPTIONS (t2));
+ TYPE_RAISES_EXCEPTIONS (t2),
+ NULL_TREE);
t1 = build_exception_variant (rval, raises);
break;
}
{
/* Get this value the long way, since TYPE_METHOD_BASETYPE
is just the main variant of this. */
- tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
+ tree basetype = class_of_this_parm (t2);
tree raises = merge_exception_specifiers (TYPE_RAISES_EXCEPTIONS (t1),
- TYPE_RAISES_EXCEPTIONS (t2));
+ TYPE_RAISES_EXCEPTIONS (t2),
+ NULL_TREE);
tree t3;
/* If this was a member function type, get back to the
/* First handle noexcept. */
if (exact < ce_exact)
{
- /* noexcept(false) is compatible with any throwing dynamic-exc-spec
+ /* noexcept(false) is compatible with no exception-specification,
and stricter than any spec. */
if (t1 == noexcept_false_spec)
- return !nothrow_spec_p (t2) || exact == ce_derived;
- /* Even a derived noexcept(false) is compatible with a throwing
- dynamic spec. */
+ return t2 == NULL_TREE || exact == ce_derived;
+ /* Even a derived noexcept(false) is compatible with no
+ exception-specification. */
if (t2 == noexcept_false_spec)
- return !nothrow_spec_p (t1);
+ return t1 == NULL_TREE;
/* Otherwise, if we aren't looking for an exact match, noexcept is
equivalent to throw(). */
if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
TYPENAME_TYPE_FULLNAME (t2)))
return false;
- if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+ /* Qualifiers don't matter on scopes. */
+ if (!same_type_ignoring_top_level_qualifiers_p (TYPE_CONTEXT (t1),
+ TYPE_CONTEXT (t2)))
return false;
break;
break;
case TYPE_PACK_EXPANSION:
- return same_type_p (PACK_EXPANSION_PATTERN (t1),
- PACK_EXPANSION_PATTERN (t2));
+ return (same_type_p (PACK_EXPANSION_PATTERN (t1),
+ PACK_EXPANSION_PATTERN (t2))
+ && comp_template_args (PACK_EXPANSION_EXTRA_ARGS (t1),
+ PACK_EXPANSION_EXTRA_ARGS (t2)));
case DECLTYPE_TYPE:
if (DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t1)
!= DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t2)
|| (DECLTYPE_FOR_LAMBDA_CAPTURE (t1)
!= DECLTYPE_FOR_LAMBDA_CAPTURE (t2))
- || (DECLTYPE_FOR_LAMBDA_RETURN (t1)
- != DECLTYPE_FOR_LAMBDA_RETURN (t2))
+ || (DECLTYPE_FOR_LAMBDA_PROXY (t1)
+ != DECLTYPE_FOR_LAMBDA_PROXY (t2))
|| !cp_tree_equal (DECLTYPE_TYPE_EXPR (t1),
DECLTYPE_TYPE_EXPR (t2)))
return false;
break;
+ case UNDERLYING_TYPE:
+ return same_type_p (UNDERLYING_TYPE_TYPE (t1),
+ UNDERLYING_TYPE_TYPE (t2));
+
default:
return false;
}
/* If we get here, we know that from a target independent POV the
types are the same. Make sure the target attributes are also
the same. */
- return targetm.comp_type_attributes (t1, t2);
+ return comp_type_attributes (t1, t2);
}
/* Return true if T1 and T2 are related as allowed by STRICT. STRICT
unlowered_expr_type (const_tree exp)
{
tree type;
+ tree etype = TREE_TYPE (exp);
type = is_bitfield_expr_with_lowered_type (exp);
- if (!type)
- type = TREE_TYPE (exp);
+ if (type)
+ type = cp_build_qualified_type (type, cp_type_quals (etype));
+ else
+ type = etype;
return type;
}
/* FIXME remove? at least need to remember that this isn't really a
constant expression if EXP isn't decl_constant_var_p, like with
C_MAYBE_CONST_EXPR. */
- exp = decl_constant_value (exp);
+ exp = decl_constant_value_safe (exp);
if (error_operand_p (exp))
return error_mark_node;
if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
type = TREE_TYPE (expr);
gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
+ /* Scoped enums don't promote. */
+ if (SCOPED_ENUM_P (type))
+ return expr;
promoted_type = type_promotes_to (type);
if (type != promoted_type)
expr = cp_convert (promoted_type, expr);
? LE_EXPR : GE_EXPR),
op0, TREE_CODE (op0),
op1, TREE_CODE (op1),
- /*overloaded_p=*/NULL,
+ /*overload=*/NULL,
complain),
cp_build_unary_op (code, op0, 0, complain),
cp_build_unary_op (code, op1, 0, complain),
tree object_type;
tree member_scope;
tree result = NULL_TREE;
+ tree using_decl = NULL_TREE;
if (error_operand_p (object) || error_operand_p (member))
return error_mark_node;
if (!CLASS_TYPE_P (object_type))
{
if (complain & tf_error)
- error ("request for member %qD in %qE, which is of non-class type %qT",
- member, object, object_type);
+ {
+ if (POINTER_TYPE_P (object_type)
+ && CLASS_TYPE_P (TREE_TYPE (object_type)))
+ error ("request for member %qD in %qE, which is of pointer "
+ "type %qT (maybe you meant to use %<->%> ?)",
+ member, object, object_type);
+ else
+ error ("request for member %qD in %qE, which is of non-class "
+ "type %qT", member, object, object_type);
+ }
return error_mark_node;
}
/* Convert to the base. */
object = build_base_path (PLUS_EXPR, object, binfo,
- /*nonnull=*/1);
+ /*nonnull=*/1, complain);
/* If we found the base successfully then we should be able
to convert to it successfully. */
gcc_assert (object != error_mark_node);
result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
object, result);
}
+ else if ((using_decl = strip_using_decl (member)) != member)
+ result = build_class_member_access_expr (object,
+ using_decl,
+ access_path, preserve_reference,
+ complain);
else
{
if (complain & tf_error)
return error_mark_node;
}
expr = lookup_member (dtor_type, complete_dtor_identifier,
- /*protect=*/1, /*want_type=*/false);
+ /*protect=*/1, /*want_type=*/false,
+ tf_warning_or_error);
expr = (adjust_result_of_qualified_name_lookup
(expr, dtor_type, object_type));
return expr;
if (!CLASS_TYPE_P (object_type))
{
if (complain & tf_error)
- error ("request for member %qD in %qE, which is of non-class type %qT",
- name, object, object_type);
+ {
+ if (POINTER_TYPE_P (object_type)
+ && CLASS_TYPE_P (TREE_TYPE (object_type)))
+ error ("request for member %qD in %qE, which is of pointer "
+ "type %qT (maybe you meant to use %<->%> ?)",
+ name, object, object_type);
+ else
+ error ("request for member %qD in %qE, which is of non-class "
+ "type %qT", name, object, object_type);
+ }
return error_mark_node;
}
{
/* Look up the member. */
member = lookup_member (access_path, name, /*protect=*/1,
- /*want_type=*/false);
+ /*want_type=*/false, complain);
if (member == NULL_TREE)
{
if (complain & tf_error)
- error ("%qD has no member named %qE", object_type, name);
+ error ("%qD has no member named %qE",
+ TREE_CODE (access_path) == TREE_BINFO
+ ? TREE_TYPE (access_path) : object_type, name);
return error_mark_node;
}
if (member == error_mark_node)
ptrmem_type = TREE_TYPE (ptrmem);
gcc_assert (TYPE_PTRMEMFUNC_P (ptrmem_type));
member = lookup_member (ptrmem_type, member_name, /*protect=*/0,
- /*want_type=*/false);
+ /*want_type=*/false, tf_warning_or_error);
member_type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (ptrmem_type));
return fold_build3_loc (input_location,
if (processing_template_decl)
{
- /* Retain the type if we know the operand is a pointer so that
- describable_type doesn't make auto deduction break. */
+ /* Retain the type if we know the operand is a pointer. */
if (TREE_TYPE (expr) && POINTER_TYPE_P (TREE_TYPE (expr)))
return build_min (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr);
if (type_dependent_expression_p (expr))
}
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
- NULL_TREE, /*overloaded_p=*/NULL, complain);
+ NULL_TREE, /*overload=*/NULL, complain);
if (!rval)
rval = cp_build_indirect_ref (expr, errorstring, complain);
/* Helper function called from c-common. */
tree
-build_indirect_ref (location_t loc __attribute__ ((__unused__)),
+build_indirect_ref (location_t loc ATTRIBUTE_UNUSED,
tree ptr, ref_operator errorstring)
{
return cp_build_indirect_ref (ptr, errorstring, tf_warning_or_error);
gcc_unreachable ();
}
else if (pointer != error_mark_node)
- switch (errorstring)
- {
- case RO_NULL:
- error ("invalid type argument");
- break;
- case RO_ARRAY_INDEXING:
- error ("invalid type argument of array indexing");
- break;
- case RO_UNARY_STAR:
- error ("invalid type argument of unary %<*%>");
- break;
- case RO_IMPLICIT_CONVERSION:
- error ("invalid type argument of implicit conversion");
- break;
- default:
- gcc_unreachable ();
- }
+ invalid_indirection_error (input_location, type, errorstring);
+
return error_mark_node;
}
basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
basetype, ba_check, NULL);
instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype,
- 1);
+ 1, tf_warning_or_error);
if (instance_ptr == error_mark_node)
return error_mark_node;
}
/* ...and then the delta in the PMF. */
- instance_ptr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (instance_ptr),
- instance_ptr, fold_convert (sizetype, delta));
+ instance_ptr = fold_build_pointer_plus (instance_ptr, delta);
/* Hand back the adjusted 'this' argument to our caller. */
*instance_ptrptr = instance_ptr;
TREE_NO_WARNING (vtbl) = 1;
/* Finally, extract the function pointer from the vtable. */
- e2 = fold_build2_loc (input_location,
- POINTER_PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
- fold_convert (sizetype, idx));
+ e2 = fold_build_pointer_plus_loc (input_location, vtbl, idx);
e2 = cp_build_indirect_ref (e2, RO_NULL, tf_warning_or_error);
TREE_CONSTANT (e2) = 1;
/* Check for errors in format strings and inappropriately
null parameters. */
- check_function_arguments (TYPE_ATTRIBUTES (fntype), nargs, argarray,
- parm_types);
+ check_function_arguments (fntype, nargs, argarray);
ret = build_cxx_call (function, nargs, argarray);
tree
build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
- tree arg2, enum tree_code arg2_code, bool *overloaded_p,
+ tree arg2, enum tree_code arg2_code, tree *overload,
tsubst_flags_t complain)
{
tree orig_arg1;
expr = build_m_component_ref (arg1, arg2);
else
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
- overloaded_p, complain);
+ overload, complain);
/* Check for cases such as x+y<<z which users are likely to
misinterpret. But don't warn about obj << x + y, since that is a
}
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
- /*overloaded_p=*/NULL, complain);
+ /*overload=*/NULL, complain);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2,
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|| code == TRUTH_XOR_EXPR)
{
- if (!really_overloaded_fn (op0))
+ if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0)))
op0 = decay_conversion (op0);
- if (!really_overloaded_fn (op1))
+ if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1)))
op1 = decay_conversion (op1);
}
else
{
- if (!really_overloaded_fn (op0))
+ if (!really_overloaded_fn (op0) && !VOID_TYPE_P (TREE_TYPE (op0)))
op0 = default_conversion (op0);
- if (!really_overloaded_fn (op1))
+ if (!really_overloaded_fn (op1) && !VOID_TYPE_P (TREE_TYPE (op1)))
op1 = default_conversion (op1);
}
else
{
op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
- op1 = cp_convert (TREE_TYPE (op0), integer_zero_node);
+ op1 = cp_convert (TREE_TYPE (op0), op1);
}
result_type = TREE_TYPE (op0);
}
result_type = composite_pointer_type (type0, type1, op0, op1,
CPO_COMPARISON, complain);
else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
- result_type = type0;
+ {
+ result_type = type0;
+ if (extra_warnings && (complain & tf_warning))
+ warning (OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
+ }
else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
- result_type = type1;
+ {
+ result_type = type1;
+ if (extra_warnings && (complain & tf_warning))
+ warning (OPT_Wextra,
+ "ordered comparison of pointer with integer zero");
+ }
else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
/* One of the operands must be of nullptr_t type. */
result_type = TREE_TYPE (nullptr_node);
{
case MULT_EXPR:
case TRUNC_DIV_EXPR:
+ op1 = save_expr (op1);
imag = build2 (resultcode, real_type, imag, op1);
/* Fall through. */
case PLUS_EXPR:
switch (code)
{
case MULT_EXPR:
+ op0 = save_expr (op0);
imag = build2 (resultcode, real_type, op0, imag);
/* Fall through. */
case PLUS_EXPR:
gcc_unreachable();
}
}
- return build2 (COMPLEX_EXPR, result_type, real, imag);
+ real = fold_if_not_in_template (real);
+ imag = fold_if_not_in_template (imag);
+ result = build2 (COMPLEX_EXPR, result_type, real, imag);
+ result = fold_if_not_in_template (result);
+ return result;
}
/* For certain operations (which identify themselves by shorten != 0)
/* Don't look for a function. */;
else
exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
- /*overloaded_p=*/NULL, complain);
+ /*overload=*/NULL, complain);
if (!exp && code == ADDR_EXPR)
{
if (is_overloaded_fn (xarg))
tree type = TREE_TYPE (expr);
if (TYPE_PTRMEM_P (type))
return build_binary_op (EXPR_LOCATION (expr),
- NE_EXPR, expr, integer_zero_node, 1);
+ NE_EXPR, expr, nullptr_node, 1);
+ else if (TYPE_PTR_P (type) || TYPE_PTRMEMFUNC_P (type))
+ {
+ /* With -Wzero-as-null-pointer-constant do not warn for an
+ 'if (p)' or a 'while (!p)', where p is a pointer. */
+ tree ret;
+ ++c_inhibit_evaluation_warnings;
+ ret = c_common_truthvalue_conversion (input_location, expr);
+ --c_inhibit_evaluation_warnings;
+ return ret;
+ }
else
return c_common_truthvalue_conversion (input_location, expr);
}
if (kind == clk_none)
{
if (complain & tf_error)
- lvalue_error (lv_addressof);
+ lvalue_error (input_location, lv_addressof);
return error_mark_node;
}
if (strict_lvalue && (kind & (clk_rvalueref|clk_class)))
&& TREE_CONSTANT (TREE_OPERAND (val, 0)))
{
tree type = build_pointer_type (argtype);
- tree op0 = fold_convert (type, TREE_OPERAND (val, 0));
- tree op1 = fold_convert (sizetype, fold_offsetof (arg, val));
- return fold_build2 (POINTER_PLUS_EXPR, type, op0, op1);
+ return fold_convert (type, fold_offsetof_1 (arg));
}
/* Handle complex lvalues (when permitted)
if (TREE_CODE (arg) == OFFSET_REF)
PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
}
- else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
+ else if (BASELINK_P (TREE_OPERAND (arg, 1)))
{
tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
break;
case REALPART_EXPR:
- if (TREE_CODE (arg) == COMPLEX_CST)
- return TREE_REALPART (arg);
- else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- {
- arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
- return fold_if_not_in_template (arg);
- }
- else
- return arg;
-
case IMAGPART_EXPR:
- if (TREE_CODE (arg) == COMPLEX_CST)
- return TREE_IMAGPART (arg);
- else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
- {
- arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
- return fold_if_not_in_template (arg);
- }
+ arg = build_real_imag_expr (input_location, code, arg);
+ if (arg == error_mark_node)
+ return arg;
else
- return cp_convert (TREE_TYPE (arg), integer_zero_node);
+ return fold_if_not_in_template (arg);
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
|| TREE_READONLY (arg))
{
if (complain & tf_error)
- readonly_error (arg, ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? REK_INCREMENT : REK_DECREMENT));
+ cxx_readonly_error (arg, ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? lv_increment : lv_decrement));
else
return error_mark_node;
}
inc = cp_convert (argtype, inc);
+ /* If 'arg' is an Objective-C PROPERTY_REF expression, then we
+ need to ask Objective-C to build the increment or decrement
+ expression for it. */
+ if (objc_is_property_ref (arg))
+ return objc_build_incr_expr_for_property_ref (input_location, code,
+ arg, inc);
+
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
}
val = boolean_increment (code, arg);
}
+ else if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+ /* An rvalue has no cv-qualifiers. */
+ val = build2 (code, cv_unqualified (TREE_TYPE (arg)), arg, inc);
else
val = build2 (code, TREE_TYPE (arg), arg, inc);
if (TREE_CODE (arg) == SAVE_EXPR)
targ = arg;
else
- targ = build_cplus_new (TREE_TYPE (arg), arg);
+ targ = build_cplus_new (TREE_TYPE (arg), arg, tf_warning_or_error);
return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ);
}
|| DECL_EXTERNAL (x));
/* Fall through. */
- case CONST_DECL:
case RESULT_DECL:
if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
&& !DECL_ARTIFICIAL (x))
TREE_ADDRESSABLE (x) = 1;
return true;
+ case CONST_DECL:
case FUNCTION_DECL:
TREE_ADDRESSABLE (x) = 1;
return true;
expr = build_conditional_expr (ifexp, op1, op2, complain);
if (processing_template_decl && expr != error_mark_node)
- return build_min_non_dep (COND_EXPR, expr,
- orig_ifexp, orig_op1, orig_op2);
+ {
+ tree min = build_min_non_dep (COND_EXPR, expr,
+ orig_ifexp, orig_op1, orig_op2);
+ /* Remember that the result is an lvalue or xvalue. */
+ if (lvalue_or_rvalue_with_address_p (expr)
+ && !lvalue_or_rvalue_with_address_p (min))
+ TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min),
+ !real_lvalue_p (expr));
+ expr = convert_from_reference (min);
+ }
return expr;
}
\f
{
tree expr = TREE_VALUE (list);
+ if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+ && !CONSTRUCTOR_IS_DIRECT_INIT (expr))
+ {
+ if (complain & tf_error)
+ pedwarn (EXPR_LOC_OR_HERE (expr), 0, "list-initializer for "
+ "non-class type must not be parenthesized");
+ else
+ return error_mark_node;
+ }
+
if (TREE_CHAIN (list))
{
if (complain & tf_error)
default:
gcc_unreachable ();
}
+ else
+ return error_mark_node;
for (list = TREE_CHAIN (list); list; list = TREE_CHAIN (list))
expr = build_x_compound_expr (expr, TREE_VALUE (list),
}
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
- /*overloaded_p=*/NULL, complain);
+ /*overload=*/NULL, complain);
if (!result)
result = cp_build_compound_expr (op1, op2, complain);
}
/* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
- casts away constness. CAST gives the type of cast.
+ casts away constness. CAST gives the type of cast. Returns true
+ if the cast is ill-formed, false if it is well-formed.
??? This function warns for casting away any qualifier not just
const. We would like to specify exactly what qualifiers are casted
away.
*/
-static void
+static bool
check_for_casting_away_constness (tree src_type, tree dest_type,
- enum tree_code cast)
+ enum tree_code cast, tsubst_flags_t complain)
{
/* C-style casts are allowed to cast away constness. With
WARN_CAST_QUAL, we still want to issue a warning. */
if (cast == CAST_EXPR && !warn_cast_qual)
- return;
+ return false;
if (!casts_away_constness (src_type, dest_type))
- return;
+ return false;
switch (cast)
{
case CAST_EXPR:
- warning (OPT_Wcast_qual,
- "cast from type %qT to type %qT casts away qualifiers",
- src_type, dest_type);
- return;
+ if (complain & tf_warning)
+ warning (OPT_Wcast_qual,
+ "cast from type %qT to type %qT casts away qualifiers",
+ src_type, dest_type);
+ return false;
case STATIC_CAST_EXPR:
- error ("static_cast from type %qT to type %qT casts away qualifiers",
- src_type, dest_type);
- return;
+ if (complain & tf_error)
+ error ("static_cast from type %qT to type %qT casts away qualifiers",
+ src_type, dest_type);
+ return true;
case REINTERPRET_CAST_EXPR:
- error ("reinterpret_cast from type %qT to type %qT casts away qualifiers",
- src_type, dest_type);
- return;
+ if (complain & tf_error)
+ error ("reinterpret_cast from type %qT to type %qT casts away qualifiers",
+ src_type, dest_type);
+ return true;
+
default:
gcc_unreachable();
}
/* Convert from "B*" to "D*". This function will check that "B"
is not a virtual base of "D". */
expr = build_base_path (MINUS_EXPR, build_address (expr),
- base, /*nonnull=*/false);
+ base, /*nonnull=*/false, complain);
/* Convert the pointer to a reference -- but then remember that
there are no expressions with reference type in C++.
return convert_from_reference (rvalue (cp_fold_convert (type, expr)));
}
- /* "An lvalue of type cv1 T1 can be cast to type rvalue reference to
+ /* "A glvalue of type cv1 T1 can be cast to type rvalue reference to
cv2 T2 if cv2 T2 is reference-compatible with cv1 T1 (8.5.3)." */
if (TREE_CODE (type) == REFERENCE_TYPE
&& TYPE_REF_IS_RVALUE (type)
- && real_lvalue_p (expr)
+ && lvalue_or_rvalue_with_address_p (expr)
&& reference_related_p (TREE_TYPE (type), intype)
&& (c_cast_p || at_least_as_qualified_p (TREE_TYPE (type), intype)))
{
{
tree base;
- if (!c_cast_p)
- check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
+ if (!c_cast_p
+ && check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR,
+ complain))
+ return error_mark_node;
base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
c_cast_p ? ba_unique : ba_check,
NULL);
- expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
+ expr = build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false,
+ complain);
return cp_fold_convert(type, expr);
}
}
if (can_convert (t1, t2) || can_convert (t2, t1))
{
- if (!c_cast_p)
- check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
+ if (!c_cast_p
+ && check_for_casting_away_constness (intype, type,
+ STATIC_CAST_EXPR,
+ complain))
+ return error_mark_node;
return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
- c_cast_p, tf_warning_or_error);
+ c_cast_p, complain);
}
}
&& VOID_TYPE_P (TREE_TYPE (intype))
&& TYPE_PTROB_P (type))
{
- if (!c_cast_p)
- check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
+ if (!c_cast_p
+ && check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR,
+ complain))
+ return error_mark_node;
return build_nop (type, expr);
}
{
tree sexpr = expr;
- if (!c_cast_p)
- check_for_casting_away_constness (intype, type, REINTERPRET_CAST_EXPR);
+ if (!c_cast_p
+ && check_for_casting_away_constness (intype, type,
+ REINTERPRET_CAST_EXPR,
+ complain))
+ return error_mark_node;
/* Warn about possible alignment problems. */
if (STRICT_ALIGNMENT && warn_cast_align
&& (complain & tf_warning)
whether or not the conversion succeeded. */
static tree
-build_const_cast_1 (tree dst_type, tree expr, bool complain,
+build_const_cast_1 (tree dst_type, tree expr, tsubst_flags_t complain,
bool *valid_p)
{
tree src_type;
if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
{
- if (complain)
+ if (complain & tf_error)
error ("invalid use of const_cast with type %qT, "
"which is not a pointer, "
"reference, nor a pointer-to-data-member type", dst_type);
if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
{
- if (complain)
+ if (complain & tf_error)
error ("invalid use of const_cast with type %qT, which is a pointer "
"or reference to a function type", dst_type);
return error_mark_node;
/* [expr.const.cast]
- An lvalue of type T1 can be explicitly converted to an lvalue of
- type T2 using the cast const_cast<T2&> (where T1 and T2 are object
- types) if a pointer to T1 can be explicitly converted to the type
- pointer to T2 using a const_cast. */
+ For two object types T1 and T2, if a pointer to T1 can be explicitly
+ converted to the type "pointer to T2" using a const_cast, then the
+ following conversions can also be made:
+
+ -- an lvalue of type T1 can be explicitly converted to an lvalue of
+ type T2 using the cast const_cast<T2&>;
+
+ -- a glvalue of type T1 can be explicitly converted to an xvalue of
+ type T2 using the cast const_cast<T2&&>; and
+
+ -- if T1 is a class type, a prvalue of type T1 can be explicitly
+ converted to an xvalue of type T2 using the cast const_cast<T2&&>. */
+
if (TREE_CODE (dst_type) == REFERENCE_TYPE)
{
reference_type = dst_type;
- if (! real_lvalue_p (expr))
+ if (!TYPE_REF_IS_RVALUE (dst_type)
+ ? real_lvalue_p (expr)
+ : (CLASS_TYPE_P (TREE_TYPE (dst_type))
+ ? lvalue_p (expr)
+ : lvalue_or_rvalue_with_address_p (expr)))
+ /* OK. */;
+ else
{
- if (complain)
+ if (complain & tf_error)
error ("invalid const_cast of an rvalue of type %qT to type %qT",
src_type, dst_type);
return error_mark_node;
return error_mark_node;
}
- if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
- && comp_ptr_ttypes_const (dst_type, src_type))
+ if (TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
{
- if (valid_p)
- {
- *valid_p = true;
- /* This cast is actually a C-style cast. Issue a warning if
- the user is making a potentially unsafe cast. */
- check_for_casting_away_constness (src_type, dst_type, CAST_EXPR);
- }
- if (reference_type)
- {
- expr = cp_build_addr_expr (expr,
- complain ? tf_warning_or_error : tf_none);
- expr = build_nop (reference_type, expr);
- return convert_from_reference (expr);
- }
- else
+ if (comp_ptr_ttypes_const (dst_type, src_type))
{
- expr = decay_conversion (expr);
- /* build_c_cast puts on a NOP_EXPR to make the result not an
- lvalue. Strip such NOP_EXPRs if VALUE is being used in
- non-lvalue context. */
- if (TREE_CODE (expr) == NOP_EXPR
- && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
- expr = TREE_OPERAND (expr, 0);
- return build_nop (dst_type, expr);
+ if (valid_p)
+ {
+ *valid_p = true;
+ /* This cast is actually a C-style cast. Issue a warning if
+ the user is making a potentially unsafe cast. */
+ check_for_casting_away_constness (src_type, dst_type,
+ CAST_EXPR, complain);
+ }
+ if (reference_type)
+ {
+ expr = cp_build_addr_expr (expr, complain);
+ expr = build_nop (reference_type, expr);
+ return convert_from_reference (expr);
+ }
+ else
+ {
+ expr = decay_conversion (expr);
+ /* build_c_cast puts on a NOP_EXPR to make the result not an
+ lvalue. Strip such NOP_EXPRs if VALUE is being used in
+ non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+ return build_nop (dst_type, expr);
+ }
}
+ else if (valid_p
+ && !at_least_as_qualified_p (TREE_TYPE (dst_type),
+ TREE_TYPE (src_type)))
+ check_for_casting_away_constness (src_type, dst_type, CAST_EXPR,
+ complain);
}
- if (complain)
+ if (complain & tf_error)
error ("invalid const_cast from type %qT to type %qT",
src_type, dst_type);
return error_mark_node;
return convert_from_reference (t);
}
- return build_const_cast_1 (type, expr, complain & tf_error,
+ return build_const_cast_1 (type, expr, complain,
/*valid_p=*/NULL);
}
"cast to pointer from integer of different size");
/* A C-style cast can be a const_cast. */
- result = build_const_cast_1 (type, value, /*complain=*/false,
+ result = build_const_cast_1 (type, value, complain & tf_warning,
&valid_p);
if (valid_p)
return result;
if (!CLASS_TYPE_P (type))
type = TYPE_MAIN_VARIANT (type);
result_type = TREE_TYPE (result);
- if (!CLASS_TYPE_P (result_type))
+ if (!CLASS_TYPE_P (result_type) && TREE_CODE (type) != REFERENCE_TYPE)
result_type = TYPE_MAIN_VARIANT (result_type);
/* If the type of RESULT does not match TYPE, perform a
const_cast to make it match. If the static_cast or
{
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
lhs, rhs, make_node (NOP_EXPR),
- /*overloaded_p=*/NULL,
+ /*overload=*/NULL,
complain);
if (result == NULL_TREE)
return error_mark_node;
}
else
{
+ tree init = NULL_TREE;
+
/* A binary op has been requested. Combine the old LHS
value with the RHS producing the value we should actually
store into the LHS. */
&& MAYBE_CLASS_TYPE_P (TREE_TYPE (lhstype)))
|| MAYBE_CLASS_TYPE_P (lhstype)));
+ /* Preevaluate the RHS to make sure its evaluation is complete
+ before the lvalue-to-rvalue conversion of the LHS:
+
+ [expr.ass] With respect to an indeterminately-sequenced
+ function call, the operation of a compound assignment is a
+ single evaluation. [ Note: Therefore, a function call shall
+ not intervene between the lvalue-to-rvalue conversion and the
+ side effect associated with any single compound assignment
+ operator. -- end note ] */
lhs = stabilize_reference (lhs);
+ if (TREE_SIDE_EFFECTS (rhs))
+ rhs = mark_rvalue_use (rhs);
+ rhs = stabilize_expr (rhs, &init);
newrhs = cp_build_binary_op (input_location,
modifycode, lhs, rhs,
complain);
return error_mark_node;
}
+ if (init)
+ newrhs = build2 (COMPOUND_EXPR, TREE_TYPE (newrhs), init, newrhs);
+
/* Now it looks like a plain assignment. */
modifycode = NOP_EXPR;
if (c_dialect_objc ())
&& C_TYPE_FIELDS_READONLY (lhstype))))
{
if (complain & tf_error)
- readonly_error (lhs, REK_ASSIGNMENT);
+ cxx_readonly_error (lhs, lv_assign);
else
return error_mark_node;
}
}
if (check_array_initializer (lhs, lhstype, newrhs))
return error_mark_node;
- newrhs = digest_init (lhstype, newrhs);
+ newrhs = digest_init (lhstype, newrhs, complain);
+ if (newrhs == error_mark_node)
+ return error_mark_node;
}
else if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
/* Allow array assignment in compiler-generated code. */
else if (!current_function_decl
- || !DECL_ARTIFICIAL (current_function_decl))
+ || !DECL_DEFAULTED_FN (current_function_decl))
{
/* This routine is used for both initialization and assignment.
Make sure the diagnostic message differentiates the context. */
{
if (TREE_CODE (newrhs) == CALL_EXPR
&& TYPE_NEEDS_CONSTRUCTING (lhstype))
- newrhs = build_cplus_new (lhstype, newrhs);
+ newrhs = build_cplus_new (lhstype, newrhs, complain);
/* Can't initialize directly from a TARGET_EXPR, since that would
cause the lhs to be constructed twice, and possibly result in
{
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
make_node (modifycode),
- /*overloaded_p=*/NULL,
+ /*overload=*/NULL,
complain);
if (rval)
{
/* Handle null pointer to member function conversions. */
if (null_ptr_cst_p (pfn))
{
- pfn = build_c_cast (input_location, type, integer_zero_node);
+ pfn = build_c_cast (input_location, type, nullptr_node);
return build_ptrmemfunc1 (to_type,
integer_zero_node,
pfn);
break;
case ICR_CONVERTING:
warning (OPT_Wmissing_format_attribute,
- "target of conversion might be might be a candidate "
+ "target of conversion might be a candidate "
"for a format attribute");
break;
case ICR_INIT:
if (fndecl)
savew = warningcount, savee = errorcount;
- rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE,
- /*cleanup=*/NULL, complain);
+ rhs = initialize_reference (type, rhs, flags, complain);
if (fndecl)
{
if (warningcount > savew)
return rhs;
if (MAYBE_CLASS_TYPE_P (type))
- return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+ return perform_implicit_conversion_flags (type, rhs, complain, flags);
return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
complain, flags);
tree type = lambda_return_type (retval);
tree oldtype = LAMBDA_EXPR_RETURN_TYPE (lambda);
- if (VOID_TYPE_P (type))
- { /* Nothing. */ }
- else if (oldtype == NULL_TREE)
- {
- pedwarn (input_location, OPT_pedantic, "lambda return type "
- "can only be deduced when the return statement is "
- "the only statement in the function body");
- apply_lambda_return_type (lambda, type);
- }
+ if (oldtype == NULL_TREE)
+ apply_lambda_return_type (lambda, type);
+ /* If one of the answers is type-dependent, we can't do any
+ better until instantiation time. */
+ else if (oldtype == dependent_lambda_return_type_node)
+ /* Leave it. */;
+ else if (type == dependent_lambda_return_type_node)
+ apply_lambda_return_type (lambda, type);
else if (!same_type_p (type, oldtype))
error ("inconsistent types %qT and %qT deduced for "
"lambda return type", type, oldtype);
/* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
treated as an rvalue for the purposes of overload resolution to
- favor move constructors over copy constructors. */
- if ((cxx_dialect != cxx98)
- && named_return_value_okay_p
- /* The variable must not have the `volatile' qualifier. */
- && !CP_TYPE_VOLATILE_P (TREE_TYPE (retval))
- /* The return type must be a class type. */
+ favor move constructors over copy constructors.
+
+ Note that these conditions are similar to, but not as strict as,
+ the conditions for the named return value optimization. */
+ if ((cxx_dialect != cxx98)
+ && (TREE_CODE (retval) == VAR_DECL
+ || TREE_CODE (retval) == PARM_DECL)
+ && DECL_CONTEXT (retval) == current_function_decl
+ && !TREE_STATIC (retval)
+ && same_type_p ((TYPE_MAIN_VARIANT (TREE_TYPE (retval))),
+ (TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_TYPE (current_function_decl)))))
+ /* This is only interesting for class type. */
&& CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
flags = flags | LOOKUP_PREFER_RVALUE;
so the usual checks are not appropriate. */
if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
{
- /* In Objective-C++, some types may have been 'volatilized' by
- the compiler for EH; when comparing them here, the volatile
- qualification must be ignored. */
- tree nv_to = objc_non_volatilized_type (to);
- tree nv_from = objc_non_volatilized_type (from);
-
- if (!at_least_as_qualified_p (nv_to, nv_from))
+ if (!at_least_as_qualified_p (to, from))
return 0;
- if (!at_least_as_qualified_p (nv_from, nv_to))
+ if (!at_least_as_qualified_p (from, to))
{
if (constp == 0)
return 0;
}
if (constp > 0)
- constp &= TYPE_READONLY (nv_to);
+ constp &= TYPE_READONLY (to);
}
if (TREE_CODE (to) == VECTOR_TYPE)
if (TREE_CODE (type) == FUNCTION_TYPE)
return TYPE_QUALS (type);
else if (TREE_CODE (type) == METHOD_TYPE)
- return cp_type_quals (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type))));
+ return cp_type_quals (class_of_this_parm (type));
else
gcc_unreachable ();
}
&& type_quals != TYPE_UNQUALIFIED));
/* Avoid setting TREE_READONLY incorrectly. */
- if (/* If the object has a constructor, the constructor may modify
- the object. */
- TYPE_NEEDS_CONSTRUCTING (type)
- /* If the type isn't complete, we don't know yet if it will need
- constructing. */
- || !COMPLETE_TYPE_P (type)
- /* If the type has a mutable component, that component might be
- modified. */
- || TYPE_HAS_MUTABLE_P (type))
+ /* We used to check TYPE_NEEDS_CONSTRUCTING here, but now a constexpr
+ constructor can produce constant init, so rely on cp_finish_decl to
+ clear TREE_READONLY if the variable has non-constant init. */
+
+ /* If the type has a mutable component, that component might be
+ modified. */
+ if (TYPE_HAS_MUTABLE_P (type))
type_quals &= ~TYPE_QUAL_CONST;
c_apply_type_quals_to_decl (type_quals, decl);
tree
non_reference (tree t)
{
- if (TREE_CODE (t) == REFERENCE_TYPE)
+ if (t && TREE_CODE (t) == REFERENCE_TYPE)
t = TREE_TYPE (t);
return t;
}
if (kind == clk_none)
{
if (complain & tf_error)
- lvalue_error (use);
+ lvalue_error (input_location, use);
return 0;
}
else if (kind & (clk_rvalueref|clk_class))
return 1;
}
+/* Return true if a user-defined literal operator is a raw operator. */
+
+bool
+check_raw_literal_operator (const_tree decl)
+{
+ tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ tree argtype;
+ int arity;
+ bool maybe_raw_p = false;
+
+ /* Count the number and type of arguments and check for ellipsis. */
+ for (argtype = argtypes, arity = 0;
+ argtype && argtype != void_list_node;
+ ++arity, argtype = TREE_CHAIN (argtype))
+ {
+ tree t = TREE_VALUE (argtype);
+
+ if (same_type_p (t, const_string_type_node))
+ maybe_raw_p = true;
+ }
+ if (!argtype)
+ return false; /* Found ellipsis. */
+
+ if (!maybe_raw_p || arity != 1)
+ return false;
+
+ return true;
+}
+
+
+/* Return true if a user-defined literal operator has one of the allowed
+ argument types. */
+
+bool
+check_literal_operator_args (const_tree decl,
+ bool *long_long_unsigned_p, bool *long_double_p)
+{
+ tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ if (processing_template_decl || processing_specialization)
+ return argtypes == void_list_node;
+ else
+ {
+ tree argtype;
+ int arity;
+ int max_arity = 2;
+
+ *long_long_unsigned_p = false;
+ *long_double_p = false;
+
+ /* Count the number and type of arguments and check for ellipsis. */
+ for (argtype = argtypes, arity = 0;
+ argtype && argtype != void_list_node;
+ argtype = TREE_CHAIN (argtype))
+ {
+ tree t = TREE_VALUE (argtype);
+ ++arity;
+
+ if (TREE_CODE (t) == POINTER_TYPE)
+ {
+ bool maybe_raw_p = false;
+ t = TREE_TYPE (t);
+ if (cp_type_quals (t) != TYPE_QUAL_CONST)
+ return false;
+ t = TYPE_MAIN_VARIANT (t);
+ if ((maybe_raw_p = same_type_p (t, char_type_node))
+ || same_type_p (t, wchar_type_node)
+ || same_type_p (t, char16_type_node)
+ || same_type_p (t, char32_type_node))
+ {
+ argtype = TREE_CHAIN (argtype);
+ if (!argtype)
+ return false;
+ t = TREE_VALUE (argtype);
+ if (maybe_raw_p && argtype == void_list_node)
+ return true;
+ else if (same_type_p (t, size_type_node))
+ {
+ ++arity;
+ continue;
+ }
+ else
+ return false;
+ }
+ }
+ else if (same_type_p (t, long_long_unsigned_type_node))
+ {
+ max_arity = 1;
+ *long_long_unsigned_p = true;
+ }
+ else if (same_type_p (t, long_double_type_node))
+ {
+ max_arity = 1;
+ *long_double_p = true;
+ }
+ else if (same_type_p (t, char_type_node))
+ max_arity = 1;
+ else if (same_type_p (t, wchar_type_node))
+ max_arity = 1;
+ else if (same_type_p (t, char16_type_node))
+ max_arity = 1;
+ else if (same_type_p (t, char32_type_node))
+ max_arity = 1;
+ else
+ return false;
+ }
+ if (!argtype)
+ return false; /* Found ellipsis. */
+
+ if (arity != max_arity)
+ return false;
+
+ return true;
+ }
+}
+