/* 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
+ 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-common.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
#include "params.h"
static tree pfn_from_ptrmemfunc (tree);
static tree delta_from_ptrmemfunc (tree);
-static tree convert_for_assignment (tree, tree, const char *, tree, int,
+static tree convert_for_assignment (tree, tree, impl_conv_rhs, tree, int,
tsubst_flags_t, int);
static tree cp_pointer_int_sum (enum tree_code, tree, tree);
static tree rationalize_conditional_expr (enum tree_code, tree,
static bool comp_except_types (tree, tree, bool);
static bool comp_array_types (const_tree, const_tree, bool);
static tree pointer_diff (tree, tree, tree);
-static tree get_delta_difference (tree, tree, bool, bool);
+static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
static void casts_away_constness_r (tree *, tree *);
static bool casts_away_constness (tree, tree);
static void maybe_warn_about_returning_address_of_local (tree);
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.)
- Returns the error_mark_node if the VALUE does not have
+ Returns error_mark_node if the VALUE does not have
complete type when this function returns. */
tree
-require_complete_type (tree value)
+require_complete_type_sfinae (tree value, tsubst_flags_t complain)
{
tree type;
if (COMPLETE_TYPE_P (type))
return value;
- if (complete_type_or_else (type, value))
+ if (complete_type_or_maybe_complain (type, value, complain))
return value;
else
return error_mark_node;
}
+tree
+require_complete_type (tree value)
+{
+ return require_complete_type_sfinae (value, tf_warning_or_error);
+}
+
/* Try to complete TYPE, if it is incomplete. For example, if TYPE is
a template instantiation, do the instantiation. Returns TYPE,
whether or not it could be completed, unless something goes
Returns NULL_TREE if the type cannot be made complete. */
tree
-complete_type_or_else (tree type, tree value)
+complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
{
type = complete_type (type);
if (type == error_mark_node)
return NULL_TREE;
else if (!COMPLETE_TYPE_P (type))
{
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ if (complain & tf_error)
+ cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
return NULL_TREE;
}
else
return type;
}
+tree
+complete_type_or_else (tree type, tree value)
+{
+ return complete_type_or_maybe_complain (type, value, tf_warning_or_error);
+}
+
/* Return truthvalue of whether type of EXP is instantiated. */
int
enum tree_code code2 = TREE_CODE (t2);
tree attributes;
+
/* In what follows, we slightly generalize the rules given in [expr] so
as to deal with `long long' and `complex'. First, merge the
attributes. */
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);
}
if (c_dialect_objc () && TREE_CODE (t1) == POINTER_TYPE
&& TREE_CODE (t2) == POINTER_TYPE)
{
- if (objc_compare_types (t1, t2, -3, NULL_TREE))
- return t1;
+ if (objc_have_common_type (t1, t2, -3, NULL_TREE))
+ return objc_common_type (t1, t2);
}
/* [expr.eq] permits the application of a pointer conversion to
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
const_tree probe;
const_tree base;
int length = 0;
- const_tree noexcept_spec = NULL_TREE;
- const_tree other_spec;
if (t1 == t2)
return true;
- /* First test noexcept compatibility. */
- if (t1 && TREE_PURPOSE (t1))
- noexcept_spec = t1, other_spec = t2;
- else if (t2 && TREE_PURPOSE (t2))
- noexcept_spec = t2, other_spec = t1;
- if (noexcept_spec)
- {
- tree p = TREE_PURPOSE (noexcept_spec);
- /* Two noexcept-specs are equivalent iff their exprs are. */
- if (other_spec && TREE_PURPOSE (other_spec))
- return cp_tree_equal (p, TREE_PURPOSE (other_spec));
- /* noexcept(true) is compatible with throw(). */
- else if (exact < ce_exact && p == boolean_true_node)
- return nothrow_spec_p (other_spec);
- /* noexcept(false) is compatible with any throwing
- dynamic-exception-spec. */
- else if (exact < ce_exact && p == boolean_false_node)
- return !nothrow_spec_p (other_spec);
- /* A dependent noexcept-spec is not compatible with any
- dynamic-exception-spec. */
- else
- return false;
- }
+ /* First handle noexcept. */
+ if (exact < ce_exact)
+ {
+ /* noexcept(false) is compatible with no exception-specification,
+ and stricter than any spec. */
+ if (t1 == noexcept_false_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 t1 == NULL_TREE;
+
+ /* Otherwise, if we aren't looking for an exact match, noexcept is
+ equivalent to throw(). */
+ if (t1 == noexcept_true_spec)
+ t1 = empty_except_spec;
+ if (t2 == noexcept_true_spec)
+ t2 = empty_except_spec;
+ }
+
+ /* If any noexcept is left, it is only comparable to itself;
+ either we're looking for an exact match or we're redeclaring a
+ template with dependent noexcept. */
+ if ((t1 && TREE_PURPOSE (t1))
+ || (t2 && TREE_PURPOSE (t2)))
+ return (t1 && t2
+ && cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)));
if (t1 == NULL_TREE) /* T1 is ... */
return t2 == NULL_TREE || exact == ce_derived;
static bool
comp_template_parms_position (tree t1, tree t2)
{
+ tree index1, index2;
gcc_assert (t1 && t2
&& TREE_CODE (t1) == TREE_CODE (t2)
&& (TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM
|| TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM
|| TREE_CODE (t1) == TEMPLATE_TYPE_PARM));
- if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
- || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2)
- || (TEMPLATE_TYPE_PARAMETER_PACK (t1)
- != TEMPLATE_TYPE_PARAMETER_PACK (t2)))
- return false;
-
- return true;
-}
-
-/* Subroutine of incompatible_dependent_types_p.
- Return the template parameter of the dependent type T.
- If T is a typedef, return the template parameters of
- the _decl_ of the typedef. T must be a dependent type. */
-
-static tree
-get_template_parms_of_dependent_type (tree t)
-{
- tree tinfo = NULL_TREE, tparms = NULL_TREE;
-
- /* First, try the obvious case of getting the
- template info from T itself. */
- if ((tinfo = get_template_info (t)))
- ;
- else if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
- return TEMPLATE_TYPE_PARM_SIBLING_PARMS (t);
- else if (typedef_variant_p (t)
- && !NAMESPACE_SCOPE_P (TYPE_NAME (t)))
- tinfo = get_template_info (DECL_CONTEXT (TYPE_NAME (t)));
- /* If T is a TYPENAME_TYPE which context is a template type
- parameter, get the template parameters from that context. */
- else if (TYPE_CONTEXT (t)
- && TREE_CODE (TYPE_CONTEXT (t)) == TEMPLATE_TYPE_PARM)
- return TEMPLATE_TYPE_PARM_SIBLING_PARMS (TYPE_CONTEXT (t));
- else if (TYPE_CONTEXT (t)
- && !NAMESPACE_SCOPE_P (t))
- tinfo = get_template_info (TYPE_CONTEXT (t));
-
- if (tinfo)
- tparms = DECL_TEMPLATE_PARMS (TI_TEMPLATE (tinfo));
-
- return tparms;
-}
-
-/* Subroutine of structural_comptypes.
- Compare the dependent types T1 and T2.
- Return TRUE if we are sure they can't be equal, FALSE otherwise.
- The whole point of this function is to support cases where either T1 or
- T2 is a typedef. In those cases, we need to compare the template parameters
- of the _decl_ of the typedef. If those don't match then we know T1
- and T2 cannot be equal. */
-
-static bool
-incompatible_dependent_types_p (tree t1, tree t2)
-{
- tree tparms1 = NULL_TREE, tparms2 = NULL_TREE;
- bool t1_typedef_variant_p, t2_typedef_variant_p;
-
- if (!uses_template_parms (t1) || !uses_template_parms (t2))
- return false;
-
- if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM)
- {
- /* If T1 and T2 don't have the same relative position in their
- template parameters set, they can't be equal. */
- if (!comp_template_parms_position (t1, t2))
- return true;
- }
-
- t1_typedef_variant_p = typedef_variant_p (t1);
- t2_typedef_variant_p = typedef_variant_p (t2);
+ index1 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t1));
+ index2 = TEMPLATE_TYPE_PARM_INDEX (TYPE_MAIN_VARIANT (t2));
- /* Either T1 or T2 must be a typedef. */
- if (!t1_typedef_variant_p && !t2_typedef_variant_p)
+ /* If T1 and T2 belong to template parm lists of different size,
+ let's assume they are different. */
+ if (TEMPLATE_PARM_NUM_SIBLINGS (index1)
+ != TEMPLATE_PARM_NUM_SIBLINGS (index2))
return false;
- if (!t1_typedef_variant_p || !t2_typedef_variant_p)
- /* Either T1 or T2 is not a typedef so we cannot compare the
- the template parms of the typedefs of T1 and T2.
- At this point, if the main variant type of T1 and T2 are equal
- it means the two types can't be incompatible, from the perspective
- of this function. */
- if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
- return false;
-
- /* So if we reach this point, it means either T1 or T2 is a typedef variant.
- Let's compare their template parameters. */
-
- tparms1 = get_template_parms_of_dependent_type (t1);
- tparms2 = get_template_parms_of_dependent_type (t2);
-
- /* If T2 is a template type parm and if we could not get the template
- parms it belongs to, that means we have not finished parsing the
- full set of template parameters of the template declaration it
- belongs to yet. If we could get the template parms T1 belongs to,
- that mostly means T1 and T2 belongs to templates that are
- different and incompatible. */
- if (TREE_CODE (t1) == TEMPLATE_TYPE_PARM
- && (tparms1 == NULL_TREE || tparms2 == NULL_TREE)
- && tparms1 != tparms2)
- return true;
-
- if (tparms1 == NULL_TREE
- || tparms2 == NULL_TREE
- || tparms1 == tparms2)
+ /* Then compare their relative position. */
+ if (TEMPLATE_PARM_IDX (index1) != TEMPLATE_PARM_IDX (index2)
+ || TEMPLATE_PARM_LEVEL (index1) != TEMPLATE_PARM_LEVEL (index2)
+ || (TEMPLATE_PARM_PARAMETER_PACK (index1)
+ != TEMPLATE_PARM_PARAMETER_PACK (index2)))
return false;
- /* And now compare the mighty template parms! */
- return !comp_template_parms (tparms1, tparms2);
+ return true;
}
/* Subroutine in comptypes. */
if (TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
return false;
- /* If T1 and T2 are dependent typedefs then check upfront that
- the template parameters of their typedef DECLs match before
- going down checking their subtypes. */
- if (incompatible_dependent_types_p (t1, t2))
- return false;
-
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
qualifiers (just above). */
break;
case TEMPLATE_TYPE_PARM:
- /* If incompatible_dependent_types_p called earlier didn't decide
- T1 and T2 were different, they might be equal. */
+ /* If T1 and T2 don't have the same relative position in their
+ template parameters set, they can't be equal. */
+ if (!comp_template_parms_position (t1, t2))
+ return false;
break;
case TYPENAME_TYPE:
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
return structural_comptypes (t1, t2, strict);
}
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+ top-level qualifiers. */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+ if (type1 == error_mark_node || type2 == error_mark_node)
+ return false;
+
+ return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+}
+
/* Returns 1 if TYPE1 is at least as qualified as TYPE2. */
bool
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;
}
return error_mark_node;
}
- exp = decl_constant_value (exp);
+ /* 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_safe (exp);
if (error_operand_p (exp))
return error_mark_node;
+ if (NULLPTR_TYPE_P (type))
+ return nullptr_node;
+
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Leave such NOP_EXPRs, since RHS is being used in non-lvalue context. */
code = TREE_CODE (type);
if (invalid_nonstatic_memfn_p (exp, tf_warning_or_error))
return error_mark_node;
if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
- return cp_build_unary_op (ADDR_EXPR, exp, 0, tf_warning_or_error);
+ return cp_build_addr_expr (exp, tf_warning_or_error);
if (code == ARRAY_TYPE)
{
tree adr;
}
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
- adr = cp_build_unary_op (ADDR_EXPR, exp, 1, tf_warning_or_error);
+ adr = cp_build_addr_expr (exp, tf_warning_or_error);
return cp_convert (ptrtype, adr);
}
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 field;
- for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
{
if (TREE_STATIC (field))
continue;
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;
complete type). */
object_type = TREE_TYPE (object);
if (!currently_open_class (object_type)
- && !complete_type_or_else (object_type, object))
+ && !complete_type_or_maybe_complain (object_type, object, complain))
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;
return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
object = build_non_dependent_expr (object);
}
-
+ else if (c_dialect_objc ()
+ && TREE_CODE (name) == IDENTIFIER_NODE
+ && (expr = objc_maybe_build_component_ref (object, name)))
+ return expr;
+
/* [expr.ref]
The type of the first expression shall be "class object" (of a
complete type). */
if (!currently_open_class (object_type)
- && !complete_type_or_else (object_type, object))
+ && !complete_type_or_maybe_complain (object_type, object, complain))
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",
- 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;
}
|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
TREE_THIS_VOLATILE (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
- ret = require_complete_type (fold_if_not_in_template (rval));
+ ret = require_complete_type_sfinae (fold_if_not_in_template (rval),
+ complain);
protected_set_expr_location (ret, loc);
return ret;
}
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;
vtable entry is treated as a function pointer. */
if (TARGET_VTABLE_USES_DESCRIPTORS)
e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
- cp_build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1,
- tf_warning_or_error));
+ cp_build_addr_expr (e2, tf_warning_or_error));
e2 = fold_convert (TREE_TYPE (e3), e2);
e1 = build_conditional_expr (e1, e2, e3, tf_warning_or_error);
/* 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);
"declared here");
}
else
- error_at (loc, too_many_p ? G_("too many arguments to function")
- : G_("too few arguments to function"));
+ {
+ if (c_dialect_objc () && objc_message_selector ())
+ error_at (loc,
+ too_many_p
+ ? G_("too many arguments to method %q#D")
+ : G_("too few arguments to method %q#D"),
+ objc_message_selector ());
+ else
+ error_at (loc, too_many_p ? G_("too many arguments to function")
+ : G_("too few arguments to function"));
+ }
}
/* Convert the actual parameter expressions in the list VALUES to the
{
parmval = convert_for_initialization
(NULL_TREE, type, val, flags,
- "argument passing", fndecl, i, complain);
+ ICR_ARGPASS, fndecl, i, complain);
parmval = convert_for_arg_passing (type, parmval);
}
/* Don't do ellipsis conversion for __built_in_constant_p
as this will result in spurious errors for non-trivial
types. */
- val = require_complete_type (val);
+ val = require_complete_type_sfinae (val, complain);
else
val = convert_arg_to_ellipsis (val);
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);
}
tree e1 = cp_build_binary_op (location,
EQ_EXPR,
pfn0,
- fold_convert (TREE_TYPE (pfn0),
- integer_zero_node),
+ build_zero_cst (TREE_TYPE (pfn0)),
complain);
tree e2 = cp_build_binary_op (location,
BIT_AND_EXPR,
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);
}
complain);
e2 = cp_build_binary_op (location, EQ_EXPR,
pfn0,
- fold_convert (TREE_TYPE (pfn0),
- integer_zero_node),
+ build_zero_cst (TREE_TYPE (pfn0)),
complain);
e2 = cp_build_binary_op (location,
TRUTH_ANDIF_EXPR, e2, e1, complain);
e2 = cp_build_binary_op (location,
EQ_EXPR,
pfn0,
- fold_convert (TREE_TYPE (pfn0),
- integer_zero_node),
+ build_zero_cst (TREE_TYPE (pfn0)),
complain);
e1 = cp_build_binary_op (location,
TRUTH_ORIF_EXPR, e1, e2, complain);
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);
if (!result_type
&& arithmetic_types_p
&& (shorten || common || short_compare))
- result_type = cp_common_type (type0, type1);
+ {
+ result_type = cp_common_type (type0, type1);
+ do_warn_double_promotion (result_type, type0, type1,
+ "implicit conversion from %qT to %qT "
+ "to match other operand of binary "
+ "expression",
+ location);
+ }
if (!result_type)
{
{
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))
PTRMEM_OK_P (xarg) = ptrmem;
}
}
- else if (TREE_CODE (xarg) == TARGET_EXPR && (complain & tf_warning))
- warning (0, "taking address of temporary");
- exp = cp_build_unary_op (ADDR_EXPR, xarg, 0, complain);
+
+ exp = cp_build_addr_expr_strict (xarg, complain);
}
if (processing_template_decl && exp != error_mark_node)
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);
}
return build1 (NOP_EXPR, type, expr);
}
+/* Take the address of ARG, whatever that means under C++ semantics.
+ If STRICT_LVALUE is true, require an lvalue; otherwise, allow xvalues
+ and class rvalues as well.
+
+ Nothing should call this function directly; instead, callers should use
+ cp_build_addr_expr or cp_build_addr_expr_strict. */
+
+static tree
+cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
+{
+ tree argtype;
+ tree val;
+
+ if (!arg || error_operand_p (arg))
+ return error_mark_node;
+
+ arg = mark_lvalue_use (arg);
+ argtype = lvalue_type (arg);
+
+ gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
+ || !IDENTIFIER_OPNAME_P (arg));
+
+ if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
+ && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
+ {
+ /* They're trying to take the address of a unique non-static
+ member function. This is ill-formed (except in MS-land),
+ but let's try to DTRT.
+ Note: We only handle unique functions here because we don't
+ want to complain if there's a static overload; non-unique
+ cases will be handled by instantiate_type. But we need to
+ handle this case here to allow casts on the resulting PMF.
+ We could defer this in non-MS mode, but it's easier to give
+ a useful error here. */
+
+ /* Inside constant member functions, the `this' pointer
+ contains an extra const qualifier. TYPE_MAIN_VARIANT
+ is used here to remove this const from the diagnostics
+ and the created OFFSET_REF. */
+ tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
+ tree fn = get_first_fn (TREE_OPERAND (arg, 1));
+ mark_used (fn);
+
+ if (! flag_ms_extensions)
+ {
+ tree name = DECL_NAME (fn);
+ if (!(complain & tf_error))
+ return error_mark_node;
+ else if (current_class_type
+ && TREE_OPERAND (arg, 0) == current_class_ref)
+ /* An expression like &memfn. */
+ permerror (input_location, "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
+ permerror (input_location, "ISO C++ forbids taking the address of a bound member"
+ " function to form a pointer to member function."
+ " Say %<&%T::%D%>",
+ base, name);
+ }
+ arg = build_offset_ref (base, fn, /*address_p=*/true);
+ }
+
+ /* Uninstantiated types are all functions. Taking the
+ address of a function is a no-op, so just return the
+ argument. */
+ if (type_unknown_p (arg))
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
+
+ if (TREE_CODE (arg) == OFFSET_REF)
+ /* We want a pointer to member; bypass all the code for actually taking
+ the address of something. */
+ goto offset_ref;
+
+ /* Anything not already handled and not a true memory reference
+ is an error. */
+ if (TREE_CODE (argtype) != FUNCTION_TYPE
+ && TREE_CODE (argtype) != METHOD_TYPE)
+ {
+ cp_lvalue_kind kind = lvalue_kind (arg);
+ if (kind == clk_none)
+ {
+ if (complain & tf_error)
+ lvalue_error (input_location, lv_addressof);
+ return error_mark_node;
+ }
+ if (strict_lvalue && (kind & (clk_rvalueref|clk_class)))
+ {
+ if (!(complain & tf_error))
+ return error_mark_node;
+ if (kind & clk_class)
+ /* Make this a permerror because we used to accept it. */
+ permerror (input_location, "taking address of temporary");
+ else
+ error ("taking address of xvalue (rvalue reference)");
+ }
+ }
+
+ if (TREE_CODE (argtype) == REFERENCE_TYPE)
+ {
+ tree type = build_pointer_type (TREE_TYPE (argtype));
+ arg = build1 (CONVERT_EXPR, type, arg);
+ return arg;
+ }
+ else if (pedantic && DECL_MAIN_P (arg))
+ {
+ /* ARM $3.4 */
+ /* Apparently a lot of autoconf scripts for C++ packages do this,
+ so only complain if -pedantic. */
+ if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
+ pedwarn (input_location, OPT_pedantic,
+ "ISO C++ forbids taking address of function %<::main%>");
+ else if (flag_pedantic_errors)
+ return error_mark_node;
+ }
+
+ /* Let &* cancel out to simplify resulting code. */
+ if (TREE_CODE (arg) == INDIRECT_REF)
+ {
+ /* We don't need to have `current_class_ptr' wrapped in a
+ NON_LVALUE_EXPR node. */
+ if (arg == current_class_ref)
+ return current_class_ptr;
+
+ arg = TREE_OPERAND (arg, 0);
+ if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
+ {
+ tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
+ arg = build1 (CONVERT_EXPR, type, arg);
+ }
+ else
+ /* Don't let this be an lvalue. */
+ arg = rvalue (arg);
+ return arg;
+ }
+
+ /* ??? Cope with user tricks that amount to offsetof. */
+ if (TREE_CODE (argtype) != FUNCTION_TYPE
+ && TREE_CODE (argtype) != METHOD_TYPE
+ && argtype != unknown_type_node
+ && (val = get_base_address (arg))
+ && COMPLETE_TYPE_P (TREE_TYPE (val))
+ && TREE_CODE (val) == INDIRECT_REF
+ && TREE_CONSTANT (TREE_OPERAND (val, 0)))
+ {
+ tree type = build_pointer_type (argtype);
+ return fold_convert (type, fold_offsetof_1 (arg));
+ }
+
+ /* Handle complex lvalues (when permitted)
+ by reduction to simpler cases. */
+ val = unary_complex_lvalue (ADDR_EXPR, arg);
+ if (val != 0)
+ return val;
+
+ switch (TREE_CODE (arg))
+ {
+ CASE_CONVERT:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ /* Even if we're not being pedantic, we cannot allow this
+ extension when we're instantiating in a SFINAE
+ context. */
+ if (! lvalue_p (arg) && complain == tf_none)
+ {
+ if (complain & tf_error)
+ permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression");
+ else
+ return error_mark_node;
+ }
+ break;
+
+ case BASELINK:
+ arg = BASELINK_FUNCTIONS (arg);
+ /* Fall through. */
+
+ case OVERLOAD:
+ arg = OVL_CURRENT (arg);
+ break;
+
+ case OFFSET_REF:
+ offset_ref:
+ /* Turn a reference to a non-static data member into a
+ pointer-to-member. */
+ {
+ tree type;
+ tree t;
+
+ gcc_assert (PTRMEM_OK_P (arg));
+
+ t = TREE_OPERAND (arg, 1);
+ if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+ {
+ if (complain & tf_error)
+ error ("cannot create pointer to reference member %qD", t);
+ return error_mark_node;
+ }
+
+ type = build_ptrmem_type (context_for_name_lookup (t),
+ TREE_TYPE (t));
+ t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
+ return t;
+ }
+
+ default:
+ break;
+ }
+
+ if (argtype != error_mark_node)
+ argtype = build_pointer_type (argtype);
+
+ /* In a template, we are processing a non-dependent expression
+ so we can just form an ADDR_EXPR with the correct type. */
+ if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
+ {
+ val = build_address (arg);
+ if (TREE_CODE (arg) == OFFSET_REF)
+ PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
+ }
+ else if (BASELINK_P (TREE_OPERAND (arg, 1)))
+ {
+ tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
+
+ /* We can only get here with a single static member
+ function. */
+ gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (fn));
+ mark_used (fn);
+ val = build_address (fn);
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
+ /* Do not lose object's side effects. */
+ val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
+ TREE_OPERAND (arg, 0), val);
+ }
+ else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+ {
+ if (complain & tf_error)
+ error ("attempt to take address of bit-field structure member %qD",
+ TREE_OPERAND (arg, 1));
+ return error_mark_node;
+ }
+ else
+ {
+ tree object = TREE_OPERAND (arg, 0);
+ tree field = TREE_OPERAND (arg, 1);
+ gcc_assert (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (object), decl_type_context (field)));
+ val = build_address (arg);
+ }
+
+ if (TREE_CODE (argtype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+ {
+ build_ptrmemfunc_type (argtype);
+ val = build_ptrmemfunc (argtype, val, 0,
+ /*c_cast_p=*/false,
+ tf_warning_or_error);
+ }
+
+ return val;
+}
+
+/* Take the address of ARG if it has one, even if it's an rvalue. */
+
+tree
+cp_build_addr_expr (tree arg, tsubst_flags_t complain)
+{
+ return cp_build_addr_expr_1 (arg, 0, complain);
+}
+
+/* Take the address of ARG, but only if it's an lvalue. */
+
+tree
+cp_build_addr_expr_strict (tree arg, tsubst_flags_t complain)
+{
+ return cp_build_addr_expr_1 (arg, 1, complain);
+}
+
/* C++: Must handle pointers to members.
Perhaps type instantiation should be extended to handle conversion
tree val;
const char *invalid_op_diag;
- if (error_operand_p (arg))
+ if (!arg || error_operand_p (arg))
return error_mark_node;
if ((invalid_op_diag
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);
case ADDR_EXPR:
/* Note that this operation never does default_conversion
regardless of NOCONVERT. */
-
- argtype = lvalue_type (arg);
-
- arg = mark_lvalue_use (arg);
-
- if (TREE_CODE (arg) == OFFSET_REF)
- goto offset_ref;
-
- if (TREE_CODE (argtype) == REFERENCE_TYPE)
- {
- tree type = build_pointer_type (TREE_TYPE (argtype));
- arg = build1 (CONVERT_EXPR, type, arg);
- return arg;
- }
- else if (pedantic && DECL_MAIN_P (arg))
- {
- /* ARM $3.4 */
- /* Apparently a lot of autoconf scripts for C++ packages do this,
- so only complain if -pedantic. */
- if (complain & (flag_pedantic_errors ? tf_error : tf_warning))
- pedwarn (input_location, OPT_pedantic,
- "ISO C++ forbids taking address of function %<::main%>");
- else if (flag_pedantic_errors)
- return error_mark_node;
- }
-
- /* Let &* cancel out to simplify resulting code. */
- if (TREE_CODE (arg) == INDIRECT_REF)
- {
- /* We don't need to have `current_class_ptr' wrapped in a
- NON_LVALUE_EXPR node. */
- if (arg == current_class_ref)
- return current_class_ptr;
-
- arg = TREE_OPERAND (arg, 0);
- if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
- {
- tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg)));
- arg = build1 (CONVERT_EXPR, type, arg);
- }
- else
- /* Don't let this be an lvalue. */
- arg = rvalue (arg);
- return arg;
- }
-
- /* ??? Cope with user tricks that amount to offsetof. */
- if (TREE_CODE (argtype) != FUNCTION_TYPE
- && TREE_CODE (argtype) != METHOD_TYPE
- && argtype != unknown_type_node
- && (val = get_base_address (arg))
- && TREE_CODE (val) == INDIRECT_REF
- && 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);
- }
-
- /* Uninstantiated types are all functions. Taking the
- address of a function is a no-op, so just return the
- argument. */
-
- gcc_assert (TREE_CODE (arg) != IDENTIFIER_NODE
- || !IDENTIFIER_OPNAME_P (arg));
-
- if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
- && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
- {
- /* They're trying to take the address of a unique non-static
- member function. This is ill-formed (except in MS-land),
- but let's try to DTRT.
- Note: We only handle unique functions here because we don't
- want to complain if there's a static overload; non-unique
- cases will be handled by instantiate_type. But we need to
- handle this case here to allow casts on the resulting PMF.
- We could defer this in non-MS mode, but it's easier to give
- a useful error here. */
-
- /* Inside constant member functions, the `this' pointer
- contains an extra const qualifier. TYPE_MAIN_VARIANT
- is used here to remove this const from the diagnostics
- and the created OFFSET_REF. */
- tree base = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg, 0)));
- tree fn = get_first_fn (TREE_OPERAND (arg, 1));
- mark_used (fn);
-
- if (! flag_ms_extensions)
- {
- tree name = DECL_NAME (fn);
- if (!(complain & tf_error))
- return error_mark_node;
- else if (current_class_type
- && TREE_OPERAND (arg, 0) == current_class_ref)
- /* An expression like &memfn. */
- permerror (input_location, "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
- permerror (input_location, "ISO C++ forbids taking the address of a bound member"
- " function to form a pointer to member function."
- " Say %<&%T::%D%>",
- base, name);
- }
- arg = build_offset_ref (base, fn, /*address_p=*/true);
- }
-
- offset_ref:
- if (type_unknown_p (arg))
- return build1 (ADDR_EXPR, unknown_type_node, arg);
-
- /* Handle complex lvalues (when permitted)
- by reduction to simpler cases. */
- val = unary_complex_lvalue (code, arg);
- if (val != 0)
- return val;
-
- switch (TREE_CODE (arg))
- {
- CASE_CONVERT:
- case FLOAT_EXPR:
- case FIX_TRUNC_EXPR:
- /* Even if we're not being pedantic, we cannot allow this
- extension when we're instantiating in a SFINAE
- context. */
- if (! lvalue_p (arg) && complain == tf_none)
- {
- if (complain & tf_error)
- permerror (input_location, "ISO C++ forbids taking the address of a cast to a non-lvalue expression");
- else
- return error_mark_node;
- }
- break;
-
- case BASELINK:
- arg = BASELINK_FUNCTIONS (arg);
- /* Fall through. */
-
- case OVERLOAD:
- arg = OVL_CURRENT (arg);
- break;
-
- case OFFSET_REF:
- /* Turn a reference to a non-static data member into a
- pointer-to-member. */
- {
- tree type;
- tree t;
-
- if (!PTRMEM_OK_P (arg))
- return cp_build_unary_op (code, arg, 0, complain);
-
- t = TREE_OPERAND (arg, 1);
- if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
- {
- if (complain & tf_error)
- error ("cannot create pointer to reference member %qD", t);
- return error_mark_node;
- }
-
- type = build_ptrmem_type (context_for_name_lookup (t),
- TREE_TYPE (t));
- t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
- return t;
- }
-
- default:
- break;
- }
-
- /* Anything not already handled and not a true memory reference
- is an error. */
- if (TREE_CODE (argtype) != FUNCTION_TYPE
- && TREE_CODE (argtype) != METHOD_TYPE
- && TREE_CODE (arg) != OFFSET_REF
- && !lvalue_or_else (arg, lv_addressof, complain))
- return error_mark_node;
-
- if (argtype != error_mark_node)
- argtype = build_pointer_type (argtype);
-
- /* In a template, we are processing a non-dependent expression
- so we can just form an ADDR_EXPR with the correct type. */
- if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
- {
- val = build_address (arg);
- if (TREE_CODE (arg) == OFFSET_REF)
- PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
- }
- else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
- {
- tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
-
- /* We can only get here with a single static member
- function. */
- gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
- && DECL_STATIC_FUNCTION_P (fn));
- mark_used (fn);
- val = build_address (fn);
- if (TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
- /* Do not lose object's side effects. */
- val = build2 (COMPOUND_EXPR, TREE_TYPE (val),
- TREE_OPERAND (arg, 0), val);
- }
- else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
- {
- if (complain & tf_error)
- error ("attempt to take address of bit-field structure member %qD",
- TREE_OPERAND (arg, 1));
- return error_mark_node;
- }
- else
- {
- tree object = TREE_OPERAND (arg, 0);
- tree field = TREE_OPERAND (arg, 1);
- gcc_assert (same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (object), decl_type_context (field)));
- val = build_address (arg);
- }
-
- if (TREE_CODE (argtype) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
- {
- build_ptrmemfunc_type (argtype);
- val = build_ptrmemfunc (argtype, val, 0,
- /*c_cast_p=*/false);
- }
-
- return val;
+ return cp_build_addr_expr (arg, complain);
default:
break;
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
/* Given a list of expressions, return a compound expression
that performs them all and returns the value of the last of them. */
-tree build_x_compound_expr_from_list (tree list, const char *msg)
+tree
+build_x_compound_expr_from_list (tree list, expr_list_kind exp,
+ tsubst_flags_t complain)
{
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 (msg)
- permerror (input_location, "%s expression list treated as compound expression", msg);
+ if (complain & tf_error)
+ switch (exp)
+ {
+ case ELK_INIT:
+ permerror (input_location, "expression list treated as compound "
+ "expression in initializer");
+ break;
+ case ELK_MEM_INIT:
+ permerror (input_location, "expression list treated as compound "
+ "expression in mem-initializer");
+ break;
+ case ELK_FUNC_CAST:
+ permerror (input_location, "expression list treated as compound "
+ "expression in functional cast");
+ break;
+ 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),
- tf_warning_or_error);
+ complain);
}
return expr;
}
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);
tree
cp_build_compound_expr (tree lhs, tree rhs, tsubst_flags_t complain)
{
- lhs = convert_to_void (lhs, "left-hand operand of comma", complain);
+ lhs = convert_to_void (lhs, ICV_LEFT_OF_COMMA, complain);
if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
}
/* 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();
}
tree
convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
- bool c_cast_p)
+ bool c_cast_p, tsubst_flags_t complain)
{
if (TYPE_PTRMEM_P (type))
{
delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
TYPE_PTRMEM_CLASS_TYPE (type),
allow_inverse_p,
- c_cast_p);
+ c_cast_p, complain);
+ if (delta == error_mark_node)
+ return error_mark_node;
+
if (!integer_zerop (delta))
{
tree cond, op1, op2;
}
else
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
- allow_inverse_p, c_cast_p);
-}
-
-/* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
- a version of EXPR that has TREE_OVERFLOW set if it is set in ORIG.
- Otherwise, return EXPR unchanged. */
-
-static tree
-ignore_overflows (tree expr, tree orig)
-{
- if (TREE_CODE (expr) == INTEGER_CST
- && CONSTANT_CLASS_P (orig)
- && TREE_CODE (orig) != STRING_CST
- && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
- {
- if (!TREE_OVERFLOW (orig))
- /* Ensure constant sharing. */
- expr = build_int_cst_wide (TREE_TYPE (expr),
- TREE_INT_CST_LOW (expr),
- TREE_INT_CST_HIGH (expr));
- else
- {
- /* Avoid clobbering a shared constant. */
- expr = copy_node (expr);
- TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
- }
- }
- return expr;
+ allow_inverse_p, c_cast_p, complain);
}
/* Perform a static_cast from EXPR to TYPE. When C_CAST_P is true,
{
tree intype;
tree result;
- tree orig;
/* Assume the cast is valid. */
*valid_p = true;
/* 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 (cp_fold_convert (type, expr));
+ there are no expressions with reference type in C++.
+
+ We call rvalue so that there's an actual tree code
+ (NON_LVALUE_EXPR) for the static_cast; otherwise, if the operand
+ is a variable with the same type, the conversion would get folded
+ away, leaving just the variable and causing lvalue_kind to give
+ the wrong answer. */
+ 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)))
{
return convert_from_reference (expr);
}
- orig = expr;
-
/* Resolve overloaded address here rather than once in
implicit_conversion and again in the inverse code below. */
if (TYPE_PTRMEMFUNC_P (type) && type_unknown_p (expr))
{
result = convert_from_reference (result);
- /* Ignore any integer overflow caused by the cast. */
- result = ignore_overflows (result, orig);
-
/* [expr.static.cast]
If T is a reference type, the result is an lvalue; otherwise,
Any expression can be explicitly converted to type cv void. */
if (TREE_CODE (type) == VOID_TYPE)
- return convert_to_void (expr, /*implicit=*/NULL, complain);
+ return convert_to_void (expr, ICV_CAST, complain);
/* [expr.static.cast]
|| SCALAR_FLOAT_TYPE_P (type))
&& (INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
|| SCALAR_FLOAT_TYPE_P (intype)))
- {
- expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
-
- /* Ignore any integer overflow caused by the cast. */
- expr = ignore_overflows (expr, orig);
- return expr;
- }
+ return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
&& CLASS_TYPE_P (TREE_TYPE (type))
{
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);
- return 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 ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
}
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);
+ 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);
}
warning (0, "casting %qT to %qT does not dereference pointer",
intype, type);
- expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain);
+ expr = cp_build_addr_expr (expr, complain);
if (warn_strict_aliasing > 2)
strict_aliasing_warning (TREE_TYPE (expr), 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)
+ if (comp_ptr_ttypes_const (dst_type, src_type))
{
- *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_unary_op (ADDR_EXPR, expr, 0,
- complain? tf_warning_or_error : tf_none);
- 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);
+ 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
}
else
{
- lhs = require_complete_type (lhs);
+ lhs = require_complete_type_sfinae (lhs, complain);
if (lhs == error_mark_node)
return error_mark_node;
if (modifycode == NOP_EXPR)
{
+ if (c_dialect_objc ())
+ {
+ result = objc_maybe_build_modify_expr (lhs, rhs);
+ if (result)
+ return result;
+ }
+
/* `operator=' is not an inheritable operator. */
if (! MAYBE_CLASS_TYPE_P (lhstype))
/* Do the default thing. */;
{
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 ())
+ {
+ result = objc_maybe_build_modify_expr (lhs, newrhs);
+ if (result)
+ return result;
+ }
}
gcc_assert (TREE_CODE (lhstype) != REFERENCE_TYPE);
gcc_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE);
&& 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. */
/* Calls with INIT_EXPR are all direct-initialization, so don't set
LOOKUP_ONLYCONVERTING. */
newrhs = convert_for_initialization (lhs, olhstype, newrhs, LOOKUP_NORMAL,
- "initialization", NULL_TREE, 0,
+ ICR_INIT, NULL_TREE, 0,
complain);
else
- newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
+ newrhs = convert_for_assignment (olhstype, newrhs, ICR_ASSIGN,
NULL_TREE, 0, complain, LOOKUP_IMPLICIT);
if (!same_type_p (lhstype, olhstype))
{
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)
{
/* Helper function for get_delta_difference which assumes FROM is a base
class of TO. Returns a delta for the conversion of pointer-to-member
- of FROM to pointer-to-member of TO. If the conversion is invalid,
+ of FROM to pointer-to-member of TO. If the conversion is invalid and
+ tf_error is not set in COMPLAIN returns error_mark_node, otherwise
returns zero. If FROM is not a base class of TO, returns NULL_TREE.
- If C_CAST_P is true, this conversion is taking place as part of a C-style
- cast. */
+ If C_CAST_P is true, this conversion is taking place as part of a
+ C-style cast. */
static tree
-get_delta_difference_1 (tree from, tree to, bool c_cast_p)
+get_delta_difference_1 (tree from, tree to, bool c_cast_p,
+ tsubst_flags_t complain)
{
tree binfo;
base_kind kind;
+ base_access access = c_cast_p ? ba_unique : ba_check;
+
+ /* Note: ba_quiet does not distinguish between access control and
+ ambiguity. */
+ if (!(complain & tf_error))
+ access |= ba_quiet;
+
+ binfo = lookup_base (to, from, access, &kind);
- binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
if (kind == bk_inaccessible || kind == bk_ambig)
{
+ if (!(complain & tf_error))
+ return error_mark_node;
+
error (" in pointer to member function conversion");
return size_zero_node;
}
/* FROM is a virtual base class of TO. Issue an error or warning
depending on whether or not this is a reinterpret cast. */
{
+ if (!(complain & tf_error))
+ return error_mark_node;
+
error ("pointer to member conversion via virtual base %qT",
BINFO_TYPE (binfo_from_vbase (binfo)));
return size_zero_node;
}
}
- else
- return NULL_TREE;
+ else
+ return NULL_TREE;
}
/* Get difference in deltas for different pointer to member function
- types. Returns an integer constant of type PTRDIFF_TYPE_NODE. If
- the conversion is invalid, the constant is zero. If
- ALLOW_INVERSE_P is true, then allow reverse conversions as well.
- If C_CAST_P is true this conversion is taking place as part of a
- C-style cast.
+ types. If the conversion is invalid and tf_error is not set in
+ COMPLAIN, returns error_mark_node, otherwise returns an integer
+ constant of type PTRDIFF_TYPE_NODE and its value is zero if the
+ conversion is invalid. If ALLOW_INVERSE_P is true, then allow reverse
+ conversions as well. If C_CAST_P is true this conversion is taking
+ place as part of a C-style cast.
Note that the naming of FROM and TO is kind of backwards; the return
value is what we add to a TO in order to get a FROM. They are named
static tree
get_delta_difference (tree from, tree to,
bool allow_inverse_p,
- bool c_cast_p)
+ bool c_cast_p, tsubst_flags_t complain)
{
tree result;
/* Pointer to member of incomplete class is permitted*/
result = size_zero_node;
else
- result = get_delta_difference_1 (from, to, c_cast_p);
+ result = get_delta_difference_1 (from, to, c_cast_p, complain);
+
+ if (result == error_mark_node)
+ return error_mark_node;
if (!result)
{
if (!allow_inverse_p)
{
+ if (!(complain & tf_error))
+ return error_mark_node;
+
error_not_base_type (from, to);
error (" in pointer to member conversion");
- result = size_zero_node;
+ result = size_zero_node;
}
else
{
- result = get_delta_difference_1 (to, from, c_cast_p);
+ result = get_delta_difference_1 (to, from, c_cast_p, complain);
+
+ if (result == error_mark_node)
+ return error_mark_node;
if (result)
result = size_diffop_loc (input_location,
- size_zero_node, result);
+ size_zero_node, result);
else
{
+ if (!(complain & tf_error))
+ return error_mark_node;
+
error_not_base_type (from, to);
error (" in pointer to member conversion");
result = size_zero_node;
/* Pull the FIELD_DECLs out of the type. */
pfn_field = TYPE_FIELDS (type);
- delta_field = TREE_CHAIN (pfn_field);
+ delta_field = DECL_CHAIN (pfn_field);
/* Make sure DELTA has the type we want. */
delta = convert_and_check (delta_type_node, delta);
Return error_mark_node, if something goes wrong. */
tree
-build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
+build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p,
+ tsubst_flags_t complain)
{
tree fn;
tree pfn_type;
n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
force,
- c_cast_p);
+ c_cast_p, complain);
+ if (n == error_mark_node)
+ return error_mark_node;
/* We don't have to do any conversion to convert a
pointer-to-member to its own type. But, we don't want to
/* 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);
/* First, calculate the adjustment to the function's class. */
*delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
- /*c_cast_p=*/0);
+ /*c_cast_p=*/0, tf_warning_or_error);
if (!DECL_VIRTUAL_P (fn))
*pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
}
/* Convert value RHS to type TYPE as preparation for an assignment to
- an lvalue of type TYPE. ERRTYPE is a string to use in error
- messages: "assignment", "return", etc. If FNDECL is non-NULL, we
- are doing the conversion in order to pass the PARMNUMth argument of
- FNDECL. */
+ an lvalue of type TYPE. ERRTYPE indicates what kind of error the
+ implicit conversion is. If FNDECL is non-NULL, we are doing the
+ conversion in order to pass the PARMNUMth argument of FNDECL.
+ If FNDECL is NULL, we are doing the conversion in function pointer
+ argument passing, conversion in initialization, etc. */
static tree
convert_for_assignment (tree type, tree rhs,
- const char *errtype, tree fndecl, int parmnum,
+ impl_conv_rhs errtype, tree fndecl, int parmnum,
tsubst_flags_t complain, int flags)
{
tree rhstype;
if (TREE_CODE (type) == VECTOR_TYPE && coder == VECTOR_TYPE
&& vector_types_convertible_p (type, rhstype, true))
- return convert (type, rhs);
+ {
+ rhs = mark_rvalue_use (rhs);
+ return convert (type, rhs);
+ }
if (rhs == error_mark_node || rhstype == error_mark_node)
return error_mark_node;
if (c_dialect_objc ())
{
int parmno;
+ tree selector;
tree rname = fndecl;
- if (!strcmp (errtype, "assignment"))
- parmno = -1;
- else if (!strcmp (errtype, "initialization"))
- parmno = -2;
- else
- {
- tree selector = objc_message_selector ();
-
- parmno = parmnum;
-
- if (selector && parmno > 1)
- {
- rname = selector;
- parmno -= 1;
- }
+ switch (errtype)
+ {
+ case ICR_ASSIGN:
+ parmno = -1;
+ break;
+ case ICR_INIT:
+ parmno = -2;
+ break;
+ default:
+ selector = objc_message_selector ();
+ parmno = parmnum;
+ if (selector && parmno > 1)
+ {
+ rname = selector;
+ parmno -= 1;
+ }
}
if (objc_compare_types (type, rhstype, parmno, rname))
- return convert (type, rhs);
+ {
+ rhs = mark_rvalue_use (rhs);
+ return convert (type, rhs);
+ }
}
/* [expr.ass]
error ("cannot convert %qT to %qT for argument %qP to %qD",
rhstype, type, parmnum, fndecl);
else
- error ("cannot convert %qT to %qT in %s", rhstype, type,
- errtype);
+ switch (errtype)
+ {
+ case ICR_DEFAULT_ARGUMENT:
+ error ("cannot convert %qT to %qT in default argument",
+ rhstype, type);
+ break;
+ case ICR_ARGPASS:
+ error ("cannot convert %qT to %qT in argument passing",
+ rhstype, type);
+ break;
+ case ICR_CONVERTING:
+ error ("cannot convert %qT to %qT",
+ rhstype, type);
+ break;
+ case ICR_INIT:
+ error ("cannot convert %qT to %qT in initialization",
+ rhstype, type);
+ break;
+ case ICR_RETURN:
+ error ("cannot convert %qT to %qT in return",
+ rhstype, type);
+ break;
+ case ICR_ASSIGN:
+ error ("cannot convert %qT to %qT in assignment",
+ rhstype, type);
+ break;
+ default:
+ gcc_unreachable();
+ }
}
return error_mark_node;
}
&& coder == codel
&& check_missing_format_attribute (type, rhstype)
&& (complain & tf_warning))
- warning (OPT_Wmissing_format_attribute,
- "%s might be a candidate for a format attribute",
- errtype);
+ switch (errtype)
+ {
+ case ICR_ARGPASS:
+ case ICR_DEFAULT_ARGUMENT:
+ if (fndecl)
+ warning (OPT_Wmissing_format_attribute,
+ "parameter %qP of %qD might be a candidate "
+ "for a format attribute", parmnum, fndecl);
+ else
+ warning (OPT_Wmissing_format_attribute,
+ "parameter might be a candidate "
+ "for a format attribute");
+ break;
+ case ICR_CONVERTING:
+ warning (OPT_Wmissing_format_attribute,
+ "target of conversion might be a candidate "
+ "for a format attribute");
+ break;
+ case ICR_INIT:
+ warning (OPT_Wmissing_format_attribute,
+ "target of initialization might be a candidate "
+ "for a format attribute");
+ break;
+ case ICR_RETURN:
+ warning (OPT_Wmissing_format_attribute,
+ "return type might be a candidate "
+ "for a format attribute");
+ break;
+ case ICR_ASSIGN:
+ warning (OPT_Wmissing_format_attribute,
+ "left-hand side of assignment might be a candidate "
+ "for a format attribute");
+ break;
+ default:
+ gcc_unreachable();
+ }
}
/* If -Wparentheses, warn about a = b = c when a has type bool and b
&& TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE
&& (complain & tf_warning))
{
- location_t loc = EXPR_HAS_LOCATION (rhs)
- ? EXPR_LOCATION (rhs) : input_location;
+ location_t loc = EXPR_LOC_OR_HERE (rhs);
warning_at (loc, OPT_Wparentheses,
"suggest parentheses around assignment used as truth value");
/* Convert RHS to be of type TYPE.
If EXP is nonzero, it is the target of the initialization.
- ERRTYPE is a string to use in error messages.
+ ERRTYPE indicates what kind of error the implicit conversion is.
Two major differences between the behavior of
`convert_for_assignment' and `convert_for_initialization'
tree
convert_for_initialization (tree exp, tree type, tree rhs, int flags,
- const char *errtype, tree fndecl, int parmnum,
+ impl_conv_rhs errtype, tree fndecl, int parmnum,
tsubst_flags_t complain)
{
enum tree_code codel = TREE_CODE (type);
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)
}
if (exp != 0)
- exp = require_complete_type (exp);
+ exp = require_complete_type_sfinae (exp, complain);
if (exp == error_mark_node)
return error_mark_node;
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;
to the type of return value's location to handle the
case that functype is smaller than the valtype. */
retval = convert_for_initialization
- (NULL_TREE, functype, retval, flags, "return", NULL_TREE, 0,
+ (NULL_TREE, functype, retval, flags, ICR_RETURN, NULL_TREE, 0,
tf_warning_or_error);
retval = convert (valtype, retval);
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. */
- bool objc_quals_match = objc_type_quals_match (to, from);
-
- if (!at_least_as_qualified_p (to, from) && !objc_quals_match)
+ if (!at_least_as_qualified_p (to, from))
return 0;
- if (!at_least_as_qualified_p (from, to) && !objc_quals_match)
+ if (!at_least_as_qualified_p (from, to))
{
if (constp == 0)
return 0;
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;
}
int
lvalue_or_else (tree ref, enum lvalue_use use, tsubst_flags_t complain)
{
- int win = lvalue_p (ref);
+ cp_lvalue_kind kind = lvalue_kind (ref);
+
+ if (kind == clk_none)
+ {
+ if (complain & tf_error)
+ lvalue_error (input_location, use);
+ return 0;
+ }
+ else if (kind & (clk_rvalueref|clk_class))
+ {
+ if (!(complain & tf_error))
+ return 0;
+ if (kind & clk_class)
+ /* Make this a permerror because we used to accept it. */
+ permerror (input_location, "using temporary as lvalue");
+ else
+ error ("using xvalue (rvalue reference) as lvalue");
+ }
+ 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 (!win && (complain & tf_error))
- lvalue_error (use);
+ 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. */
- return win;
+ if (arity != max_arity)
+ return false;
+
+ return true;
+ }
}