/* Language-dependent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987-2017 Free Software Foundation, Inc.
+ Copyright (C) 1987-2019 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "stringpool.h"
#include "attribs.h"
#include "flags.h"
+#include "selftest.h"
static tree bot_manip (tree *, int *, void *);
static tree bot_replace (tree *, int *, void *);
static tree build_target_expr (tree, tree, tsubst_flags_t);
static tree count_trees_r (tree *, int *, void *);
static tree verify_stmt_tree_r (tree *, int *, void *);
-static tree build_local_temp (tree);
static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
return lvalue_kind (TREE_OPERAND (ref, 0));
if (TREE_TYPE (ref)
- && TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+ && TYPE_REF_P (TREE_TYPE (ref)))
{
/* unnamed rvalue references are rvalues */
if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref))
if (ref == current_class_ptr)
return clk_none;
+ /* Expressions with cv void type are prvalues. */
+ if (TREE_TYPE (ref) && VOID_TYPE_P (TREE_TYPE (ref)))
+ return clk_none;
+
switch (TREE_CODE (ref))
{
case SAVE_EXPR:
return clk_none;
+
/* preincrements and predecrements are valid lvals, provided
what they refer to are valid lvals. */
case PREINCREMENT_EXPR:
case TRY_CATCH_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
+ case VIEW_CONVERT_EXPR:
return lvalue_kind (TREE_OPERAND (ref, 0));
+ case ARRAY_REF:
+ {
+ tree op1 = TREE_OPERAND (ref, 0);
+ if (TREE_CODE (TREE_TYPE (op1)) == ARRAY_TYPE)
+ {
+ op1_lvalue_kind = lvalue_kind (op1);
+ if (op1_lvalue_kind == clk_class)
+ /* in the case of an array operand, the result is an lvalue if
+ that operand is an lvalue and an xvalue otherwise */
+ op1_lvalue_kind = clk_rvalueref;
+ return op1_lvalue_kind;
+ }
+ else
+ return clk_ordinary;
+ }
+
case MEMBER_REF:
case DOTSTAR_EXPR:
if (TREE_CODE (ref) == MEMBER_REF)
op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0));
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (TREE_OPERAND (ref, 1))))
op1_lvalue_kind = clk_none;
+ else if (op1_lvalue_kind == clk_class)
+ /* The result of a .* expression whose second operand is a pointer to a
+ data member is an lvalue if the first operand is an lvalue and an
+ xvalue otherwise. */
+ op1_lvalue_kind = clk_rvalueref;
return op1_lvalue_kind;
case COMPONENT_REF:
return lvalue_kind (TREE_OPERAND (ref, 1));
}
op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0));
+ if (op1_lvalue_kind == clk_class)
+ /* If E1 is an lvalue, then E1.E2 is an lvalue;
+ otherwise E1.E2 is an xvalue. */
+ op1_lvalue_kind = clk_rvalueref;
+
/* Look at the member designator. */
if (!op1_lvalue_kind)
;
/* FALLTHRU */
case INDIRECT_REF:
case ARROW_EXPR:
- case ARRAY_REF:
- case ARRAY_NOTATION_REF:
case PARM_DECL:
case RESULT_DECL:
case PLACEHOLDER_EXPR:
break;
case COND_EXPR:
- op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1)
- ? TREE_OPERAND (ref, 1)
- : TREE_OPERAND (ref, 0));
- op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 2));
+ if (processing_template_decl)
+ {
+ /* Within templates, a REFERENCE_TYPE will indicate whether
+ the COND_EXPR result is an ordinary lvalue or rvalueref.
+ Since REFERENCE_TYPEs are handled above, if we reach this
+ point, we know we got a plain rvalue. Unless we have a
+ type-dependent expr, that is, but we shouldn't be testing
+ lvalueness if we can't even tell the types yet! */
+ gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref)));
+ goto default_;
+ }
+ {
+ tree op1 = TREE_OPERAND (ref, 1);
+ if (!op1) op1 = TREE_OPERAND (ref, 0);
+ tree op2 = TREE_OPERAND (ref, 2);
+ op1_lvalue_kind = lvalue_kind (op1);
+ op2_lvalue_kind = lvalue_kind (op2);
+ if (!op1_lvalue_kind != !op2_lvalue_kind)
+ {
+ /* The second or the third operand (but not both) is a
+ throw-expression; the result is of the type
+ and value category of the other. */
+ if (op1_lvalue_kind && TREE_CODE (op2) == THROW_EXPR)
+ op2_lvalue_kind = op1_lvalue_kind;
+ else if (op2_lvalue_kind && TREE_CODE (op1) == THROW_EXPR)
+ op1_lvalue_kind = op2_lvalue_kind;
+ }
+ }
break;
case MODOP_EXPR:
return lvalue_kind (BASELINK_FUNCTIONS (CONST_CAST_TREE (ref)));
case NON_DEPENDENT_EXPR:
+ case PAREN_EXPR:
return lvalue_kind (TREE_OPERAND (ref, 0));
+ case TEMPLATE_PARM_INDEX:
+ if (CLASS_TYPE_P (TREE_TYPE (ref)))
+ /* A template parameter object is an lvalue. */
+ return clk_ordinary;
+ return clk_none;
+
default:
+ default_:
if (!TREE_TYPE (ref))
return clk_none;
if (CLASS_TYPE_P (TREE_TYPE (ref))
|| TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
return clk_class;
- break;
+ return clk_none;
}
/* If one operand is not an lvalue at all, then this expression is
tree
cp_stabilize_reference (tree ref)
{
+ STRIP_ANY_LOCATION_WRAPPER (ref);
switch (TREE_CODE (ref))
{
case NON_DEPENDENT_EXPR:
bool
builtin_valid_in_constant_expr_p (const_tree decl)
{
- if (!(TREE_CODE (decl) == FUNCTION_DECL
- && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL))
- /* Not a built-in. */
+ STRIP_ANY_LOCATION_WRAPPER (decl);
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ /* Not a function. */
return false;
+ if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
+ {
+ if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
+ BUILT_IN_FRONTEND))
+ return true;
+ /* Not a built-in. */
+ return false;
+ }
switch (DECL_FUNCTION_CODE (decl))
{
/* These always have constant results like the corresponding
|| useless_type_conversion_p (TREE_TYPE (decl),
TREE_TYPE (value)));
+ /* Set TREE_READONLY for optimization, such as gimplify_init_constructor
+ moving a constant aggregate into .rodata. */
+ if (CP_TYPE_CONST_NON_VOLATILE_P (type)
+ && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
+ && !VOID_TYPE_P (TREE_TYPE (value))
+ && reduced_constant_expression_p (value))
+ TREE_READONLY (decl) = true;
+
if (complain & tf_no_cleanup)
/* The caller is building a new-expr and does not need a cleanup. */
t = NULL_TREE;
return error_mark_node;
}
t = build4 (TARGET_EXPR, type, decl, value, t, NULL_TREE);
- if (EXPR_HAS_LOCATION (value))
- SET_EXPR_LOCATION (t, EXPR_LOCATION (value));
+ if (location_t eloc = cp_expr_location (value))
+ SET_EXPR_LOCATION (t, eloc);
/* We always set TREE_SIDE_EFFECTS so that expand_expr does not
ignore the TARGET_EXPR. If there really turn out to be no
side-effects, then the optimizer should be able to get rid of
/* Return an undeclared local temporary of type TYPE for use in building a
TARGET_EXPR. */
-static tree
+tree
build_local_temp (tree type)
{
tree slot = build_decl (input_location,
tree rval;
int is_ctor;
+ gcc_assert (!VOID_TYPE_P (type));
+
/* Don't build AGGR_INIT_EXPR in a template. */
if (processing_template_decl)
return init;
tree
build_cplus_new (tree type, tree init, tsubst_flags_t complain)
{
+ /* This function should cope with what build_special_member_call
+ can produce. When performing parenthesized aggregate initialization,
+ it can produce a { }. */
+ if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ {
+ gcc_assert (cxx_dialect >= cxx2a);
+ return finish_compound_literal (type, init, complain);
+ }
+
tree rval = build_aggr_init_expr (type, init);
tree slot;
+ if (init == error_mark_node)
+ return error_mark_node;
+
if (!complete_type_or_maybe_complain (type, init, complain))
return error_mark_node;
build_vec_init_elt (tree type, tree init, tsubst_flags_t complain)
{
tree inner_type = strip_array_types (type);
- vec<tree, va_gc> *argvec;
if (integer_zerop (array_type_nelts_total (type))
|| !CLASS_TYPE_P (inner_type))
|| (same_type_ignoring_top_level_qualifiers_p
(type, TREE_TYPE (init))));
- argvec = make_tree_vector ();
+ releasing_vec argvec;
if (init)
{
tree init_type = strip_array_types (TREE_TYPE (init));
init = build_special_member_call (NULL_TREE, complete_ctor_identifier,
&argvec, inner_type, LOOKUP_NORMAL,
complain);
- release_tree_vector (argvec);
/* For a trivial constructor, build_over_call creates a TARGET_EXPR. But
we don't want one here because we aren't creating a temporary. */
return build_cplus_array_type (elt, build_index_type (size_int (n - 1)));
}
-/* True iff T is an N3639 array of runtime bound (VLA). These were
- approved for C++14 but then removed. */
+/* True iff T is an N3639 array of runtime bound (VLA). These were approved
+ for C++14 but then removed. This should only be used for N3639
+ specifically; code wondering more generally if something is a VLA should use
+ vla_type_p. */
bool
array_of_runtime_bound_p (tree t)
{
if (!t || TREE_CODE (t) != ARRAY_TYPE)
return false;
+ if (variably_modified_type_p (TREE_TYPE (t), NULL_TREE))
+ return false;
tree dom = TYPE_DOMAIN (t);
if (!dom)
return false;
|| (!value_dependent_expression_p (max) && !TREE_CONSTANT (max)));
}
+/* True iff T is a variable length array. */
+
+bool
+vla_type_p (tree t)
+{
+ for (; t && TREE_CODE (t) == ARRAY_TYPE;
+ t = TREE_TYPE (t))
+ if (tree dom = TYPE_DOMAIN (t))
+ {
+ tree max = TYPE_MAX_VALUE (dom);
+ if (!potential_rvalue_constant_expression (max)
+ || (!value_dependent_expression_p (max) && !TREE_CONSTANT (max)))
+ return true;
+ }
+ return false;
+}
+
/* Return a reference type node referring to TO_TYPE. If RVAL is
true, return an rvalue reference type, otherwise return an lvalue
reference type. If a type node exists, reuse it, otherwise create
{
tree lvalue_ref, t;
- if (TREE_CODE (to_type) == REFERENCE_TYPE)
+ if (to_type == error_mark_node)
+ return error_mark_node;
+
+ if (TYPE_REF_P (to_type))
{
rval = rval && TYPE_REF_IS_RVALUE (to_type);
to_type = TREE_TYPE (to_type);
move (tree expr)
{
tree type = TREE_TYPE (expr);
- gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
+ gcc_assert (!TYPE_REF_P (type));
type = cp_build_reference_type (type, /*rval*/true);
return build_static_cast (type, expr, tf_warning_or_error);
}
[dcl.ref], [dcl.fct]. This used to be an error, but as of DR 295
(in CD1) we always ignore extra cv-quals on functions. */
if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)
- && (TREE_CODE (type) == REFERENCE_TYPE
- || TREE_CODE (type) == FUNCTION_TYPE
- || TREE_CODE (type) == METHOD_TYPE))
+ && (TYPE_REF_P (type)
+ || FUNC_OR_METHOD_TYPE_P (type)))
{
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (TYPE_REF_P (type))
bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
}
if ((type_quals & TYPE_QUAL_RESTRICT)
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM
&& TREE_CODE (type) != TYPENAME_TYPE
- && !POINTER_TYPE_P (type))
+ && !INDIRECT_TYPE_P (type))
{
bad_quals |= TYPE_QUAL_RESTRICT;
type_quals &= ~TYPE_QUAL_RESTRICT;
/* Retrieve (or create) the appropriately qualified variant. */
result = build_qualified_type (type, type_quals);
- /* Preserve exception specs and ref-qualifier since build_qualified_type
- doesn't know about them. */
- if (TREE_CODE (result) == FUNCTION_TYPE
- || TREE_CODE (result) == METHOD_TYPE)
- {
- result = build_exception_variant (result, TYPE_RAISES_EXCEPTIONS (type));
- result = build_ref_qualified_type (result, type_memfn_rqual (type));
- }
-
return result;
}
return cp_build_type_attribute_variant (result, new_attribs);
}
-/* Builds a qualified variant of T that is not a typedef variant.
+/* Builds a qualified variant of T that is either not a typedef variant
+ (the default behavior) or not a typedef variant of a user-facing type
+ (if FLAGS contains STF_USER_FACING).
+
E.g. consider the following declarations:
typedef const int ConstInt;
typedef ConstInt* PtrConstInt;
stripped. */
tree
-strip_typedefs (tree t, bool *remove_attributes)
+strip_typedefs (tree t, bool *remove_attributes, unsigned int flags)
{
tree result = NULL, type = NULL, t0 = NULL;
if (TREE_CODE (t) == TREE_LIST)
{
bool changed = false;
- vec<tree,va_gc> *vec = make_tree_vector ();
+ releasing_vec vec;
tree r = t;
for (; t; t = TREE_CHAIN (t))
{
gcc_assert (!TREE_PURPOSE (t));
- tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes);
+ tree elt = strip_typedefs (TREE_VALUE (t), remove_attributes, flags);
if (elt != TREE_VALUE (t))
changed = true;
vec_safe_push (vec, elt);
}
if (changed)
r = build_tree_list_vec (vec);
- release_tree_vector (vec);
return r;
}
if (t == TYPE_CANONICAL (t))
return t;
- if (dependent_alias_template_spec_p (t))
+ if (!(flags & STF_STRIP_DEPENDENT)
+ && dependent_alias_template_spec_p (t, nt_opaque))
/* DR 1558: However, if the template-id is dependent, subsequent
template argument substitution still applies to the template-id. */
return t;
switch (TREE_CODE (t))
{
case POINTER_TYPE:
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
result = build_pointer_type (type);
break;
case REFERENCE_TYPE:
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
result = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t));
break;
case OFFSET_TYPE:
- t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes);
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ t0 = strip_typedefs (TYPE_OFFSET_BASETYPE (t), remove_attributes, flags);
+ type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
result = build_offset_type (t0, type);
break;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
{
- t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t), remove_attributes);
+ t0 = strip_typedefs (TYPE_PTRMEMFUNC_FN_TYPE (t),
+ remove_attributes, flags);
result = build_ptrmemfunc_type (t0);
}
break;
case ARRAY_TYPE:
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
- t0 = strip_typedefs (TYPE_DOMAIN (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
+ t0 = strip_typedefs (TYPE_DOMAIN (t), remove_attributes, flags);
result = build_cplus_array_type (type, t0);
break;
case FUNCTION_TYPE:
&& (TYPE_ATTRIBUTES (t) || TYPE_USER_ALIGN (t)))
is_variant = true;
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
tree canon_spec = (flag_noexcept_type
? canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (t))
: NULL_TREE);
if (arg_node == void_list_node)
break;
arg_type = strip_typedefs (TREE_VALUE (arg_node),
- remove_attributes);
+ remove_attributes, flags);
gcc_assert (arg_type);
if (arg_type == TREE_VALUE (arg_node) && !changed)
continue;
result =
build_method_type_directly (class_type, type,
TREE_CHAIN (arg_types));
- result
- = build_ref_qualified_type (result, type_memfn_rqual (t));
}
else
{
- result = build_function_type (type,
- arg_types);
- result = apply_memfn_quals (result,
- type_memfn_quals (t),
- type_memfn_rqual (t));
+ result = build_function_type (type, arg_types);
+ result = apply_memfn_quals (result, type_memfn_quals (t));
}
- if (canon_spec)
- result = build_exception_variant (result, canon_spec);
- if (TYPE_HAS_LATE_RETURN_TYPE (t))
- TYPE_HAS_LATE_RETURN_TYPE (result) = 1;
+ result = build_cp_fntype_variant (result,
+ type_memfn_rqual (t), canon_spec,
+ TYPE_HAS_LATE_RETURN_TYPE (t));
}
break;
case TYPENAME_TYPE:
tree arg = TREE_VEC_ELT (args, i);
tree strip_arg;
if (TYPE_P (arg))
- strip_arg = strip_typedefs (arg, remove_attributes);
+ strip_arg = strip_typedefs (arg, remove_attributes, flags);
else
- strip_arg = strip_typedefs_expr (arg, remove_attributes);
+ strip_arg = strip_typedefs_expr (arg, remove_attributes,
+ flags);
TREE_VEC_ELT (new_args, i) = strip_arg;
if (strip_arg != arg)
changed = true;
else
ggc_free (new_args);
}
- tree ctx = strip_typedefs (TYPE_CONTEXT (t), remove_attributes);
+ tree ctx = strip_typedefs (TYPE_CONTEXT (t), remove_attributes, flags);
if (!changed && ctx == TYPE_CONTEXT (t) && !typedef_variant_p (t))
return t;
tree name = fullname;
break;
case DECLTYPE_TYPE:
result = strip_typedefs_expr (DECLTYPE_TYPE_EXPR (t),
- remove_attributes);
+ remove_attributes, flags);
if (result == DECLTYPE_TYPE_EXPR (t))
result = NULL_TREE;
else
tf_none));
break;
case UNDERLYING_TYPE:
- type = strip_typedefs (UNDERLYING_TYPE_TYPE (t), remove_attributes);
+ type = strip_typedefs (UNDERLYING_TYPE_TYPE (t),
+ remove_attributes, flags);
result = finish_underlying_type (type);
break;
default:
{
if (typedef_variant_p (t))
{
- /* Explicitly get the underlying type, as TYPE_MAIN_VARIANT doesn't
- strip typedefs with attributes. */
- result = TYPE_MAIN_VARIANT (DECL_ORIGINAL_TYPE (TYPE_NAME (t)));
- result = strip_typedefs (result);
+ if ((flags & STF_USER_VISIBLE)
+ && !user_facing_original_type_p (t))
+ return t;
+ /* If T is a non-template alias or typedef, we can assume that
+ instantiating its definition will hit any substitution failure,
+ so we don't need to retain it here as well. */
+ if (!alias_template_specialization_p (t, nt_opaque))
+ flags |= STF_STRIP_DEPENDENT;
+ result = strip_typedefs (DECL_ORIGINAL_TYPE (TYPE_NAME (t)),
+ remove_attributes, flags);
}
else
result = TYPE_MAIN_VARIANT (t);
}
- gcc_assert (!typedef_variant_p (result));
+ /*gcc_assert (!typedef_variant_p (result)
+ || dependent_alias_template_spec_p (result, nt_opaque)
+ || ((flags & STF_USER_VISIBLE)
+ && !user_facing_original_type_p (result)));*/
if (COMPLETE_TYPE_P (result) && !COMPLETE_TYPE_P (t))
/* If RESULT is complete and T isn't, it's likely the case that T
sizeof(TT) is replaced by sizeof(T). */
tree
-strip_typedefs_expr (tree t, bool *remove_attributes)
+strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
{
unsigned i,n;
tree r, type, *ops;
if (t == NULL_TREE || t == error_mark_node)
return t;
+ STRIP_ANY_LOCATION_WRAPPER (t);
+
if (DECL_P (t) || CONSTANT_CLASS_P (t))
return t;
/* Some expressions have type operands, so let's handle types here rather
than check TYPE_P in multiple places below. */
if (TYPE_P (t))
- return strip_typedefs (t, remove_attributes);
+ return strip_typedefs (t, remove_attributes, flags);
code = TREE_CODE (t);
switch (code)
case TRAIT_EXPR:
{
- tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t), remove_attributes);
- tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t), remove_attributes);
+ tree type1 = strip_typedefs (TRAIT_EXPR_TYPE1 (t),
+ remove_attributes, flags);
+ tree type2 = strip_typedefs (TRAIT_EXPR_TYPE2 (t),
+ remove_attributes, flags);
if (type1 == TRAIT_EXPR_TYPE1 (t)
&& type2 == TRAIT_EXPR_TYPE2 (t))
return t;
case TREE_LIST:
{
- vec<tree, va_gc> *vec = make_tree_vector ();
+ releasing_vec vec;
bool changed = false;
tree it;
for (it = t; it; it = TREE_CHAIN (it))
{
- tree val = strip_typedefs_expr (TREE_VALUE (t), remove_attributes);
+ tree val = strip_typedefs_expr (TREE_VALUE (it),
+ remove_attributes, flags);
vec_safe_push (vec, val);
- if (val != TREE_VALUE (t))
+ if (val != TREE_VALUE (it))
changed = true;
gcc_assert (TREE_PURPOSE (it) == NULL_TREE);
}
}
else
r = t;
- release_tree_vector (vec);
return r;
}
case TREE_VEC:
{
bool changed = false;
- vec<tree, va_gc> *vec = make_tree_vector ();
+ releasing_vec vec;
n = TREE_VEC_LENGTH (t);
vec_safe_reserve (vec, n);
for (i = 0; i < n; ++i)
{
tree op = strip_typedefs_expr (TREE_VEC_ELT (t, i),
- remove_attributes);
+ remove_attributes, flags);
vec->quick_push (op);
if (op != TREE_VEC_ELT (t, i))
changed = true;
}
else
r = t;
- release_tree_vector (vec);
return r;
}
vec<constructor_elt, va_gc> *vec
= vec_safe_copy (CONSTRUCTOR_ELTS (t));
n = CONSTRUCTOR_NELTS (t);
- type = strip_typedefs (TREE_TYPE (t), remove_attributes);
+ type = strip_typedefs (TREE_TYPE (t), remove_attributes, flags);
for (i = 0; i < n; ++i)
{
constructor_elt *e = &(*vec)[i];
- tree op = strip_typedefs_expr (e->value, remove_attributes);
+ tree op = strip_typedefs_expr (e->value, remove_attributes, flags);
if (op != e->value)
{
changed = true;
e->value = op;
}
gcc_checking_assert
- (e->index == strip_typedefs_expr (e->index, remove_attributes));
+ (e->index == strip_typedefs_expr (e->index, remove_attributes,
+ flags));
}
if (!changed && type == TREE_TYPE (t))
}
case LAMBDA_EXPR:
- error ("lambda-expression in a constant expression");
+ return t;
+
+ case STATEMENT_LIST:
+ error ("statement-expression in a constant expression");
return error_mark_node;
default:
gcc_assert (EXPR_P (t));
- n = TREE_OPERAND_LENGTH (t);
+ n = cp_tree_operand_length (t);
ops = XALLOCAVEC (tree, n);
type = TREE_TYPE (t);
case REINTERPRET_CAST_EXPR:
case CAST_EXPR:
case NEW_EXPR:
- type = strip_typedefs (type, remove_attributes);
+ type = strip_typedefs (type, remove_attributes, flags);
/* fallthrough */
default:
for (i = 0; i < n; ++i)
- ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i), remove_attributes);
+ ops[i] = strip_typedefs_expr (TREE_OPERAND (t, i),
+ remove_attributes, flags);
break;
}
return t;
}
-/* Like check_qualified_type, but also check ref-qualifier and exception
- specification. */
+/* Like check_qualified_type, but also check ref-qualifier, exception
+ specification, and whether the return type was specified after the
+ parameters. */
static bool
cp_check_qualified_type (const_tree cand, const_tree base, int type_quals,
- cp_ref_qualifier rqual, tree raises)
+ cp_ref_qualifier rqual, tree raises, bool late)
{
return (TYPE_QUALS (cand) == type_quals
&& check_base_type (cand, base)
&& comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (cand),
ce_exact)
+ && TYPE_HAS_LATE_RETURN_TYPE (cand) == late
&& type_memfn_rqual (cand) == rqual);
}
tree
build_ref_qualified_type (tree type, cp_ref_qualifier rqual)
{
- tree t;
-
- if (rqual == type_memfn_rqual (type))
- return type;
-
- int type_quals = TYPE_QUALS (type);
tree raises = TYPE_RAISES_EXCEPTIONS (type);
- for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- if (cp_check_qualified_type (t, type, type_quals, rqual, raises))
- return t;
-
- t = build_variant_type_copy (type);
- switch (rqual)
- {
- case REF_QUAL_RVALUE:
- FUNCTION_RVALUE_QUALIFIED (t) = 1;
- FUNCTION_REF_QUALIFIED (t) = 1;
- break;
- case REF_QUAL_LVALUE:
- FUNCTION_RVALUE_QUALIFIED (t) = 0;
- FUNCTION_REF_QUALIFIED (t) = 1;
- break;
- default:
- FUNCTION_REF_QUALIFIED (t) = 0;
- break;
- }
-
- if (TYPE_STRUCTURAL_EQUALITY_P (type))
- /* Propagate structural equality. */
- SET_TYPE_STRUCTURAL_EQUALITY (t);
- else if (TYPE_CANONICAL (type) != type)
- /* Build the underlying canonical type, since it is different
- from TYPE. */
- TYPE_CANONICAL (t) = build_ref_qualified_type (TYPE_CANONICAL (type),
- rqual);
- else
- /* T is its own canonical type. */
- TYPE_CANONICAL (t) = t;
-
- return t;
+ bool late = TYPE_HAS_LATE_RETURN_TYPE (type);
+ return build_cp_fntype_variant (type, rqual, raises, late);
}
-/* Cache of free ovl nodes. Uses OVL_FUNCTION for chaining. */
-static GTY((deletable)) tree ovl_cache;
-
/* Make a raw overload node containing FN. */
tree
ovl_make (tree fn, tree next)
{
- tree result = ovl_cache;
-
- if (result)
- {
- ovl_cache = OVL_FUNCTION (result);
- /* Zap the flags. */
- memset (result, 0, sizeof (tree_base));
- TREE_SET_CODE (result, OVERLOAD);
- }
- else
- result = make_node (OVERLOAD);
+ tree result = make_node (OVERLOAD);
if (TREE_CODE (fn) == OVERLOAD)
OVL_NESTED_P (result) = true;
TREE_TYPE (result) = (next || TREE_CODE (fn) == TEMPLATE_DECL
? unknown_type_node : TREE_TYPE (fn));
+ if (next && TREE_CODE (next) == OVERLOAD && OVL_DEDUP_P (next))
+ OVL_DEDUP_P (result) = true;
OVL_FUNCTION (result) = fn;
OVL_CHAIN (result) = next;
return result;
}
-static tree
-ovl_copy (tree ovl)
-{
- tree result = ovl_cache;
-
- if (result)
- {
- ovl_cache = OVL_FUNCTION (result);
- /* Zap the flags. */
- memset (result, 0, sizeof (tree_base));
- TREE_SET_CODE (result, OVERLOAD);
- }
- else
- result = make_node (OVERLOAD);
-
- gcc_checking_assert (!OVL_NESTED_P (ovl) && OVL_USED_P (ovl));
- TREE_TYPE (result) = TREE_TYPE (ovl);
- OVL_FUNCTION (result) = OVL_FUNCTION (ovl);
- OVL_CHAIN (result) = OVL_CHAIN (ovl);
- OVL_HIDDEN_P (result) = OVL_HIDDEN_P (ovl);
- OVL_USING_P (result) = OVL_USING_P (ovl);
- OVL_LOOKUP_P (result) = OVL_LOOKUP_P (ovl);
-
- return result;
-}
-
/* Add FN to the (potentially NULL) overload set OVL. USING_P is
true, if FN is via a using declaration. We also pay attention to
- DECL_HIDDEN. Overloads are ordered as hidden, using, regular. */
+ DECL_HIDDEN. We keep the hidden decls first, but remaining ones
+ are unordered. */
tree
ovl_insert (tree fn, tree maybe_ovl, bool using_p)
{
- bool copying = false; /* Checking use only. */
- bool hidden_p = DECL_HIDDEN_P (fn);
- int weight = (hidden_p << 1) | (using_p << 0);
-
- tree result = NULL_TREE;
+ tree result = maybe_ovl;
tree insert_after = NULL_TREE;
- /* Find insertion point. */
- while (maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
- && (weight < ((OVL_HIDDEN_P (maybe_ovl) << 1)
- | (OVL_USING_P (maybe_ovl) << 0))))
+ /* Skip hidden. */
+ for (; maybe_ovl && TREE_CODE (maybe_ovl) == OVERLOAD
+ && OVL_HIDDEN_P (maybe_ovl);
+ maybe_ovl = OVL_CHAIN (maybe_ovl))
{
- gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl)
- && (!copying || OVL_USED_P (maybe_ovl)));
- if (OVL_USED_P (maybe_ovl))
- {
- copying = true;
- maybe_ovl = ovl_copy (maybe_ovl);
- if (insert_after)
- OVL_CHAIN (insert_after) = maybe_ovl;
- }
- if (!result)
- result = maybe_ovl;
+ gcc_checking_assert (!OVL_LOOKUP_P (maybe_ovl));
insert_after = maybe_ovl;
- maybe_ovl = OVL_CHAIN (maybe_ovl);
}
- tree trail = fn;
+ bool hidden_p = DECL_HIDDEN_P (fn);
if (maybe_ovl || using_p || hidden_p || TREE_CODE (fn) == TEMPLATE_DECL)
{
- trail = ovl_make (fn, maybe_ovl);
+ maybe_ovl = ovl_make (fn, maybe_ovl);
if (hidden_p)
- OVL_HIDDEN_P (trail) = true;
+ OVL_HIDDEN_P (maybe_ovl) = true;
if (using_p)
- OVL_USING_P (trail) = true;
+ OVL_DEDUP_P (maybe_ovl) = OVL_USING_P (maybe_ovl) = true;
}
+ else
+ maybe_ovl = fn;
if (insert_after)
{
- OVL_CHAIN (insert_after) = trail;
+ OVL_CHAIN (insert_after) = maybe_ovl;
TREE_TYPE (insert_after) = unknown_type_node;
}
else
- result = trail;
+ result = maybe_ovl;
return result;
}
tree
ovl_iterator::reveal_node (tree overload, tree node)
{
- /* We cannot have returned NODE as part of a lookup overload, so it
- cannot be USED. */
- gcc_checking_assert (!OVL_USED_P (node));
+ /* We cannot have returned NODE as part of a lookup overload, so we
+ don't have to worry about preserving that. */
OVL_HIDDEN_P (node) = false;
if (tree chain = OVL_CHAIN (node))
- if (TREE_CODE (chain) == OVERLOAD
- && (OVL_USING_P (chain) || OVL_HIDDEN_P (chain)))
+ if (TREE_CODE (chain) == OVERLOAD)
{
- /* The node needs moving, and the simplest way is to remove it
- and reinsert. */
- overload = remove_node (overload, node);
- overload = ovl_insert (OVL_FUNCTION (node), overload);
+ if (OVL_HIDDEN_P (chain))
+ {
+ /* The node needs moving, and the simplest way is to remove it
+ and reinsert. */
+ overload = remove_node (overload, node);
+ overload = ovl_insert (OVL_FUNCTION (node), overload);
+ }
+ else if (OVL_DEDUP_P (chain))
+ OVL_DEDUP_P (node) = true;
}
return overload;
}
-/* NODE is on the overloads of OVL. Remove it. If a predecessor is
- OVL_USED_P we must copy OVL nodes, because those are immutable.
+/* NODE is on the overloads of OVL. Remove it.
The removed node is unaltered and may continue to be iterated
from (i.e. it is safe to remove a node from an overload one is
currently iterating over). */
tree
ovl_iterator::remove_node (tree overload, tree node)
{
- bool copying = false; /* Checking use only. */
-
tree *slot = &overload;
while (*slot != node)
{
tree probe = *slot;
- gcc_checking_assert (!OVL_LOOKUP_P (probe)
- && (!copying || OVL_USED_P (probe)));
- if (OVL_USED_P (probe))
- {
- copying = true;
- probe = ovl_copy (probe);
- *slot = probe;
- }
+ gcc_checking_assert (!OVL_LOOKUP_P (probe));
slot = &OVL_CHAIN (probe);
}
tree
lookup_add (tree fns, tree lookup)
{
+ if (fns == error_mark_node || lookup == error_mark_node)
+ return error_mark_node;
+
if (lookup || TREE_CODE (fns) == TEMPLATE_DECL)
{
lookup = ovl_make (fns, lookup);
for (; fns != probe; fns = OVL_CHAIN (fns))
{
lookup = lookup_add (OVL_FUNCTION (fns), lookup);
- /* Propagate OVL_USING, but OVL_HIDDEN doesn't matter. */
+ /* Propagate OVL_USING, but OVL_HIDDEN &
+ OVL_DEDUP_P don't matter. */
if (OVL_USING_P (fns))
OVL_USING_P (lookup) = true;
}
return lookup;
}
-/* Regular overload OVL is part of a kept lookup. Mark the nodes on
- it as immutable. */
-
-static void
-ovl_used (tree ovl)
-{
- for (;
- ovl && TREE_CODE (ovl) == OVERLOAD
- && !OVL_USED_P (ovl);
- ovl = OVL_CHAIN (ovl))
- {
- gcc_checking_assert (!OVL_LOOKUP_P (ovl));
- OVL_USED_P (ovl) = true;
- }
-}
-
-/* If KEEP is true, preserve the contents of a lookup so that it is
- available for a later instantiation. Otherwise release the LOOKUP
- nodes for reuse. */
-
-void
-lookup_keep (tree lookup, bool keep)
-{
- for (;
- lookup && TREE_CODE (lookup) == OVERLOAD
- && OVL_LOOKUP_P (lookup) && !OVL_USED_P (lookup);
- lookup = OVL_CHAIN (lookup))
- if (keep)
- {
- OVL_USED_P (lookup) = true;
- ovl_used (OVL_FUNCTION (lookup));
- }
- else
- {
- OVL_FUNCTION (lookup) = ovl_cache;
- ovl_cache = lookup;
- }
-
- if (keep)
- ovl_used (lookup);
-}
-
/* Returns nonzero if X is an expression for a (possibly overloaded)
function. If "f" is a function or function template, "f", "c->f",
"c.f", "C::f", and "f<int>" will all be considered possibly
int
is_overloaded_fn (tree x)
{
+ STRIP_ANY_LOCATION_WRAPPER (x);
+
/* A baselink is also considered an overloaded function. */
if (TREE_CODE (x) == OFFSET_REF
|| TREE_CODE (x) == COMPONENT_REF)
|| (TREE_CODE (x) == OVERLOAD && !OVL_SINGLE_P (x)))
return 2;
- return (TREE_CODE (x) == FUNCTION_DECL
- || TREE_CODE (x) == OVERLOAD);
+ return OVL_P (x);
}
/* X is the CALL_EXPR_FN of a CALL_EXPR. If X represents a dependent name
return x;
if (TREE_CODE (x) == TEMPLATE_ID_EXPR)
x = TREE_OPERAND (x, 0);
- if (TREE_CODE (x) == OVERLOAD || TREE_CODE (x) == FUNCTION_DECL)
+ if (OVL_P (x))
return OVL_NAME (x);
return NULL_TREE;
}
return is_overloaded_fn (x) == 2;
}
-/* Get the overload set FROM refers to. */
+/* Get the overload set FROM refers to. Returns NULL if it's not an
+ overload set. */
tree
-get_fns (tree from)
+maybe_get_fns (tree from)
{
+ STRIP_ANY_LOCATION_WRAPPER (from);
+
/* A baselink is also considered an overloaded function. */
if (TREE_CODE (from) == OFFSET_REF
|| TREE_CODE (from) == COMPONENT_REF)
from = BASELINK_FUNCTIONS (from);
if (TREE_CODE (from) == TEMPLATE_ID_EXPR)
from = TREE_OPERAND (from, 0);
- gcc_assert (TREE_CODE (from) == OVERLOAD
- || TREE_CODE (from) == FUNCTION_DECL);
- return from;
+
+ if (OVL_P (from))
+ return from;
+
+ return NULL;
+}
+
+/* FROM refers to an overload set. Return that set (or die). */
+
+tree
+get_fns (tree from)
+{
+ tree res = maybe_get_fns (from);
+
+ gcc_assert (res);
+ return res;
}
/* Return the first function of the overload set FROM refers to. */
if (raises == NULL_TREE)
return raises;
else if (DEFERRED_NOEXCEPT_SPEC_P (raises)
+ || UNPARSED_NOEXCEPT_SPEC_P (raises)
|| uses_template_parms (raises)
|| uses_template_parms (TREE_PURPOSE (raises)))
/* Keep a dependent or deferred exception specification. */
return NULL_TREE;
}
-/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
- listed in RAISES. */
-
tree
-build_exception_variant (tree type, tree raises)
+build_cp_fntype_variant (tree type, cp_ref_qualifier rqual,
+ tree raises, bool late)
{
- tree v;
- int type_quals;
+ cp_cv_quals type_quals = TYPE_QUALS (type);
- if (comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (type), ce_exact))
+ if (cp_check_qualified_type (type, type, type_quals, rqual, raises, late))
return type;
- type_quals = TYPE_QUALS (type);
- cp_ref_qualifier rqual = type_memfn_rqual (type);
- for (v = TYPE_MAIN_VARIANT (type); v; v = TYPE_NEXT_VARIANT (v))
- if (cp_check_qualified_type (v, type, type_quals, rqual, raises))
+ tree v = TYPE_MAIN_VARIANT (type);
+ for (; v; v = TYPE_NEXT_VARIANT (v))
+ if (cp_check_qualified_type (v, type, type_quals, rqual, raises, late))
return v;
/* Need to build a new variant. */
v = build_variant_type_copy (type);
TYPE_RAISES_EXCEPTIONS (v) = raises;
-
- if (!flag_noexcept_type)
- /* The exception-specification is not part of the canonical type. */
- return v;
+ TYPE_HAS_LATE_RETURN_TYPE (v) = late;
+ switch (rqual)
+ {
+ case REF_QUAL_RVALUE:
+ FUNCTION_RVALUE_QUALIFIED (v) = 1;
+ FUNCTION_REF_QUALIFIED (v) = 1;
+ break;
+ case REF_QUAL_LVALUE:
+ FUNCTION_RVALUE_QUALIFIED (v) = 0;
+ FUNCTION_REF_QUALIFIED (v) = 1;
+ break;
+ default:
+ FUNCTION_REF_QUALIFIED (v) = 0;
+ break;
+ }
/* Canonicalize the exception specification. */
- tree cr = canonical_eh_spec (raises);
+ tree cr = flag_noexcept_type ? canonical_eh_spec (raises) : NULL_TREE;
if (TYPE_STRUCTURAL_EQUALITY_P (type))
/* Propagate structural equality. */
SET_TYPE_STRUCTURAL_EQUALITY (v);
- else if (TYPE_CANONICAL (type) != type || cr != raises)
+ else if (TYPE_CANONICAL (type) != type || cr != raises || late)
/* Build the underlying canonical type, since it is different
from TYPE. */
- TYPE_CANONICAL (v) = build_exception_variant (TYPE_CANONICAL (type), cr);
+ TYPE_CANONICAL (v) = build_cp_fntype_variant (TYPE_CANONICAL (type),
+ rqual, cr, false);
else
/* T is its own canonical type. */
TYPE_CANONICAL (v) = v;
return v;
}
+/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
+ listed in RAISES. */
+
+tree
+build_exception_variant (tree type, tree raises)
+{
+ cp_ref_qualifier rqual = type_memfn_rqual (type);
+ bool late = TYPE_HAS_LATE_RETURN_TYPE (type);
+ return build_cp_fntype_variant (type, rqual, raises, late);
+}
+
/* Given a TEMPLATE_TEMPLATE_PARM node T, create a new
BOUND_TEMPLATE_TEMPLATE_PARM bound with NEWARGS as its template
arguments. */
{
tree r;
- /* There's no point in checking linkage on template functions; we
+ /* Lambda types that don't have mangling scope have no linkage. We
+ check CLASSTYPE_LAMBDA_EXPR for error_mark_node because
+ when we get here from pushtag none of the lambda information is
+ set up yet, so we want to assume that the lambda has linkage and
+ fix it up later if not. We need to check this even in templates so
+ that we properly handle a lambda-expression in the signature. */
+ if (LAMBDA_TYPE_P (t)
+ && CLASSTYPE_LAMBDA_EXPR (t) != error_mark_node
+ && LAMBDA_TYPE_EXTRA_SCOPE (t) == NULL_TREE)
+ return t;
+
+ /* Otherwise there's no point in checking linkage on template functions; we
can't know their complete types. */
if (processing_template_decl)
return NULL_TREE;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
goto ptrmem;
- /* Lambda types that don't have mangling scope have no linkage. We
- check CLASSTYPE_LAMBDA_EXPR for error_mark_node because
- when we get here from pushtag none of the lambda information is
- set up yet, so we want to assume that the lambda has linkage and
- fix it up later if not. */
- if (CLASSTYPE_LAMBDA_EXPR (t)
- && CLASSTYPE_LAMBDA_EXPR (t) != error_mark_node
- && LAMBDA_TYPE_EXTRA_SCOPE (t) == NULL_TREE)
- return t;
/* Fall through. */
case UNION_TYPE:
if (!CLASS_TYPE_P (t))
void
cxx_print_statistics (void)
{
- print_class_statistics ();
print_template_statistics ();
if (GATHER_STATISTICS)
fprintf (stderr, "maximum template instantiation depth reached: %d\n",
return sz;
}
+struct bot_data
+{
+ splay_tree target_remap;
+ bool clear_location;
+};
+
/* Called from break_out_target_exprs via mapcar. */
static tree
-bot_manip (tree* tp, int* walk_subtrees, void* data)
+bot_manip (tree* tp, int* walk_subtrees, void* data_)
{
- splay_tree target_remap = ((splay_tree) data);
+ bot_data &data = *(bot_data*)data_;
+ splay_tree target_remap = data.target_remap;
tree t = *tp;
if (!TYPE_P (t) && TREE_CONSTANT (t) && !TREE_SIDE_EFFECTS (t))
{
u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1),
tf_warning_or_error);
+ if (u == error_mark_node)
+ return u;
if (AGGR_INIT_ZERO_FIRST (TREE_OPERAND (t, 1)))
AGGR_INIT_ZERO_FIRST (TREE_OPERAND (u, 1)) = true;
}
(splay_tree_key) TREE_OPERAND (t, 0),
(splay_tree_value) TREE_OPERAND (u, 0));
- TREE_OPERAND (u, 1) = break_out_target_exprs (TREE_OPERAND (u, 1));
+ TREE_OPERAND (u, 1) = break_out_target_exprs (TREE_OPERAND (u, 1),
+ data.clear_location);
+ if (TREE_OPERAND (u, 1) == error_mark_node)
+ return error_mark_node;
/* Replace the old expression with the new version. */
*tp = u;
/* Make a copy of this node. */
t = copy_tree_r (tp, walk_subtrees, NULL);
- if (TREE_CODE (*tp) == CALL_EXPR)
- {
+ if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR)
+ if (!processing_template_decl)
set_flags_from_callee (*tp);
-
- /* builtin_LINE and builtin_FILE get the location where the default
- argument is expanded, not where the call was written. */
- tree callee = get_callee_fndecl (*tp);
- if (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
- switch (DECL_FUNCTION_CODE (callee))
- {
- case BUILT_IN_FILE:
- case BUILT_IN_LINE:
- SET_EXPR_LOCATION (*tp, input_location);
- default:
- break;
- }
- }
+ if (data.clear_location && EXPR_HAS_LOCATION (*tp))
+ SET_EXPR_LOCATION (*tp, input_location);
return t;
}
variables. */
static tree
-bot_replace (tree* t, int* /*walk_subtrees*/, void* data)
+bot_replace (tree* t, int* /*walk_subtrees*/, void* data_)
{
- splay_tree target_remap = ((splay_tree) data);
+ bot_data &data = *(bot_data*)data_;
+ splay_tree target_remap = data.target_remap;
if (VAR_P (*t))
{
/* When we parse a default argument expression, we may create
temporary variables via TARGET_EXPRs. When we actually use the
default-argument expression, we make a copy of the expression
- and replace the temporaries with appropriate local versions. */
+ and replace the temporaries with appropriate local versions.
+
+ If CLEAR_LOCATION is true, override any EXPR_LOCATION with
+ input_location. */
tree
-break_out_target_exprs (tree t)
+break_out_target_exprs (tree t, bool clear_location /* = false */)
{
static int target_remap_count;
static splay_tree target_remap;
target_remap = splay_tree_new (splay_tree_compare_pointers,
/*splay_tree_delete_key_fn=*/NULL,
/*splay_tree_delete_value_fn=*/NULL);
- cp_walk_tree (&t, bot_manip, target_remap, NULL);
- cp_walk_tree (&t, bot_replace, target_remap, NULL);
+ bot_data data = { target_remap, clear_location };
+ if (cp_walk_tree (&t, bot_manip, &data, NULL) == error_mark_node)
+ t = error_mark_node;
+ cp_walk_tree (&t, bot_replace, &data, NULL);
if (!--target_remap_count)
{
struct replace_placeholders_t
{
tree obj; /* The object to be substituted for a PLACEHOLDER_EXPR. */
+ tree exp; /* The outermost exp. */
bool seen; /* Whether we've encountered a PLACEHOLDER_EXPR. */
hash_set<tree> *pset; /* To avoid walking same trees multiple times. */
};
replace_placeholders_t *d = static_cast<replace_placeholders_t*>(data_);
tree obj = d->obj;
- if (TREE_CONSTANT (*t))
+ if (TYPE_P (*t) || TREE_CONSTANT (*t))
{
*walk_subtrees = false;
return NULL_TREE;
for (; !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (*t),
TREE_TYPE (x));
x = TREE_OPERAND (x, 0))
- gcc_assert (TREE_CODE (x) == COMPONENT_REF);
- *t = x;
+ gcc_assert (handled_component_p (x));
+ *t = unshare_expr (x);
*walk_subtrees = false;
d->seen = true;
}
{
constructor_elt *ce;
vec<constructor_elt,va_gc> *v = CONSTRUCTOR_ELTS (*t);
+ /* Don't walk into CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctors
+ other than the d->exp one, those have PLACEHOLDER_EXPRs
+ related to another object. */
+ if ((CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t)
+ && *t != d->exp)
+ || d->pset->add (*t))
+ {
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
for (unsigned i = 0; vec_safe_iterate (v, i, &ce); ++i)
{
tree *valp = &ce->value;
tree type = TREE_TYPE (*valp);
tree subob = obj;
+ /* Elements with RANGE_EXPR index shouldn't have any
+ placeholders in them. */
+ if (ce->index && TREE_CODE (ce->index) == RANGE_EXPR)
+ continue;
+
if (TREE_CODE (*valp) == CONSTRUCTOR
&& AGGREGATE_TYPE_P (type))
{
valp = &TARGET_EXPR_INITIAL (*valp);
}
d->obj = subob;
- cp_walk_tree (valp, replace_placeholders_r, data_, d->pset);
+ cp_walk_tree (valp, replace_placeholders_r, data_, NULL);
d->obj = obj;
}
*walk_subtrees = false;
}
default:
+ if (d->pset->add (*t))
+ *walk_subtrees = false;
break;
}
return exp;
tree *tp = &exp;
- hash_set<tree> pset;
- replace_placeholders_t data = { obj, false, &pset };
if (TREE_CODE (exp) == TARGET_EXPR)
tp = &TARGET_EXPR_INITIAL (exp);
- cp_walk_tree (tp, replace_placeholders_r, &data, &pset);
+ hash_set<tree> pset;
+ replace_placeholders_t data = { obj, *tp, false, &pset };
+ cp_walk_tree (tp, replace_placeholders_r, &data, NULL);
if (seen_p)
*seen_p = data.seen;
return exp;
}
+/* Callback function for find_placeholders. */
+
+static tree
+find_placeholders_r (tree *t, int *walk_subtrees, void *)
+{
+ if (TYPE_P (*t) || TREE_CONSTANT (*t))
+ {
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+
+ switch (TREE_CODE (*t))
+ {
+ case PLACEHOLDER_EXPR:
+ return *t;
+
+ case CONSTRUCTOR:
+ if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t))
+ *walk_subtrees = false;
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+/* Return true if EXP contains a PLACEHOLDER_EXPR. Don't walk into
+ ctors with CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set. */
+
+bool
+find_placeholders (tree exp)
+{
+ /* This is only relevant for C++14. */
+ if (cxx_dialect < cxx14)
+ return false;
+
+ return cp_walk_tree_without_duplicates (&exp, find_placeholders_r, NULL);
+}
+
/* Similar to `build_nt', but for template definitions of dependent
expressions */
length = TREE_CODE_LENGTH (code);
for (i = 0; i < length; i++)
- {
- tree x = va_arg (p, tree);
- TREE_OPERAND (t, i) = x;
- if (x && TREE_CODE (x) == OVERLOAD)
- lookup_keep (x, true);
- }
+ TREE_OPERAND (t, i) = va_arg (p, tree);
va_end (p);
return t;
{
tree x = va_arg (p, tree);
TREE_OPERAND (t, i) = x;
- if (x)
- {
- if (!TYPE_P (x) && TREE_SIDE_EFFECTS (x))
- TREE_SIDE_EFFECTS (t) = 1;
- if (TREE_CODE (x) == OVERLOAD)
- lookup_keep (x, true);
- }
+ if (x && !TYPE_P (x) && TREE_SIDE_EFFECTS (x))
+ TREE_SIDE_EFFECTS (t) = 1;
}
va_end (p);
+
return t;
}
TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (non_dep);
for (i = 0; i < length; i++)
- {
- tree x = va_arg (p, tree);
- TREE_OPERAND (t, i) = x;
- if (x && TREE_CODE (x) == OVERLOAD)
- lookup_keep (x, true);
- }
+ TREE_OPERAND (t, i) = va_arg (p, tree);
if (code == COMPOUND_EXPR && TREE_CODE (non_dep) != COMPOUND_EXPR)
/* This should not be considered a COMPOUND_EXPR, because it
CALL_EXPR_FN (ret) = fn;
CALL_EXPR_STATIC_CHAIN (ret) = NULL_TREE;
FOR_EACH_VEC_SAFE_ELT (args, ix, t)
- {
- CALL_EXPR_ARG (ret, ix) = t;
- if (TREE_CODE (t) == OVERLOAD)
- lookup_keep (t, true);
- }
+ CALL_EXPR_ARG (ret, ix) = t;
+
return ret;
}
va_list p;
int nargs, expected_nargs;
tree fn, call;
- vec<tree, va_gc> *args;
non_dep = extract_call_expr (non_dep);
expected_nargs += 1;
gcc_assert (nargs == expected_nargs);
- args = make_tree_vector ();
+ releasing_vec args;
va_start (p, overload);
if (TREE_CODE (TREE_TYPE (overload)) == FUNCTION_TYPE)
va_end (p);
call = build_min_non_dep_call_vec (non_dep, fn, args);
- release_tree_vector (args);
tree call_expr = extract_call_expr (call);
KOENIG_LOOKUP_P (call_expr) = KOENIG_LOOKUP_P (non_dep);
if (code1 != code2)
return false;
+ if (CONSTANT_CLASS_P (t1)
+ && !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+
switch (code1)
{
case VOID_CST:
case TEMPLATE_DECL:
case IDENTIFIER_NODE:
case SSA_NAME:
+ case USING_DECL:
+ case DEFERRED_PARSE:
return false;
case BASELINK:
DEFERRED_NOEXCEPT_ARGS (t2)));
break;
+ case LAMBDA_EXPR:
+ /* Two lambda-expressions are never considered equivalent. */
+ return false;
+
default:
break;
}
|| !deleted_copy_types->contains (t))
return;
- warning_at (loc, OPT_Wabi, "the calling convention for %qT changes in "
- "-fabi-version=12 (GCC 8)", t);
- static bool explained = false;
- if (!explained)
+ if ((flag_abi_version == 12 || warn_abi_version == 12)
+ && classtype_has_non_deleted_move_ctor (t))
{
- inform (loc, " because all of its copy and move constructors "
- "are deleted");
- explained = true;
+ bool w;
+ auto_diagnostic_group d;
+ if (flag_abi_version > 12)
+ w = warning_at (loc, OPT_Wabi, "%<-fabi-version=13%> (GCC 8.2) fixes "
+ "the calling convention for %qT, which was "
+ "accidentally changed in 8.1", t);
+ else
+ w = warning_at (loc, OPT_Wabi, "%<-fabi-version=12%> (GCC 8.1) accident"
+ "ally changes the calling convention for %qT", t);
+ if (w)
+ inform (location_of (t), " declared here");
+ return;
}
+
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wabi, "the calling convention for %qT changes in "
+ "%<-fabi-version=13%> (GCC 8.2)", t))
+ inform (location_of (t), " because all of its copy and move "
+ "constructors are deleted");
}
/* Returns true iff copying an object of type T (including via move
bool saw_copy = false;
bool saw_non_deleted = false;
+ bool saw_non_deleted_move = false;
if (CLASSTYPE_LAZY_MOVE_CTOR (t))
saw_copy = saw_non_deleted = true;
break;
}
}
+ else if (move_fn_p (fn))
+ if (!DECL_DELETED_FN (fn))
+ saw_non_deleted_move = true;
}
gcc_assert (saw_copy);
- if (saw_copy && !saw_non_deleted)
- {
- if (warn_abi && abi_version_crosses (12))
- remember_deleted_copy (t);
- if (abi_version_at_least (12))
- return true;
- }
-
- return false;
+ /* ABI v12 buggily ignored move constructors. */
+ bool v11nontriv = false;
+ bool v12nontriv = !saw_non_deleted;
+ bool v13nontriv = !saw_non_deleted && !saw_non_deleted_move;
+ bool nontriv = (abi_version_at_least (13) ? v13nontriv
+ : flag_abi_version == 12 ? v12nontriv
+ : v11nontriv);
+ bool warn_nontriv = (warn_abi_version >= 13 ? v13nontriv
+ : warn_abi_version == 12 ? v12nontriv
+ : v11nontriv);
+ if (nontriv != warn_nontriv)
+ remember_deleted_copy (t);
+
+ return nontriv;
}
else
return 0;
&& !TYPE_HAS_COMPLEX_MOVE_ASSIGN (t)
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (t));
else
- return !CP_TYPE_VOLATILE_P (t) && scalarish_type_p (t);
+ /* CWG 2094 makes volatile-qualified scalars trivially copyable again. */
+ return scalarish_type_p (t);
}
/* Returns 1 iff type T is a trivial type, as defined in [basic.types] and
return 1;
}
+/* True IFF T is a C++20 structural type (P1907R1) that can be used as a
+ non-type template parameter. If EXPLAIN, explain why not. */
+
+bool
+structural_type_p (tree t, bool explain)
+{
+ t = strip_array_types (t);
+ if (INTEGRAL_OR_ENUMERATION_TYPE_P (t))
+ return true;
+ if (NULLPTR_TYPE_P (t))
+ return true;
+ if (TYPE_PTR_P (t) || TYPE_PTRMEM_P (t))
+ return true;
+ if (TYPE_REF_P (t) && !TYPE_REF_IS_RVALUE (t))
+ return true;
+ if (!CLASS_TYPE_P (t))
+ return false;
+ if (TREE_CODE (t) == UNION_TYPE)
+ {
+ if (explain)
+ inform (location_of (t), "%qT is a union", t);
+ return false;
+ }
+ if (!literal_type_p (t))
+ {
+ if (explain)
+ explain_non_literal_class (t);
+ return false;
+ }
+ if (CLASSTYPE_HAS_MUTABLE (t))
+ {
+ if (explain)
+ inform (location_of (t), "%qT has a mutable member", t);
+ return false;
+ }
+ for (tree m = next_initializable_field (TYPE_FIELDS (t)); m;
+ m = next_initializable_field (DECL_CHAIN (m)))
+ {
+ if (TREE_PRIVATE (m) || TREE_PROTECTED (m))
+ {
+ if (explain)
+ inform (location_of (m), "%qD is not public", m);
+ return false;
+ }
+ if (!structural_type_p (TREE_TYPE (m)))
+ {
+ if (explain)
+ {
+ inform (location_of (m), "%qD has a non-structural type", m);
+ structural_type_p (TREE_TYPE (m), true);
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
/* Handle the C++17 [[nodiscard]] attribute, which is similar to the GNU
warn_unused_result attribute. */
static tree
-handle_nodiscard_attribute (tree *node, tree name, tree /*args*/,
+handle_nodiscard_attribute (tree *node, tree name, tree args,
int /*flags*/, bool *no_add_attrs)
{
+ if (args && TREE_CODE (TREE_VALUE (args)) != STRING_CST)
+ {
+ error ("%qE attribute argument must be a string constant", name);
+ *no_add_attrs = true;
+ }
if (TREE_CODE (*node) == FUNCTION_DECL)
{
- if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node))))
- warning (OPT_Wattributes, "%qE attribute applied to %qD with void "
- "return type", name, *node);
+ if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))
+ && !DECL_CONSTRUCTOR_P (*node))
+ warning_at (DECL_SOURCE_LOCATION (*node),
+ OPT_Wattributes, "%qE attribute applied to %qD with void "
+ "return type", name, *node);
}
else if (OVERLOAD_TYPE_P (*node))
/* OK */;
return NULL_TREE;
}
+/* Handle a C++2a "no_unique_address" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+handle_no_unique_addr_attribute (tree* node,
+ tree name,
+ tree /*args*/,
+ int /*flags*/,
+ bool* no_add_attrs)
+{
+ if (TREE_CODE (*node) != FIELD_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute can only be applied to "
+ "non-static data members", name);
+ *no_add_attrs = true;
+ }
+ else if (DECL_C_BIT_FIELD (*node))
+ {
+ warning (OPT_Wattributes, "%qE attribute cannot be applied to "
+ "a bit-field", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* The C++20 [[likely]] and [[unlikely]] attributes on labels map to the GNU
+ hot/cold attributes. */
+
+static tree
+handle_likeliness_attribute (tree *node, tree name, tree args,
+ int flags, bool *no_add_attrs)
+{
+ *no_add_attrs = true;
+ if (TREE_CODE (*node) == LABEL_DECL
+ || TREE_CODE (*node) == FUNCTION_DECL)
+ {
+ if (args)
+ warning (OPT_Wattributes, "%qE attribute takes no arguments", name);
+ tree bname = (is_attribute_p ("likely", name)
+ ? get_identifier ("hot") : get_identifier ("cold"));
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ warning (OPT_Wattributes, "ISO C++ %qE attribute does not apply to "
+ "functions; treating as %<[[gnu::%E]]%>", name, bname);
+ tree battr = build_tree_list (bname, NULL_TREE);
+ decl_attributes (node, battr, flags);
+ return NULL_TREE;
+ }
+ else
+ return error_mark_node;
+}
+
/* Table of valid C++ attributes. */
const struct attribute_spec cxx_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "init_priority", 1, 1, true, false, false,
- handle_init_priority_attribute, false },
- { "abi_tag", 1, -1, false, false, false,
- handle_abi_tag_attribute, true },
- { NULL, 0, 0, false, false, false, NULL, false }
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "init_priority", 1, 1, true, false, false, false,
+ handle_init_priority_attribute, NULL },
+ { "abi_tag", 1, -1, false, false, false, true,
+ handle_abi_tag_attribute, NULL },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
/* Table of C++ standard attributes. */
const struct attribute_spec std_attribute_table[] =
{
- /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
- affects_type_identity } */
- { "maybe_unused", 0, 0, false, false, false,
- handle_unused_attribute, false },
- { "nodiscard", 0, 0, false, false, false,
- handle_nodiscard_attribute, false },
- { NULL, 0, 0, false, false, false, NULL, false }
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+ affects_type_identity, handler, exclude } */
+ { "maybe_unused", 0, 0, false, false, false, false,
+ handle_unused_attribute, NULL },
+ { "nodiscard", 0, 1, false, false, false, false,
+ handle_nodiscard_attribute, NULL },
+ { "no_unique_address", 0, 0, true, false, false, false,
+ handle_no_unique_addr_attribute, NULL },
+ { "likely", 0, 0, false, false, false, false,
+ handle_likeliness_attribute, attr_cold_hot_exclusions },
+ { "unlikely", 0, 0, false, false, false, false,
+ handle_likeliness_attribute, attr_cold_hot_exclusions },
+ { "noreturn", 0, 0, true, false, false, false,
+ handle_noreturn_attribute, attr_noreturn_exclusions },
+ { NULL, 0, 0, false, false, false, false, NULL, NULL }
};
/* Handle an "init_priority" attribute; arguments as in
if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
{
- error ("requested init_priority is not an integer constant");
+ error ("requested %<init_priority%> is not an integer constant");
cxx_constant_value (initp_expr);
*no_add_attrs = true;
return NULL_TREE;
if (pri > MAX_INIT_PRIORITY || pri <= 0)
{
- error ("requested init_priority is out of range");
+ error ("requested %<init_priority%> %i is out of range [0, %i]",
+ pri, MAX_INIT_PRIORITY);
*no_add_attrs = true;
return NULL_TREE;
}
if (pri <= MAX_RESERVED_INIT_PRIORITY)
{
warning
- (0, "requested init_priority is reserved for internal use");
+ (0, "requested %<init_priority%> %i is reserved for internal use",
+ pri);
}
if (SUPPORTS_INIT_PRIORITY)
tree new_type;
new_type = build_type_attribute_variant (type, attributes);
- if (TREE_CODE (new_type) == FUNCTION_TYPE
- || TREE_CODE (new_type) == METHOD_TYPE)
- {
- new_type = build_exception_variant (new_type,
- TYPE_RAISES_EXCEPTIONS (type));
- new_type = build_ref_qualified_type (new_type,
- type_memfn_rqual (type));
- }
+ if (FUNC_OR_METHOD_TYPE_P (new_type))
+ gcc_checking_assert (cxx_type_hash_eq (type, new_type));
/* Making a new main variant of a class type is broken. */
gcc_assert (!CLASS_TYPE_P (type) || new_type == type);
bool
cxx_type_hash_eq (const_tree typea, const_tree typeb)
{
- gcc_assert (TREE_CODE (typea) == FUNCTION_TYPE
- || TREE_CODE (typea) == METHOD_TYPE);
+ gcc_assert (FUNC_OR_METHOD_TYPE_P (typea));
if (type_memfn_rqual (typea) != type_memfn_rqual (typeb))
return false;
+ if (TYPE_HAS_LATE_RETURN_TYPE (typea) != TYPE_HAS_LATE_RETURN_TYPE (typeb))
+ return false;
return comp_except_specs (TYPE_RAISES_EXCEPTIONS (typea),
TYPE_RAISES_EXCEPTIONS (typeb), ce_exact);
}
cxx_copy_lang_qualifiers (const_tree typea, const_tree typeb)
{
tree type = CONST_CAST_TREE (typea);
- if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
- {
- type = build_exception_variant (type, TYPE_RAISES_EXCEPTIONS (typeb));
- type = build_ref_qualified_type (type, type_memfn_rqual (typeb));
- }
+ if (FUNC_OR_METHOD_TYPE_P (type))
+ type = build_cp_fntype_variant (type, type_memfn_rqual (typeb),
+ TYPE_RAISES_EXCEPTIONS (typeb),
+ TYPE_HAS_LATE_RETURN_TYPE (typeb));
return type;
}
result = NULL_TREE;
switch (code)
{
- case DEFAULT_ARG:
+ case DEFERRED_PARSE:
case TEMPLATE_TEMPLATE_PARM:
case BOUND_TEMPLATE_TEMPLATE_PARM:
case UNBOUND_CLASS_TEMPLATE:
break;
case DECLTYPE_TYPE:
- WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp));
+ ++cp_unevaluated_operand;
+ /* We can't use WALK_SUBTREE here because of the goto. */
+ result = cp_walk_tree (&DECLTYPE_TYPE_EXPR (*tp), func, data, pset);
+ --cp_unevaluated_operand;
+ *walk_subtrees_p = 0;
+ break;
+
+ case ALIGNOF_EXPR:
+ case SIZEOF_EXPR:
+ case NOEXCEPT_EXPR:
+ ++cp_unevaluated_operand;
+ result = cp_walk_tree (&TREE_OPERAND (*tp, 0), func, data, pset);
+ --cp_unevaluated_operand;
*walk_subtrees_p = 0;
break;
/* User variables should be mentioned in BIND_EXPR_VARS
and their initializers and sizes walked when walking
the containing BIND_EXPR. Compiler temporaries are
- handled here. */
+ handled here. And also normal variables in templates,
+ since do_poplevel doesn't build a BIND_EXPR then. */
if (VAR_P (TREE_OPERAND (*tp, 0))
- && DECL_ARTIFICIAL (TREE_OPERAND (*tp, 0))
- && !TREE_STATIC (TREE_OPERAND (*tp, 0)))
+ && (processing_template_decl
+ || (DECL_ARTIFICIAL (TREE_OPERAND (*tp, 0))
+ && !TREE_STATIC (TREE_OPERAND (*tp, 0)))))
{
tree decl = TREE_OPERAND (*tp, 0);
WALK_SUBTREE (DECL_INITIAL (decl));
}
break;
+ case LAMBDA_EXPR:
+ /* Don't walk into the body of the lambda, but the capture initializers
+ are part of the enclosing context. */
+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (*tp); cap;
+ cap = TREE_CHAIN (cap))
+ WALK_SUBTREE (TREE_VALUE (cap));
+ break;
+
default:
return NULL_TREE;
}
tree codes. */
if (processing_template_decl)
return expr;
+
+ /* TARGET_EXPRs are only expanded once. */
+ if (TREE_CODE (expr) == TARGET_EXPR)
+ return expr;
+
return save_expr (expr);
}
return sfk_conversion;
if (deduction_guide_p (decl))
return sfk_deduction_guide;
+ if (DECL_OVERLOADED_OPERATOR_CODE_RAW (decl) >= OVL_OP_EQ_EXPR
+ && DECL_OVERLOADED_OPERATOR_CODE_RAW (decl) <= OVL_OP_SPACESHIP_EXPR)
+ return sfk_comparison;
+
+ return sfk_none;
+}
+/* As above, but only if DECL is a special member function as per 11.3.3
+ [special]: default/copy/move ctor, copy/move assignment, or destructor. */
+
+special_function_kind
+special_memfn_p (const_tree decl)
+{
+ switch (special_function_kind sfk = special_function_p (decl))
+ {
+ case sfk_constructor:
+ if (!default_ctor_p (decl))
+ break;
+ gcc_fallthrough();
+ case sfk_copy_constructor:
+ case sfk_copy_assignment:
+ case sfk_move_assignment:
+ case sfk_move_constructor:
+ case sfk_destructor:
+ return sfk;
+
+ default:
+ break;
+ }
return sfk_none;
}
return (same_type_p (type, char_type_node)
|| same_type_p (type, unsigned_char_type_node)
|| same_type_p (type, signed_char_type_node)
+ || same_type_p (type, char8_type_node)
|| same_type_p (type, char16_type_node)
|| same_type_p (type, char32_type_node)
|| same_type_p (type, wchar_type_node));
/* maybe_thunk_body clears TREE_PUBLIC on the maybe-in-charge 'tor variants,
check one of the "clones" for the real linkage. */
- if ((DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl)
- || DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl))
+ if (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)
&& DECL_CHAIN (decl)
- && DECL_CLONED_FUNCTION (DECL_CHAIN (decl)))
+ && DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl)))
return decl_linkage (DECL_CHAIN (decl));
if (TREE_CODE (decl) == NAMESPACE_DECL)
}
/* There are no expressions with REFERENCE_TYPE, but there can be call
arguments with such a type; just treat it as a pointer. */
- else if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE
+ else if (TYPE_REF_P (TREE_TYPE (exp))
|| SCALAR_TYPE_P (TREE_TYPE (exp))
|| !glvalue_p (exp))
{
{
tree type = TREE_TYPE (ce->value);
tree subinit;
- if (TREE_CODE (type) == REFERENCE_TYPE
+ if (TYPE_REF_P (type)
|| SCALAR_TYPE_P (type))
ce->value = stabilize_expr (ce->value, &subinit);
else if (!stabilize_init (ce->value, &subinit))
void
cp_free_lang_data (tree t)
{
- if (TREE_CODE (t) == METHOD_TYPE
- || TREE_CODE (t) == FUNCTION_TYPE)
+ if (FUNC_OR_METHOD_TYPE_P (t))
{
/* Default args are not interesting anymore. */
tree argtypes = TYPE_ARG_TYPES (t);
DECL_EXTERNAL (t) = 1;
TREE_STATIC (t) = 0;
}
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ discard_operator_bindings (t);
if (TREE_CODE (t) == NAMESPACE_DECL)
/* We do not need the leftover chaining of namespaces from the
binding level. */
}
}
+/* Like EXPR_LOCATION, but also handle some tcc_exceptional that have
+ locations. */
+
+location_t
+cp_expr_location (const_tree t_)
+{
+ tree t = CONST_CAST_TREE (t_);
+ if (t == NULL_TREE)
+ return UNKNOWN_LOCATION;
+ switch (TREE_CODE (t))
+ {
+ case LAMBDA_EXPR:
+ return LAMBDA_EXPR_LOCATION (t);
+ case STATIC_ASSERT:
+ return STATIC_ASSERT_SOURCE_LOCATION (t);
+ case TRAIT_EXPR:
+ return TRAIT_EXPR_LOCATION (t);
+ default:
+ return EXPR_LOCATION (t);
+ }
+}
+
/* Implement -Wzero_as_null_pointer_constant. Return true if the
conditions for the warning hold, false otherwise. */
bool
maybe_warn_zero_as_null_pointer_constant (tree expr, location_t loc)
{
if (c_inhibit_evaluation_warnings == 0
- && !NULLPTR_TYPE_P (TREE_TYPE (expr)))
+ && !null_node_p (expr) && !NULLPTR_TYPE_P (TREE_TYPE (expr)))
{
warning_at (loc, OPT_Wzero_as_null_pointer_constant,
"zero as null pointer constant");
return false;
}
\f
+/* Given an initializer INIT for a TYPE, return true if INIT is zero
+ so that it can be replaced by value initialization. This function
+ distinguishes betwen empty strings as initializers for arrays and
+ for pointers (which make it return false). */
+
+bool
+type_initializer_zero_p (tree type, tree init)
+{
+ if (type == error_mark_node || init == error_mark_node)
+ return false;
+
+ STRIP_NOPS (init);
+
+ if (POINTER_TYPE_P (type))
+ return TREE_CODE (init) != STRING_CST && initializer_zerop (init);
+
+ if (TREE_CODE (init) != CONSTRUCTOR)
+ return initializer_zerop (init);
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree elt_type = TREE_TYPE (type);
+ elt_type = TYPE_MAIN_VARIANT (elt_type);
+ if (elt_type == char_type_node)
+ return initializer_zerop (init);
+
+ tree elt_init;
+ unsigned HOST_WIDE_INT i;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, elt_init)
+ if (!type_initializer_zero_p (elt_type, elt_init))
+ return false;
+ return true;
+ }
+
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return initializer_zerop (init);
+
+ if (TYPE_NON_AGGREGATE_CLASS (type))
+ return false;
+
+ tree fld = TYPE_FIELDS (type);
+
+ tree fld_init;
+ unsigned HOST_WIDE_INT i;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), i, fld_init)
+ {
+ fld = next_initializable_field (fld);
+ if (!fld)
+ return true;
+
+ tree fldtype = TREE_TYPE (fld);
+ if (!type_initializer_zero_p (fldtype, fld_init))
+ return false;
+
+ fld = DECL_CHAIN (fld);
+ if (!fld)
+ break;
+ }
+
+ return true;
+}
+\f
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
/* Complain that some language-specific thing hanging off a tree
node has been accessed improperly. */
void
lang_check_failed (const char* file, int line, const char* function)
{
- internal_error ("lang_* check: failed in %s, at %s:%d",
+ internal_error ("%<lang_*%> check: failed in %s, at %s:%d",
function, trim_filename (file), line);
}
#endif /* ENABLE_TREE_CHECKING */
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that lvalue_kind () works, for various expressions,
+ and that location wrappers don't affect the results. */
+
+static void
+test_lvalue_kind ()
+{
+ location_t loc = BUILTINS_LOCATION;
+
+ /* Verify constants and parameters, without and with
+ location wrappers. */
+ tree int_cst = build_int_cst (integer_type_node, 42);
+ ASSERT_EQ (clk_none, lvalue_kind (int_cst));
+
+ tree wrapped_int_cst = maybe_wrap_with_location (int_cst, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_int_cst));
+ ASSERT_EQ (clk_none, lvalue_kind (wrapped_int_cst));
+
+ tree string_lit = build_string (4, "foo");
+ TREE_TYPE (string_lit) = char_array_type_node;
+ string_lit = fix_string_type (string_lit);
+ ASSERT_EQ (clk_ordinary, lvalue_kind (string_lit));
+
+ tree wrapped_string_lit = maybe_wrap_with_location (string_lit, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_string_lit));
+ ASSERT_EQ (clk_ordinary, lvalue_kind (wrapped_string_lit));
+
+ tree parm = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+ get_identifier ("some_parm"),
+ integer_type_node);
+ ASSERT_EQ (clk_ordinary, lvalue_kind (parm));
+
+ tree wrapped_parm = maybe_wrap_with_location (parm, loc);
+ ASSERT_TRUE (location_wrapper_p (wrapped_parm));
+ ASSERT_EQ (clk_ordinary, lvalue_kind (wrapped_parm));
+
+ /* Verify that lvalue_kind of std::move on a parm isn't
+ affected by location wrappers. */
+ tree rvalue_ref_of_parm = move (parm);
+ ASSERT_EQ (clk_rvalueref, lvalue_kind (rvalue_ref_of_parm));
+ tree rvalue_ref_of_wrapped_parm = move (wrapped_parm);
+ ASSERT_EQ (clk_rvalueref, lvalue_kind (rvalue_ref_of_wrapped_parm));
+
+ /* Verify lvalue_p. */
+ ASSERT_FALSE (lvalue_p (int_cst));
+ ASSERT_FALSE (lvalue_p (wrapped_int_cst));
+ ASSERT_TRUE (lvalue_p (parm));
+ ASSERT_TRUE (lvalue_p (wrapped_parm));
+ ASSERT_FALSE (lvalue_p (rvalue_ref_of_parm));
+ ASSERT_FALSE (lvalue_p (rvalue_ref_of_wrapped_parm));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+cp_tree_c_tests ()
+{
+ test_lvalue_kind ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
+
+
#include "gt-cp-tree.h"