/* Language-dependent node constructors for parse phase of GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
+ Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
static int list_hash_eq (const void *, const void *);
static hashval_t list_hash_pieces (tree, tree, tree);
static hashval_t list_hash (const void *);
-static cp_lvalue_kind lvalue_p_1 (tree, int);
+static cp_lvalue_kind lvalue_p_1 (const_tree, int);
static tree build_target_expr (tree, tree);
static tree count_trees_r (tree *, int *, void *);
static tree verify_stmt_tree_r (tree *, int *, void *);
nonzero, rvalues of class type are considered lvalues. */
static cp_lvalue_kind
-lvalue_p_1 (tree ref,
+lvalue_p_1 (const_tree ref,
int treat_class_rvalues_as_lvalues)
{
cp_lvalue_kind op1_lvalue_kind = clk_none;
cp_lvalue_kind op2_lvalue_kind = clk_none;
+ /* Expressions of reference type are sometimes wrapped in
+ INDIRECT_REFs. INDIRECT_REFs are just internal compiler
+ representation, not part of the language, so we have to look
+ through them. */
+ if (TREE_CODE (ref) == INDIRECT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0)))
+ == REFERENCE_TYPE)
+ return lvalue_p_1 (TREE_OPERAND (ref, 0),
+ treat_class_rvalues_as_lvalues);
+
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
- return clk_ordinary;
+ {
+ /* unnamed rvalue references are rvalues */
+ if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref))
+ && TREE_CODE (ref) != PARM_DECL
+ && TREE_CODE (ref) != VAR_DECL
+ && TREE_CODE (ref) != COMPONENT_REF)
+ return clk_none;
+
+ /* lvalue references and named rvalue references are lvalues. */
+ return clk_ordinary;
+ }
if (ref == current_class_ptr)
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 PREDECREMENT_EXPR:
- case SAVE_EXPR:
case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
case REALPART_EXPR:
break;
case COND_EXPR:
- op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
+ op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1)
+ ? TREE_OPERAND (ref, 1)
+ : TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues);
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
treat_class_rvalues_as_lvalues);
computes the C++ definition of lvalue. */
cp_lvalue_kind
-real_lvalue_p (tree ref)
+real_lvalue_p (const_tree ref)
{
return lvalue_p_1 (ref,
/*treat_class_rvalues_as_lvalues=*/0);
considered lvalues. */
int
-lvalue_p (tree ref)
+lvalue_p (const_tree ref)
{
return
(lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none);
constant-expression. */
bool
-builtin_valid_in_constant_expr_p (tree decl)
+builtin_valid_in_constant_expr_p (const_tree decl)
{
/* At present BUILT_IN_CONSTANT_P is the only builtin we're allowing
in constant-expressions. We may want to add other builtins later. */
return slot;
}
-/* INIT is a CALL_EXPR which needs info about its target.
- TYPE is the type that this initialization should appear to have.
+/* Set various status flags when building an AGGR_INIT_EXPR object T. */
+
+static void
+process_aggr_init_operands (tree t)
+{
+ bool side_effects;
+
+ side_effects = TREE_SIDE_EFFECTS (t);
+ if (!side_effects)
+ {
+ int i, n;
+ n = TREE_OPERAND_LENGTH (t);
+ for (i = 1; i < n; i++)
+ {
+ tree op = TREE_OPERAND (t, i);
+ if (op && TREE_SIDE_EFFECTS (op))
+ {
+ side_effects = 1;
+ break;
+ }
+ }
+ }
+ TREE_SIDE_EFFECTS (t) = side_effects;
+}
+
+/* Build an AGGR_INIT_EXPR of class tcc_vl_exp with the indicated RETURN_TYPE,
+ FN, and SLOT. NARGS is the number of call arguments which are specified
+ as a tree array ARGS. */
+
+static tree
+build_aggr_init_array (tree return_type, tree fn, tree slot, int nargs,
+ tree *args)
+{
+ tree t;
+ int i;
+
+ t = build_vl_exp (AGGR_INIT_EXPR, nargs + 3);
+ TREE_TYPE (t) = return_type;
+ AGGR_INIT_EXPR_FN (t) = fn;
+ AGGR_INIT_EXPR_SLOT (t) = slot;
+ for (i = 0; i < nargs; i++)
+ AGGR_INIT_EXPR_ARG (t, i) = args[i];
+ process_aggr_init_operands (t);
+ return t;
+}
+
+/* INIT is a CALL_EXPR or AGGR_INIT_EXPR which needs info about its
+ target. TYPE is the type that this initialization should appear to
+ have.
Build an encapsulation of the initialization to perform
and return it so that it can be processed by language-independent
abstract class. */
abstract_virtuals_error (NULL_TREE, type);
- if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
+ if (TREE_CODE (init) == CALL_EXPR)
+ fn = CALL_EXPR_FN (init);
+ else if (TREE_CODE (init) == AGGR_INIT_EXPR)
+ fn = AGGR_INIT_EXPR_FN (init);
+ else
return convert (type, init);
- fn = TREE_OPERAND (init, 0);
is_ctor = (TREE_CODE (fn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
&& DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));
type, don't mess with AGGR_INIT_EXPR. */
if (is_ctor || TREE_ADDRESSABLE (type))
{
- rval = build3 (AGGR_INIT_EXPR, void_type_node, fn,
- TREE_OPERAND (init, 1), slot);
+ if (TREE_CODE(init) == CALL_EXPR)
+ rval = build_aggr_init_array (void_type_node, fn, slot,
+ call_expr_nargs (init),
+ CALL_EXPR_ARGP (init));
+ else
+ rval = build_aggr_init_array (void_type_node, fn, slot,
+ aggr_init_expr_nargs (init),
+ AGGR_INIT_EXPR_ARGP (init));
TREE_SIDE_EFFECTS (rval) = 1;
AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
}
rval = init;
rval = build_target_expr (slot, rval);
+ TARGET_EXPR_IMPLICIT_P (rval) = 1;
return rval;
}
}
\f
+/* Hash an ARRAY_TYPE. K is really of type `tree'. */
+
+static hashval_t
+cplus_array_hash (const void* k)
+{
+ hashval_t hash;
+ const_tree const t = (const_tree) k;
+
+ hash = (htab_hash_pointer (TREE_TYPE (t))
+ ^ htab_hash_pointer (TYPE_DOMAIN (t)));
+
+ return hash;
+}
+
+typedef struct cplus_array_info {
+ tree type;
+ tree domain;
+} cplus_array_info;
+
+/* Compare two ARRAY_TYPEs. K1 is really of type `tree', K2 is really
+ of type `cplus_array_info*'. */
+
+static int
+cplus_array_compare (const void * k1, const void * k2)
+{
+ const_tree const t1 = (const_tree) k1;
+ const cplus_array_info *const t2 = (const cplus_array_info*) k2;
+
+ return (TREE_TYPE (t1) == t2->type && TYPE_DOMAIN (t1) == t2->domain);
+}
+
+/* Hash table containing all of the C++ array types, including
+ dependent array types and array types whose element type is
+ cv-qualified. */
+static GTY ((param_is (union tree_node))) htab_t cplus_array_htab;
+
+
static tree
build_cplus_array_type_1 (tree elt_type, tree index_type)
{
if (elt_type == error_mark_node || index_type == error_mark_node)
return error_mark_node;
- if (dependent_type_p (elt_type)
- || (index_type
- && value_dependent_expression_p (TYPE_MAX_VALUE (index_type))))
+ if (processing_template_decl
+ && (dependent_type_p (elt_type)
+ || (index_type && !TREE_CONSTANT (TYPE_MAX_VALUE (index_type)))))
{
- t = make_node (ARRAY_TYPE);
- TREE_TYPE (t) = elt_type;
- TYPE_DOMAIN (t) = index_type;
+ void **e;
+ cplus_array_info cai;
+ hashval_t hash;
+
+ if (cplus_array_htab == NULL)
+ cplus_array_htab = htab_create_ggc (61, &cplus_array_hash,
+ &cplus_array_compare, NULL);
+
+ hash = (htab_hash_pointer (elt_type)
+ ^ htab_hash_pointer (index_type));
+ cai.type = elt_type;
+ cai.domain = index_type;
+
+ e = htab_find_slot_with_hash (cplus_array_htab, &cai, hash, INSERT);
+ if (*e)
+ /* We have found the type: we're done. */
+ return (tree) *e;
+ else
+ {
+ /* Build a new array type. */
+ t = make_node (ARRAY_TYPE);
+ TREE_TYPE (t) = elt_type;
+ TYPE_DOMAIN (t) = index_type;
+
+ /* Store it in the hash table. */
+ *e = t;
+
+ /* Set the canonical type for this new node. */
+ if (TYPE_STRUCTURAL_EQUALITY_P (elt_type)
+ || (index_type && TYPE_STRUCTURAL_EQUALITY_P (index_type)))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (elt_type) != elt_type
+ || (index_type
+ && TYPE_CANONICAL (index_type) != index_type))
+ TYPE_CANONICAL (t)
+ = build_cplus_array_type
+ (TYPE_CANONICAL (elt_type),
+ index_type ? TYPE_CANONICAL (index_type) : index_type);
+ else
+ TYPE_CANONICAL (t) = t;
+ }
}
else
t = build_array_type (elt_type, index_type);
return t;
}
+
+/* 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
+ a new one. */
+tree
+cp_build_reference_type (tree to_type, bool rval)
+{
+ tree lvalue_ref, t;
+ lvalue_ref = build_reference_type (to_type);
+ if (!rval)
+ return lvalue_ref;
+
+ /* This code to create rvalue reference types is based on and tied
+ to the code creating lvalue reference types in the middle-end
+ functions build_reference_type_for_mode and build_reference_type.
+
+ It works by putting the rvalue reference type nodes after the
+ lvalue reference nodes in the TYPE_NEXT_REF_TO linked list, so
+ they will effectively be ignored by the middle end. */
+
+ for (t = lvalue_ref; (t = TYPE_NEXT_REF_TO (t)); )
+ if (TYPE_REF_IS_RVALUE (t))
+ return t;
+
+ t = copy_node (lvalue_ref);
+
+ TYPE_REF_IS_RVALUE (t) = true;
+ TYPE_NEXT_REF_TO (t) = TYPE_NEXT_REF_TO (lvalue_ref);
+ TYPE_NEXT_REF_TO (lvalue_ref) = t;
+ TYPE_MAIN_VARIANT (t) = t;
+
+ if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (to_type) != to_type)
+ TYPE_CANONICAL (t)
+ = cp_build_reference_type (TYPE_CANONICAL (to_type), rval);
+ else
+ TYPE_CANONICAL (t) = t;
+
+ layout_type (t);
+
+ return t;
+
+}
+
+/* Used by the C++ front end to build qualified array types. However,
+ the C version of this function does not properly maintain canonical
+ types (which are not used in C). */
+tree
+c_build_qualified_type (tree type, int type_quals)
+{
+ return cp_build_qualified_type (type, type_quals);
+}
+
\f
/* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles
arrays correctly. In particular, if TYPE is an array of T's, and
if (!t)
{
- /* Make a new array type, just like the old one, but with the
- appropriately qualified element type. */
+ tree index_type = TYPE_DOMAIN (type);
+ void **e;
+ cplus_array_info cai;
+ hashval_t hash;
+
+ if (cplus_array_htab == NULL)
+ cplus_array_htab = htab_create_ggc (61, &cplus_array_hash,
+ &cplus_array_compare,
+ NULL);
+
+ hash = (htab_hash_pointer (element_type)
+ ^ htab_hash_pointer (index_type));
+ cai.type = element_type;
+ cai.domain = index_type;
+
+ e = htab_find_slot_with_hash (cplus_array_htab, &cai, hash, INSERT);
+ if (*e)
+ /* We have found the type: we're done. */
+ return (tree) *e;
+
+ /* Build a new array type and add it into the table. */
t = build_variant_type_copy (type);
TREE_TYPE (t) = element_type;
+ *e = t;
+
+ /* Set the canonical type for this new node. */
+ if (TYPE_STRUCTURAL_EQUALITY_P (element_type)
+ || (index_type && TYPE_STRUCTURAL_EQUALITY_P (index_type)))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (element_type) != element_type
+ || (index_type
+ && TYPE_CANONICAL (index_type) != index_type)
+ || TYPE_CANONICAL (type) != type)
+ TYPE_CANONICAL (t)
+ = build_cplus_array_type
+ (TYPE_CANONICAL (element_type),
+ index_type? TYPE_CANONICAL (index_type) : index_type);
+ else
+ TYPE_CANONICAL (t) = t;
}
/* Even if we already had this variant, we update
t = cp_build_qualified_type_real (t, type_quals, complain);
return build_ptrmemfunc_type (t);
}
+ else if (TREE_CODE (type) == TYPE_PACK_EXPANSION)
+ {
+ tree t = PACK_EXPANSION_PATTERN (type);
+
+ t = cp_build_qualified_type_real (t, type_quals, complain);
+ return make_pack_expansion (t);
+ }
/* A reference or method type shall not be cv qualified.
[dcl.ref], [dct.fct] */
tree
canonical_type_variant (tree t)
{
+ if (t == error_mark_node)
+ return error_mark_node;
+
return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), cp_type_quals (t));
}
\f
static int
list_hash_eq (const void* entry, const void* data)
{
- tree t = (tree) entry;
- struct list_proxy *proxy = (struct list_proxy *) data;
+ const_tree const t = (const_tree) entry;
+ const struct list_proxy *const proxy = (const struct list_proxy *) data;
return (TREE_VALUE (t) == proxy->value
&& TREE_PURPOSE (t) == proxy->purpose
static hashval_t
list_hash (const void* p)
{
- tree t = (tree) p;
+ const_tree const t = (const_tree) p;
return list_hash_pieces (TREE_PURPOSE (t),
TREE_VALUE (t),
TREE_CHAIN (t));
the type of the result expression, if known, or NULL_TREE if the
resulting expression is type-dependent. If TEMPLATE_P is true,
NAME is known to be a template because the user explicitly used the
- "template" keyword after the "::".
+ "template" keyword after the "::".
All SCOPE_REFs should be built by use of this function. */
return t;
}
+/* 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
+ overloaded functions. Returns 2 if the function is actually
+ overloaded, i.e., if it is impossible to know the type of the
+ function without performing overload resolution. */
+
int
is_overloaded_fn (tree x)
{
/* A baselink is also considered an overloaded function. */
- if (TREE_CODE (x) == OFFSET_REF)
+ if (TREE_CODE (x) == OFFSET_REF
+ || TREE_CODE (x) == COMPONENT_REF)
x = TREE_OPERAND (x, 1);
if (BASELINK_P (x))
x = BASELINK_FUNCTIONS (x);
- return (TREE_CODE (x) == FUNCTION_DECL
- || TREE_CODE (x) == TEMPLATE_ID_EXPR
- || DECL_FUNCTION_TEMPLATE_P (x)
- || TREE_CODE (x) == OVERLOAD);
+ if (TREE_CODE (x) == TEMPLATE_ID_EXPR
+ || DECL_FUNCTION_TEMPLATE_P (OVL_CURRENT (x))
+ || (TREE_CODE (x) == OVERLOAD && OVL_CHAIN (x)))
+ return 2;
+ return (TREE_CODE (x) == FUNCTION_DECL
+ || TREE_CODE (x) == OVERLOAD);
}
-int
+/* Returns true iff X is an expression for an overloaded function
+ whose type cannot be known without performing overload
+ resolution. */
+
+bool
really_overloaded_fn (tree x)
{
- if (TREE_CODE (x) == OFFSET_REF)
- x = TREE_OPERAND (x, 1);
- /* A baselink is also considered an overloaded function. */
- if (BASELINK_P (x))
- x = BASELINK_FUNCTIONS (x);
-
- return ((TREE_CODE (x) == OVERLOAD && OVL_CHAIN (x))
- || DECL_FUNCTION_TEMPLATE_P (OVL_CURRENT (x))
- || TREE_CODE (x) == TEMPLATE_ID_EXPR);
+ return is_overloaded_fn (x) == 2;
}
tree
{
gcc_assert (is_overloaded_fn (from));
/* A baselink is also considered an overloaded function. */
+ if (TREE_CODE (from) == COMPONENT_REF)
+ from = TREE_OPERAND (from, 1);
if (BASELINK_P (from))
from = BASELINK_FUNCTIONS (from);
return OVL_CURRENT (from);
const char *
cxx_printable_name (tree decl, int v)
{
- static tree decl_ring[PRINT_RING_SIZE];
+ static unsigned int uid_ring[PRINT_RING_SIZE];
static char *print_ring[PRINT_RING_SIZE];
static int ring_counter;
int i;
/* See if this print name is lying around. */
for (i = 0; i < PRINT_RING_SIZE; i++)
- if (decl_ring[i] == decl)
+ if (uid_ring[i] == DECL_UID (decl))
/* yes, so return it. */
return print_ring[i];
if (current_function_decl != NULL_TREE)
{
- if (decl_ring[ring_counter] == current_function_decl)
+ if (uid_ring[ring_counter] == DECL_UID (current_function_decl))
ring_counter += 1;
if (ring_counter == PRINT_RING_SIZE)
ring_counter = 0;
- gcc_assert (decl_ring[ring_counter] != current_function_decl);
+ gcc_assert (uid_ring[ring_counter] != DECL_UID (current_function_decl));
}
if (print_ring[ring_counter])
free (print_ring[ring_counter]);
print_ring[ring_counter] = xstrdup (lang_decl_name (decl, v));
- decl_ring[ring_counter] = decl;
+ uid_ring[ring_counter] = DECL_UID (decl);
return print_ring[ring_counter];
}
\f
TYPE_NAME (t2) = decl;
TYPE_STUB_DECL (t2) = decl;
TYPE_SIZE (t2) = 0;
+ SET_TYPE_STRUCTURAL_EQUALITY (t2);
return t2;
}
count_trees (tree t)
{
int n_trees = 0;
- walk_tree_without_duplicates (&t, count_trees_r, &n_trees);
+ cp_walk_tree_without_duplicates (&t, count_trees_r, &n_trees);
return n_trees;
}
{
htab_t statements;
statements = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
- walk_tree (&t, verify_stmt_tree_r, &statements, NULL);
+ cp_walk_tree (&t, verify_stmt_tree_r, &statements, NULL);
htab_delete (statements);
}
target_remap = splay_tree_new (splay_tree_compare_pointers,
/*splay_tree_delete_key_fn=*/NULL,
/*splay_tree_delete_value_fn=*/NULL);
- walk_tree (&t, bot_manip, target_remap, NULL);
- walk_tree (&t, bot_replace, target_remap, NULL);
+ cp_walk_tree (&t, bot_manip, target_remap, NULL);
+ cp_walk_tree (&t, bot_replace, target_remap, NULL);
if (!--target_remap_count)
{
int i;
va_list p;
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
va_start (p, code);
t = make_node (code);
return t;
}
+
/* Similar to `build', but for template definitions. */
tree
int i;
va_list p;
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
va_start (p, tt);
t = make_node (code);
int i;
va_list p;
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
va_start (p, non_dep);
t = make_node (code);
return t;
}
+/* Similar to `build_call_list', but for template definitions of non-dependent
+ expressions. NON_DEP is the non-dependent expression that has been
+ built. */
+
+tree
+build_min_non_dep_call_list (tree non_dep, tree fn, tree arglist)
+{
+ tree t = build_nt_call_list (fn, arglist);
+ TREE_TYPE (t) = TREE_TYPE (non_dep);
+ TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (non_dep);
+ return t;
+}
+
tree
get_type_decl (tree t)
{
}
}
+/* Returns true if decl is within an anonymous namespace, however deeply
+ nested, or false otherwise. */
+
+bool
+decl_anon_ns_mem_p (const_tree decl)
+{
+ while (1)
+ {
+ if (decl == NULL_TREE || decl == error_mark_node)
+ return false;
+ if (TREE_CODE (decl) == NAMESPACE_DECL
+ && DECL_NAME (decl) == NULL_TREE)
+ return true;
+ /* Classes and namespaces inside anonymous namespaces have
+ TREE_PUBLIC == 0, so we can shortcut the search. */
+ else if (TYPE_P (decl))
+ return (TREE_PUBLIC (TYPE_NAME (decl)) == 0);
+ else if (TREE_CODE (decl) == NAMESPACE_DECL)
+ return (TREE_PUBLIC (decl) == 0);
+ else
+ decl = DECL_CONTEXT (decl);
+ }
+}
+
/* Return truthvalue of whether T1 is the same tree structure as T2.
Return 1 if they are the same. Return 0 if they are different. */
&& !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
TREE_STRING_LENGTH (t1));
+ case COMPLEX_CST:
+ return cp_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
+ && cp_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+
case CONSTRUCTOR:
/* We need to do this when determining whether or not two
non-type pointer to member function template arguments
return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
case CALL_EXPR:
- if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
- return false;
- return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+ {
+ tree arg1, arg2;
+ call_expr_arg_iterator iter1, iter2;
+ if (!cp_tree_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+ return false;
+ for (arg1 = first_call_expr_arg (t1, &iter1),
+ arg2 = first_call_expr_arg (t2, &iter2);
+ arg1 && arg2;
+ arg1 = next_call_expr_arg (&iter1),
+ arg2 = next_call_expr_arg (&iter2))
+ if (!cp_tree_equal (arg1, arg2))
+ return false;
+ return (arg1 || arg2);
+ }
case TARGET_EXPR:
{
return cp_tree_equal (o1, o2);
}
+ case MODOP_EXPR:
+ {
+ tree t1_op1, t2_op1;
+
+ if (!cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)))
+ return false;
+
+ t1_op1 = TREE_OPERAND (t1, 1);
+ t2_op1 = TREE_OPERAND (t2, 1);
+ if (TREE_CODE (t1_op1) != TREE_CODE (t2_op1))
+ return false;
+
+ return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t2, 2));
+ }
+
case PTRMEM_CST:
/* Two pointer-to-members are the same if they point to the same
field or function in the same class. */
return false;
return cp_tree_equal (OVL_CHAIN (t1), OVL_CHAIN (t2));
+ case TRAIT_EXPR:
+ if (TRAIT_EXPR_KIND (t1) != TRAIT_EXPR_KIND (t2))
+ return false;
+ return same_type_p (TRAIT_EXPR_TYPE1 (t1), TRAIT_EXPR_TYPE1 (t2))
+ && same_type_p (TRAIT_EXPR_TYPE2 (t1), TRAIT_EXPR_TYPE2 (t2));
+
default:
break;
}
case tcc_binary:
case tcc_comparison:
case tcc_expression:
+ case tcc_vl_exp:
case tcc_reference:
case tcc_statement:
{
- int i;
+ int i, n;
+
+ n = TREE_OPERAND_LENGTH (t1);
+ if (TREE_CODE_CLASS (code1) == tcc_vl_exp
+ && n != TREE_OPERAND_LENGTH (t2))
+ return false;
- for (i = 0; i < TREE_CODE_LENGTH (code1); ++i)
+ for (i = 0; i < n; ++i)
if (!cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
return false;
/* Does FUNCTION use a variable-length argument list? */
int
-varargs_function_p (tree function)
+varargs_function_p (const_tree function)
{
- tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
+ const_tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
for (; parm; parm = TREE_CHAIN (parm))
if (TREE_VALUE (parm) == void_type_node)
return 0;
/* Returns 1 if decl is a member of a class. */
int
-member_p (tree decl)
+member_p (const_tree decl)
{
- const tree ctx = DECL_CONTEXT (decl);
+ const_tree const ctx = DECL_CONTEXT (decl);
return (ctx && TYPE_P (ctx));
}
/* Returns 1 if OB is a placeholder object, or a pointer to one. */
int
-is_dummy_object (tree ob)
+is_dummy_object (const_tree ob)
{
if (TREE_CODE (ob) == INDIRECT_REF)
ob = TREE_OPERAND (ob, 0);
/* Returns 1 iff type T is a POD type, as defined in [basic.types]. */
int
-pod_type_p (tree t)
+pod_type_p (const_tree t)
{
- t = strip_array_types (t);
+ /* This CONST_CAST is okay because strip_array_types returns it's
+ argument unmodified and we assign it to a const_tree. */
+ t = strip_array_types (CONST_CAST_TREE(t));
if (t == error_mark_node)
return 1;
return 1;
}
+/* Nonzero iff type T is a class template implicit specialization. */
+
+bool
+class_tmpl_impl_spec_p (const_tree t)
+{
+ return CLASS_TYPE_P (t) && CLASSTYPE_TEMPLATE_INSTANTIATION (t);
+}
+
/* Returns 1 iff zero initialization of type T means actually storing
zeros in it. */
int
-zero_init_p (tree t)
+zero_init_p (const_tree t)
{
- t = strip_array_types (t);
+ /* This CONST_CAST is okay because strip_array_types returns it's
+ argument unmodified and we assign it to a const_tree. */
+ t = strip_array_types (CONST_CAST_TREE(t));
if (t == error_mark_node)
return 1;
}
/* Build a variant of TYPE that has the indicated ATTRIBUTES. May
- return an existing type of an appropriate type already exists. */
+ return an existing type if an appropriate type already exists. */
tree
cp_build_type_attribute_variant (tree type, tree attributes)
!= TYPE_RAISES_EXCEPTIONS (type)))
new_type = build_exception_variant (new_type,
TYPE_RAISES_EXCEPTIONS (type));
+
+ /* Making a new main variant of a class type is broken. */
+ gcc_assert (!CLASS_TYPE_P (type) || new_type == type);
+
return new_type;
}
+/* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
+ Called only after doing all language independent checks. Only
+ to check TYPE_RAISES_EXCEPTIONS for FUNCTION_TYPE, the rest is already
+ compared in type_hash_eq. */
+
+bool
+cxx_type_hash_eq (const_tree typea, const_tree typeb)
+{
+ gcc_assert (TREE_CODE (typea) == FUNCTION_TYPE);
+
+ return comp_except_specs (TYPE_RAISES_EXCEPTIONS (typea),
+ TYPE_RAISES_EXCEPTIONS (typeb), 1);
+}
+
/* Apply FUNC to all language-specific sub-trees of TP in a pre-order
traversal. Called from walk_tree. */
void *data, struct pointer_set_t *pset)
{
enum tree_code code = TREE_CODE (*tp);
- location_t save_locus;
tree result;
#define WALK_SUBTREE(NODE) \
do \
{ \
- result = walk_tree (&(NODE), func, data, pset); \
+ result = cp_walk_tree (&(NODE), func, data, pset); \
if (result) goto out; \
} \
while (0)
- /* Set input_location here so we get the right instantiation context
- if we call instantiate_decl from inlinable_function_p. */
- save_locus = input_location;
- if (EXPR_HAS_LOCATION (*tp))
- input_location = EXPR_LOCATION (*tp);
-
/* Not one of the easy cases. We must explicitly go through the
children. */
result = NULL_TREE;
case TEMPLATE_TYPE_PARM:
case TYPENAME_TYPE:
case TYPEOF_TYPE:
- case BASELINK:
/* None of these have subtrees other than those already walked
above. */
*walk_subtrees_p = 0;
break;
- case TINST_LEVEL:
- WALK_SUBTREE (TINST_DECL (*tp));
+ case BASELINK:
+ WALK_SUBTREE (BASELINK_FUNCTIONS (*tp));
*walk_subtrees_p = 0;
break;
*walk_subtrees_p = 0;
break;
+ case USING_DECL:
+ WALK_SUBTREE (DECL_NAME (*tp));
+ WALK_SUBTREE (USING_DECL_SCOPE (*tp));
+ WALK_SUBTREE (USING_DECL_DECLS (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (*tp))
WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
break;
- default:
- input_location = save_locus;
- return NULL_TREE;
- }
-
- /* We didn't find what we were looking for. */
- out:
- input_location = save_locus;
- return result;
-
-#undef WALK_SUBTREE
-}
-
-/* Decide whether there are language-specific reasons to not inline a
- function as a tree. */
-
-int
-cp_cannot_inline_tree_fn (tree* fnp)
-{
- tree fn = *fnp;
-
- /* We can inline a template instantiation only if it's fully
- instantiated. */
- if (DECL_TEMPLATE_INFO (fn)
- && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
- {
- /* Don't instantiate functions that are not going to be
- inlined. */
- if (!DECL_INLINE (DECL_TEMPLATE_RESULT
- (template_for_substitution (fn))))
- return 1;
+ case TYPE_ARGUMENT_PACK:
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree args = ARGUMENT_PACK_ARGS (*tp);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; i++)
+ WALK_SUBTREE (TREE_VEC_ELT (args, i));
+ }
+ break;
- fn = *fnp = instantiate_decl (fn, /*defer_ok=*/0, /*undefined_ok=*/0);
+ case TYPE_PACK_EXPANSION:
+ WALK_SUBTREE (TREE_TYPE (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
+ case EXPR_PACK_EXPANSION:
+ WALK_SUBTREE (TREE_OPERAND (*tp, 0));
+ *walk_subtrees_p = 0;
+ break;
- if (TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
- return 1;
- }
+ case CAST_EXPR:
+ if (TREE_TYPE (*tp))
+ WALK_SUBTREE (TREE_TYPE (*tp));
- if (flag_really_no_inline
- && lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) == NULL)
- return 1;
+ {
+ int i;
+ for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (*tp)); ++i)
+ WALK_SUBTREE (TREE_OPERAND (*tp, i));
+ }
+ *walk_subtrees_p = 0;
+ break;
- /* Don't auto-inline anything that might not be bound within
- this unit of translation.
- Exclude comdat functions from this rule. While they can be bound
- to the other unit, they all must be the same. This is especially
- important so templates can inline. */
- if (!DECL_DECLARED_INLINE_P (fn) && !(*targetm.binds_local_p) (fn)
- && !DECL_COMDAT (fn))
- {
- DECL_UNINLINABLE (fn) = 1;
- return 1;
- }
+ case TRAIT_EXPR:
+ WALK_SUBTREE (TRAIT_EXPR_TYPE1 (*tp));
+ WALK_SUBTREE (TRAIT_EXPR_TYPE2 (*tp));
+ *walk_subtrees_p = 0;
+ break;
- if (varargs_function_p (fn))
- {
- DECL_UNINLINABLE (fn) = 1;
- return 1;
- }
+ case DECLTYPE_TYPE:
+ WALK_SUBTREE (DECLTYPE_TYPE_EXPR (*tp));
+ *walk_subtrees_p = 0;
+ break;
+
- if (! function_attribute_inlinable_p (fn))
- {
- DECL_UNINLINABLE (fn) = 1;
- return 1;
+ default:
+ return NULL_TREE;
}
- return 0;
-}
-
-/* Add any pending functions other than the current function (already
- handled by the caller), that thus cannot be inlined, to FNS_P, then
- return the latest function added to the array, PREV_FN. */
-
-tree
-cp_add_pending_fn_decls (void* fns_p, tree prev_fn)
-{
- varray_type *fnsp = (varray_type *)fns_p;
- struct saved_scope *s;
-
- for (s = scope_chain; s; s = s->prev)
- if (s->function_decl && s->function_decl != prev_fn)
- {
- VARRAY_PUSH_TREE (*fnsp, s->function_decl);
- prev_fn = s->function_decl;
- }
-
- return prev_fn;
-}
-
-/* Determine whether VAR is a declaration of an automatic variable in
- function FN. */
+ /* We didn't find what we were looking for. */
+ out:
+ return result;
-int
-cp_auto_var_in_fn_p (tree var, tree fn)
-{
- return (DECL_P (var) && DECL_CONTEXT (var) == fn
- && nonstatic_local_decl_p (var));
+#undef WALK_SUBTREE
}
/* Like save_expr, but for C++. */
predicate to test whether or not DECL is a special function. */
special_function_kind
-special_function_p (tree decl)
+special_function_p (const_tree decl)
{
/* Rather than doing all this stuff with magic names, we should
probably have a field of type `special_function_kind' in
if (!DECL_NAME (decl))
return lk_none;
+ /* Fields have no linkage. */
+ if (TREE_CODE (decl) == FIELD_DECL)
+ return lk_none;
+
/* Things that are TREE_PUBLIC have external linkage. */
if (TREE_PUBLIC (decl))
return lk_external;
-
- /* Linkage of a CONST_DECL depends on the linkage of the enumeration
+
+ if (TREE_CODE (decl) == NAMESPACE_DECL)
+ return lk_external;
+
+ /* Linkage of a CONST_DECL depends on the linkage of the enumeration
type. */
if (TREE_CODE (decl) == CONST_DECL)
return decl_linkage (TYPE_NAME (TREE_TYPE (decl)));
template instantiations have internal linkage (in the object
file), but the symbols should still be treated as having external
linkage from the point of view of the language. */
- if (TREE_CODE (decl) != TYPE_DECL && DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
+ if (TREE_CODE (decl) != TYPE_DECL && DECL_LANG_SPECIFIC (decl)
+ && DECL_COMDAT (decl))
return lk_external;
/* Things in local scope do not have linkage, if they don't have
if (decl_function_context (decl))
return lk_none;
+ /* Members of the anonymous namespace also have TREE_PUBLIC unset, but
+ are considered to have external linkage for language purposes. DECLs
+ really meant to have internal linkage have DECL_THIS_STATIC set. */
+ if (TREE_CODE (decl) == TYPE_DECL)
+ return lk_external;
+ if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ if (!DECL_THIS_STATIC (decl))
+ return lk_external;
+
+ /* Static data members and static member functions from classes
+ in anonymous namespace also don't have TREE_PUBLIC set. */
+ if (DECL_CLASS_CONTEXT (decl))
+ return lk_external;
+ }
+
/* Everything else has internal linkage. */
return lk_internal;
}
\f
-/* EXP is an expression that we want to pre-evaluate. Returns via INITP an
- expression to perform the pre-evaluation, and returns directly an
- expression to use the precalculated result. */
+/* EXP is an expression that we want to pre-evaluate. Returns (in
+ *INITP) an expression that will perform the pre-evaluation. The
+ value returned by this function is a side-effect free expression
+ equivalent to the pre-evaluated expression. Callers must ensure
+ that *INITP is evaluated before EXP. */
tree
stabilize_expr (tree exp, tree* initp)
tree init_expr;
if (!TREE_SIDE_EFFECTS (exp))
- {
- init_expr = NULL_TREE;
- }
+ init_expr = NULL_TREE;
else if (!real_lvalue_p (exp)
|| !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp)))
{
exp = TARGET_EXPR_SLOT (init_expr);
exp = build_indirect_ref (exp, 0);
}
-
*initp = init_expr;
+
+ gcc_assert (!TREE_SIDE_EFFECTS (exp));
return exp;
}
return build2 (COMPOUND_EXPR, void_type_node, orig, new);
}
-/* Like stabilize_expr, but for a call whose args we want to
- pre-evaluate. */
+/* Like stabilize_expr, but for a call whose arguments we want to
+ pre-evaluate. CALL is modified in place to use the pre-evaluated
+ arguments, while, upon return, *INITP contains an expression to
+ compute the arguments. */
void
stabilize_call (tree call, tree *initp)
{
tree inits = NULL_TREE;
- tree t;
+ int i;
+ int nargs = call_expr_nargs (call);
+
+ if (call == error_mark_node || processing_template_decl)
+ {
+ *initp = NULL_TREE;
+ return;
+ }
+
+ gcc_assert (TREE_CODE (call) == CALL_EXPR);
+
+ for (i = 0; i < nargs; i++)
+ {
+ tree init;
+ CALL_EXPR_ARG (call, i) =
+ stabilize_expr (CALL_EXPR_ARG (call, i), &init);
+ inits = add_stmt_to_compound (inits, init);
+ }
+
+ *initp = inits;
+}
+
+/* Like stabilize_expr, but for an AGGR_INIT_EXPR whose arguments we want
+ to pre-evaluate. CALL is modified in place to use the pre-evaluated
+ arguments, while, upon return, *INITP contains an expression to
+ compute the arguments. */
+
+void
+stabilize_aggr_init (tree call, tree *initp)
+{
+ tree inits = NULL_TREE;
+ int i;
+ int nargs = aggr_init_expr_nargs (call);
if (call == error_mark_node)
return;
- gcc_assert (TREE_CODE (call) == CALL_EXPR
- || TREE_CODE (call) == AGGR_INIT_EXPR);
+ gcc_assert (TREE_CODE (call) == AGGR_INIT_EXPR);
- for (t = TREE_OPERAND (call, 1); t; t = TREE_CHAIN (t))
- if (TREE_SIDE_EFFECTS (TREE_VALUE (t)))
- {
- tree init;
- TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init);
- inits = add_stmt_to_compound (inits, init);
- }
+ for (i = 0; i < nargs; i++)
+ {
+ tree init;
+ AGGR_INIT_EXPR_ARG (call, i) =
+ stabilize_expr (AGGR_INIT_EXPR_ARG (call, i), &init);
+ inits = add_stmt_to_compound (inits, init);
+ }
*initp = inits;
}
-/* Like stabilize_expr, but for an initialization. If we are initializing
- an object of class type, we don't want to introduce an extra temporary,
- so we look past the TARGET_EXPR and stabilize the arguments of the call
- instead. */
+/* Like stabilize_expr, but for an initialization.
+
+ If the initialization is for an object of class type, this function
+ takes care not to introduce additional temporaries.
+
+ Returns TRUE iff the expression was successfully pre-evaluated,
+ i.e., if INIT is now side-effect free, except for, possible, a
+ single call to a constructor. */
bool
stabilize_init (tree init, tree *initp)
{
tree t = init;
- if (t == error_mark_node)
+ *initp = NULL_TREE;
+
+ if (t == error_mark_node || processing_template_decl)
return true;
if (TREE_CODE (t) == INIT_EXPR
&& TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR)
- TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp);
- else
{
- if (TREE_CODE (t) == INIT_EXPR)
- t = TREE_OPERAND (t, 1);
- if (TREE_CODE (t) == TARGET_EXPR)
- t = TARGET_EXPR_INITIAL (t);
- if (TREE_CODE (t) == COMPOUND_EXPR)
- t = expr_last (t);
- if (TREE_CODE (t) == CONSTRUCTOR
- && EMPTY_CONSTRUCTOR_P (t))
- {
- /* Default-initialization. */
- *initp = NULL_TREE;
- return true;
- }
+ TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp);
+ return true;
+ }
- /* If the initializer is a COND_EXPR, we can't preevaluate
- anything. */
- if (TREE_CODE (t) == COND_EXPR)
- return false;
+ if (TREE_CODE (t) == INIT_EXPR)
+ t = TREE_OPERAND (t, 1);
+ if (TREE_CODE (t) == TARGET_EXPR)
+ t = TARGET_EXPR_INITIAL (t);
+ if (TREE_CODE (t) == COMPOUND_EXPR)
+ t = expr_last (t);
+ if (TREE_CODE (t) == CONSTRUCTOR
+ && EMPTY_CONSTRUCTOR_P (t))
+ /* Default-initialization. */
+ return true;
+
+ /* If the initializer is a COND_EXPR, we can't preevaluate
+ anything. */
+ if (TREE_CODE (t) == COND_EXPR)
+ return false;
+
+ if (TREE_CODE (t) == CALL_EXPR)
+ {
+ stabilize_call (t, initp);
+ return true;
+ }
- /* The TARGET_EXPR might be initializing via bitwise copy from
- another variable; leave that alone. */
- if (TREE_SIDE_EFFECTS (t))
- stabilize_call (t, initp);
+ if (TREE_CODE (t) == AGGR_INIT_EXPR)
+ {
+ stabilize_aggr_init (t, initp);
+ return true;
}
- return true;
+ /* The initialization is being performed via a bitwise copy -- and
+ the item copied may have side effects. */
+ return TREE_SIDE_EFFECTS (init);
}
/* Like "fold", but should be used whenever we might be processing the
return fold (expr);
}
+/* Returns true if a cast to TYPE may appear in an integral constant
+ expression. */
+
+bool
+cast_valid_in_integral_constant_expression_p (tree type)
+{
+ return (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+ || dependent_type_p (type)
+ || type == error_mark_node);
+}
+
\f
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
/* Complain that some language-specific thing hanging off a tree